class DATABASE

(source code)

description

Subscription database

note
	description: "Subscription database"

	author: "Finnian Reilly"
	copyright: "Copyright (c) 2001-2022 Finnian Reilly"
	contact: "finnian at eiffel hyphen loop dot com"

	license: "MIT license (See: en.wikipedia.org/wiki/MIT_License)"
	date: "2024-04-03 13:34:54 GMT (Wednesday 3rd April 2024)"
	revision: "22"

class
	DATABASE

inherit
	EL_REFLECTIVELY_SETTABLE
		rename
			field_included as is_table_field,
			foreign_naming as eiffel_naming
		redefine
			initialize_fields
		end

	EL_SOLITARY
		rename
			make as make_solitary
		end

	EL_MODULE_DIRECTORY

	EL_MODULE_LIO

	EL_MODULE_USER_INPUT

	EL_MODULE_FILE_SYSTEM

	SHARED_HOST; SHARED_EMAIL_QUEUE

create
	make_open

feature {NONE} -- Initialization

	initialize_fields
		do
			create address_table.make (config)
			create customer_table.make (config)

			create subscription_table.make (config)
			create invalid_payment_table.make (config)
			create feature_request_table.make (config)
			create payment_table.make (config)
			create prompts_suppressed
		end

	make_open (a_config: DATABASE_CONFIGURATION)
		require
			authenticated: a_config.is_logged_in
		local
			subscription: SUBSCRIPTION_CONFIGURATION
		do
			make_solitary
			config := a_config
			create subscription.make -- needed to make default instance of PAYPAL_PAYMENT
			make_default
		end

feature -- Access

	config: DATABASE_CONFIGURATION

	crc_32_digest_table: HASH_TABLE [NATURAL, ZSTRING]
		do
			create Result.make (table_list.count)
			across table_list as list loop
				Result [list.item.name] := list.item.crc_32_digest
			end
		end

	table_list: ARRAYED_LIST [DATA_TABLE [REFLECTIVELY_STORABLE]]
		do
			create Result.make (field_table.count)
			across field_table as field loop
				if attached {like table_list.item} field.item.value (Current) as table then
					Result.extend (table)
				end
			end
		end

feature -- Status query

	prompts_suppressed: EL_BOOLEAN_OPTION

feature -- Tables

	address_table: ADDRESS_TABLE

	customer_table: CUSTOMER_TABLE

	feature_request_table: FEATURE_REQUEST_TABLE

	invalid_payment_table: INVALID_PAYMENT_TABLE

	payment_table: PAYMENT_TABLE

	subscription_table: SUBSCRIPTION_TABLE

feature -- Basic operations

	backup
		local
			tar_path: FILE_PATH
		do
			if attached Tar_directory_command as cmd then
				cmd.set_working_directory (Directory.app_data)
				tar_path := config.backup_version_01_path.next_version_path

				File_system.make_directory (tar_path.parent)

				export_as_pyxis

				cmd.set_archive_path (tar_path)
				cmd.set_target_dir ("pyxis")
				cmd.execute
			end
			lio.put_path_field ("Created", tar_path)
			lio.put_new_line
			config.ftp_mirror.transfer (tar_path.parent)
		end

	close
		do
			do_with_tables ("Closing", agent {like table_list.item}.close)
		end

	delete
		do
			do_with_tables ("Deleting", agent {like table_list.item}.close_and_delete)
		end

	delete_customer_linked (key: NATURAL_32)
		do
			do_with_tables ("Deleting linked", agent {like table_list.item}.delete_customer_linked (key))
		end

	fulfill_order (payment: PAYPAL_PAYMENT)

		local
			new_subscriptions: CUSTOMER_SUBSCRIPTION_LIST; delivery_email: SUBSCRIPTION_DELIVERY_EMAIL
		do
			payment_table.extend (payment)
			create new_subscriptions.make_from_payment (payment)
			subscription_table.append (new_subscriptions)
			if new_subscriptions.is_empty then
				lio.put_line ("No subscriptions sent")
			else
				create delivery_email.make (new_subscriptions, "")
				Email_queue.put (delivery_email)
				lio.put_line ("Subscription pack sent")
			end
		end

	try_fulfill_order (payment: PAYPAL_PAYMENT)
		do
			if payment.is_valid then
				fulfill_order (payment)
			else
				invalid_payment_table.extend (payment)
				Email_queue.put_failed (payment)
			end
		end

feature -- Factory

	new_address_table: ADDRESS_TABLE
		do
			create Result.make (config)
		end

	new_customer_table: CUSTOMER_TABLE
		do
			create Result.make (config)
		end

feature -- Import/Export operations

	export_as_csv
		do
			export_data (agent {like table_list.item}.csv_file_path, agent {like table_list.item}.store_as_csv)
		end

	export_as_pyxis
		do
			export_data (agent {like table_list.item}.pyxis_file_path, agent {like table_list.item}.store_as_pyxis)
		end

	export_meta_data
		do
			export_data (agent {like table_list.item}.meta_data_file_path, agent {like table_list.item}.store_meta_data)
		end

	import_csv
		do
			import_data (agent {like table_list.item}.csv_file_path, agent {like table_list.item}.import_from_csv)
		end

	import_pyxis
		do
			import_data (agent {like table_list.item}.pyxis_file_path, agent {like table_list.item}.import_from_pyxis)
		end

feature -- Status query

	has_customer (email: ZSTRING): BOOLEAN
		do
			Result := not customer_table.item_by_email (email).is_default
		end

feature {CUSTOMER_TABLE} -- Implementation

	do_with_tables (name: STRING; action: PROCEDURE [like table_list.item])
		do
			across table_list as table loop
				lio.put_labeled_string (name, table.item.name)
				lio.put_new_line
				action (table.item)
			end
		end

feature {NONE} -- Implementation

	enter_select_table_shell (name: ZSTRING; command_table: EL_PROCEDURE_TABLE [ZSTRING])
		local
			shell: EL_COMMAND_SHELL
		do
			create shell.make (name, command_table, 10)
			shell.run_command_loop
		end

	export_data (export_path: FUNCTION [like table_list.item, FILE_PATH]; export_store: PROCEDURE [like table_list.item])
		do
			across table_list as table loop
				lio.put_labeled_string ("Writing", export_path (table.item).base)
				lio.put_new_line
				export_store (table.item)
			end
		end

	import_data (import_path: FUNCTION [like table_list.item, FILE_PATH]; import_to: PROCEDURE [like table_list.item])
		local
			timer: EL_EXECUTION_TIMER
		do
			if prompts_suppressed.is_enabled
				or else User_input.approved_action_y_n ("Replace all existing data. Are you sure?")
			then
				create timer.make
				timer.start
				across table_list as table loop
					lio.put_labeled_string ("Importing from", import_path (table.item).base)
					lio.put_new_line
					import_to (table.item)
				end
				lio.put_labeled_string ("Elapsed time", timer.elapsed_time.out)
				lio.put_new_line
			end
		end

	is_table_field (field: EL_FIELD_TYPE_PROPERTIES): BOOLEAN
		do
			Result := field.is_reference and then field.conforms_to (Table_type_id)
		end

feature {NONE} -- Constants

	Table_type_id: INTEGER
		once
			Result := ({DATA_TABLE [REFLECTIVELY_STORABLE]}).type_id
		end

	Tar_directory_command: EL_CREATE_TAR_COMMAND
		once
			create Result.make
		end

end