├── .all-contributorsrc ├── .autorc ├── .dockerignore ├── .flake8 ├── .github ├── ISSUE_TEMPLATE │ └── feature_request.md ├── pull_request_template.md └── workflows │ ├── check-online-status.yml │ ├── codeql-analysis.yml │ ├── container-publish.yml │ ├── demo-videos.yml │ ├── git-auto-issue-branch-creation.yml │ ├── python-package.yml │ ├── release.yml │ ├── remove-inactive-pr-previews.py │ ├── remove-pr-preview.yml │ ├── removing-inactive-pr-preview.yml │ ├── test-email-shopowner-704.yml │ ├── testing-stripe-prod-and-test-webhooks.yml │ ├── update-all-sites.yml │ ├── update-docs.yml │ ├── update-onboarding-site.yml │ └── verify-prod-onboarding.yml ├── .gitignore ├── .python-version ├── CHANGELOG.md ├── CHECKS ├── CONTRIBUTING.md ├── Dockerfile ├── LICENSE ├── README.md ├── adding-env-settings.sh ├── babel.cfg ├── docker-compose.yml ├── docs ├── .gitmodules ├── .nvmrc ├── Dockerfile ├── LICENSE ├── README.md ├── assets │ └── scss │ │ └── _variables_project.scss ├── config.toml ├── content │ └── en │ │ ├── _index.html │ │ ├── blog │ │ ├── _index.md │ │ ├── news │ │ │ ├── _index.md │ │ │ ├── first-post │ │ │ │ ├── featured-sunset-get.png │ │ │ │ └── index.md │ │ │ └── second-post.md │ │ └── releases │ │ │ ├── _index.md │ │ │ └── in-depth-monoliths-detailed-spec.md │ │ ├── community │ │ └── _index.md │ │ ├── docs │ │ ├── Architecture │ │ │ ├── _index.md │ │ │ ├── events.md │ │ │ ├── logging.md │ │ │ ├── testing.md │ │ │ ├── translation.md │ │ │ └── webhooks.md │ │ ├── Concepts │ │ │ ├── _index.md │ │ │ ├── plan.md │ │ │ └── proration.md │ │ ├── Contribution guidelines │ │ │ └── _index.md │ │ ├── Examples │ │ │ └── _index.md │ │ ├── Getting started │ │ │ └── _index.md │ │ ├── Overview │ │ │ ├── _index.md │ │ │ └── features.md │ │ ├── Tasks │ │ │ ├── _index.md │ │ │ ├── add-a-free-trial.md │ │ │ ├── add-a-logo-to-a-shop.md │ │ │ ├── add-a-slogan.md │ │ │ ├── add-a-video-to-a-shop.md │ │ │ ├── add-documents-to-plans.md │ │ │ ├── add-new-subscription-plan.md │ │ │ ├── add-options-to-a-subscription-plan.md │ │ │ ├── add-plan-description.md │ │ │ ├── add-team-members.md │ │ │ ├── add-terms-and-conditions.md │ │ │ ├── adding-vat.md │ │ │ ├── calculate-subscription-revenue.md │ │ │ ├── cant-find-option-to-pause-a-subscription.md │ │ │ ├── categorise-subscription-plans.md │ │ │ ├── change-shop-colour.md │ │ │ ├── change-the-name-of-your-shop.md │ │ │ ├── change-your-subscription-website-web-address.md │ │ │ ├── charge-subscribers-on-an-ad-hoc-basis.md │ │ │ ├── collect-notes-from-customers.md │ │ │ ├── create-a-cooling-off-period-for-plans.md │ │ │ ├── create-a-private-plan.md │ │ │ ├── create-a-seasonal-plan.md │ │ │ ├── create-plan-link.md │ │ │ ├── create-private-pages.md │ │ │ ├── create-shop-page.md │ │ │ ├── delete-files.md │ │ │ ├── edit-an-existing-plan.md │ │ │ ├── embed-subscribie-into-your-website.md │ │ │ ├── enable-donations.md │ │ │ ├── enable-email-replies-for-your-subscription-emails.md │ │ │ ├── export-subscribers-from-your-shop.md │ │ │ ├── filter-transactions.md │ │ │ ├── pause-a-subscribers-subscription.md │ │ │ ├── refund-customer-subscriptions.md │ │ │ ├── reordering-plans.md │ │ │ ├── send-customised-emails-to-subscibers.md │ │ │ ├── shop-owners-updating-credit-card-details.md │ │ │ ├── update-subscription-card-details.md │ │ │ ├── upload-files.md │ │ │ ├── view-and-export-transactions-and-donations.md │ │ │ └── view-failed-payments.md │ │ ├── Tutorials │ │ │ ├── _index.md │ │ │ ├── create-a-subscription.md │ │ │ ├── link-stripe-to-shop.md │ │ │ ├── subscribie-dashboard-guide.md │ │ │ └── test-subscriber-signup │ │ └── _index.md │ │ ├── featured-background.jpg │ │ └── search.md ├── docker-compose.yaml ├── go.mod ├── go.sum ├── layouts │ ├── 404.html │ └── sitemap.xml ├── package.json ├── run-docs.sh └── smoketest-docs.sh ├── email-queue └── .gitkeep ├── emperor.ini ├── entrypoint.sh ├── migrations ├── README ├── alembic.ini ├── env.py ├── script.py.mako └── versions │ ├── 00477315ded9_add_created_at_column_stripe_invoice_.py │ ├── 041d569f7762_add_column_created_to_stripe_invoices_.py │ ├── 063ddc60bef1_association_table_plan_question.py │ ├── 07cc236f0a6d_remove_stripe_subscription_id_from_.py │ ├── 084669093d74_add_stripe_cancel_at_to_subscription_.py │ ├── 08dcbc5f9c6d_merge_abfb5c2f77e6_spamemaildomain_and_.py │ ├── 1653ed33cbd4_add_subscribie_checkout_session_id_to_.py │ ├── 1d4b6d333c16_.py │ ├── 207556b3039b_add_custom_thank_you_url_column.py │ ├── 21b64f9d73dd_add_trial_period_days_to_plan_model.py │ ├── 2378e3286d5b_correct_store_cancel_at_at_int.py │ ├── 262c26af9630_add_has_min_sell_price_has_min_interval_.py │ ├── 2c7e021d9a69_remove_stripe_publishable_key_stripe_.py │ ├── 2f3f0b5d2bde_add_archived_to_person_class.py │ ├── 3447b58b5c69_add_is_longform_question_to_question.py │ ├── 3a54f4b1187d_add_order_to_association_table_plan_.py │ ├── 3a8f3089d09d_create_upcoming_invoice_table.py │ ├── 3abcbb0428ef_add_stripe_connect_account_id_to_.py │ ├── 429b32b9ad20_add_plan_documents_association.py │ ├── 4694133a683a_merge_5d8_default_currency_and_7fba_add_.py │ ├── 48074e6225c6_add_subscription_stripe_ended_at.py │ ├── 4e7e3ee8972d_add_pricelistrule_model.py │ ├── 500f2d55c5d3_add_logintoken_model.py │ ├── 5259c05704c4_merge_has_min_sell_price_has_min_.py │ ├── 53840eddbb0f_add_taxrate_model.py │ ├── 54495b8316a1_add_currency_to_transactions_table.py │ ├── 56e852d799d1_add_stripe_webhook_test_columns.py │ ├── 57b068821280_add_primary_plan_question_associations.py │ ├── 5b308deca3d3_add_interval_unit_interval_amount_to_.py │ ├── 5d8da4e0a709_add_default_currency_to_setting.py │ ├── 5e756a48f86d_add_stripeinvoice_model.py │ ├── 6738e7241978_add_requires_discount_code_to_.py │ ├── 686d588c3c29_remove_stripe_test_webhooksecret_and_id.py │ ├── 6ae2db9a982b_add_pricelist_model.py │ ├── 6cc0e87e8836_add_bg_primary_to_modulestyle_model.py │ ├── 6d9febd1346e_add_currency_to_subscription_table.py │ ├── 702d6ee9b14f_compact_all_migrations.py │ ├── 746b4765a957_so_that_categories_may_be_ordered.py │ ├── 75a87d5ab587_add_back_stripe_subscription_id_to_.py │ ├── 75dffc3851d8_addassociation_table_price_list_to_rule.py │ ├── 7640c2a9be5b_merge_5259c05704c4_and_fbc611c57b7a.py │ ├── 790aae5a7013_add_file_model.py │ ├── 796ff2e47e13_add_charge_vat_to_setting_model.py │ ├── 7d502ba7279c_add_stripe_subscription_id_to_.py │ ├── 7fba2877d034_add_api_key_secret_live_api_key_secret_.py │ ├── 89b4e5e02eac_add_balance_model.py │ ├── 8c008c1333d5_add_stripe_user_attempted_checkout_flow_.py │ ├── 8d9ada7a21cd_add_description_to_plan_model.py │ ├── 9189f7033477_add_private_boolean_to_pages_model.py │ ├── 938b171f97ec_subscription_to_document_association.py │ ├── 94790e701430_adding_is_donation_in_transaction_table.py │ ├── 96430096c2c7_added_stripe_pause_collection_to_.py │ ├── 98099ff3eb9c_merge_heads.py │ ├── 98bd81ff72f9_merge_heads_4694133a683a_00477315ded9.py │ ├── a4d35e9917f7_add_geo_currency_enabled_to_settings.py │ ├── abc1ff0c85e0_add_mailchimp_integration_columns.py │ ├── abfb5c2f77e6_add_spamemaildomain.py │ ├── b28487bfca0f_merge_c39_add_cancel_at_and_d7b_add_.py │ ├── b3c13acc1013_store_cancel_at_as_int.py │ ├── b3f47a3f53e2_add_hascreatedat_to_all_models.py │ ├── b767faeb4c0d_add_private_to_plan_model.py │ ├── b8e926d239f9_create_category_table.py │ ├── bb76d2149316_add_parent_plan_revision_uuid_to_plan.py │ ├── bd63fd27d653_add_donations_columns_in_settings.py │ ├── c39dd6d1961f_add_cancel_at_to_plan_model.py │ ├── c48dccfb0df5_add_password_expired_to_user_and_.py │ ├── c57ff5a7436a_.py │ ├── c5bec71f1499_add_question_table.py │ ├── c5d444ee3ccd_rename_stripe_webhook_and_account_cols_.py │ ├── c70cd4900c96_add_answer_model.py │ ├── c751fe53a042_add_external_refund_id_to_transaction_.py │ ├── c7a493cd99d4_create_questionoption_model.py │ ├── d04243b7bd47_add_custom_code_to_setting_model.py │ ├── d7b1aaee84ab_add_stripe_status_to_subscription_model.py │ ├── d8c120e8212e_add_proration_behavior_stripe_proration_.py │ ├── da154873f3ab_add_created_at_uuid_to_.py │ ├── dde6bed9a56f_add_shop_activated_to_setting_model.py │ ├── e0919a39645f_add_stripe_livemode_column_to_taxrate_.py │ ├── e0a8901cde76_add_default_country_code_to_settings_.py │ ├── e9e1f148655e_add_association_table_plan_to_price_.py │ ├── ee8e62e05b40_add_back_stripe_test_mode_colums.py │ ├── f064a641532c_set_stripe_active_default_false_and_add_.py │ ├── f0e91df9fbf1_add_stripe_livemode_to_payment_provider.py │ ├── f3579efd3331_add_stripe_external_id_to_subscription_.py │ ├── fbc611c57b7a_add_hasreadonly_read_only_mixin_to_.py │ ├── fc7ac6f06521_add_document_table.py │ ├── fcd870ab34b8_set_stripe_active_default_false.py │ └── fd28aefcdb76_add_css_properties_json_remove_bg_.py ├── operational_scripts ├── README.md ├── generate-compiled-language-files-3.sh ├── generate-language-catalog-2.sh ├── generate-pot-file-1.sh ├── openit.mjs └── recover-database.py ├── package-lock.json ├── package.json ├── pyproject.toml ├── rename-shop.sh ├── requirements-dev.lock ├── requirements.lock ├── run.sh ├── runtests.sh ├── seed.sql ├── settings.yaml.example ├── subscribie.wsgi ├── subscribie ├── TelegramHTTPHandler.py ├── Template.py ├── __init__.py ├── anti_spam_subscribie_shop_names │ ├── main.py │ └── run.py ├── api.py ├── auth.py ├── blueprints │ ├── __init__.py │ ├── admin │ │ ├── ResetSite.py │ │ ├── __init__.py │ │ ├── choice_group.py │ │ ├── export_subscribers.py │ │ ├── export_transactions.py │ │ ├── getLoadedModules.py │ │ ├── invoice.py │ │ ├── option.py │ │ ├── priceList.py │ │ ├── priceListRule.py │ │ ├── question_option.py │ │ ├── static │ │ │ ├── Mailchimp-logo.png │ │ │ ├── box.svg │ │ │ ├── cc.svg │ │ │ ├── cc_white.svg │ │ │ ├── custom_style.css │ │ │ ├── fb.svg │ │ │ ├── google_tag_manager.jpg │ │ │ ├── insta.svg │ │ │ ├── item1.svg │ │ │ ├── item2.svg │ │ │ ├── item3.svg │ │ │ ├── js │ │ │ │ └── app.js │ │ │ ├── logo.svg │ │ │ ├── money.svg │ │ │ ├── mutli-box.svg │ │ │ ├── onboarding.svg │ │ │ ├── open.svg │ │ │ ├── order.svg │ │ │ ├── packing_peanuts.png │ │ │ ├── start.svg │ │ │ ├── stripe.svg │ │ │ ├── style.css │ │ │ ├── tawk_logo.png │ │ │ ├── tawk_property_id.png │ │ │ ├── tick.svg │ │ │ └── twitter.svg │ │ ├── stats.py │ │ ├── subscriber.py │ │ ├── subscription.py │ │ └── templates │ │ │ ├── _formhelpers.html │ │ │ └── admin │ │ │ ├── add_custom_code.html │ │ │ ├── add_plan.html │ │ │ ├── add_shop_admin.html │ │ │ ├── cancel_subscription.html │ │ │ ├── categories │ │ │ ├── add_category.html │ │ │ ├── category_assign_plan.html │ │ │ ├── edit_category.html │ │ │ └── list_categories.html │ │ │ ├── change_email.html │ │ │ ├── change_password.html │ │ │ ├── choice_group │ │ │ ├── add_choice_group.html │ │ │ ├── add_question.html │ │ │ ├── choice_group_assign_plan.html │ │ │ ├── edit_choice_group.html │ │ │ └── list_choice_groups.html │ │ │ ├── connect_google_tag_manager_manually.html │ │ │ ├── connect_mailchimp_manually.html │ │ │ ├── connect_tawk_manually.html │ │ │ ├── dashboard.html │ │ │ ├── delete_admin_confirmation.html │ │ │ ├── delete_plan_choose.html │ │ │ ├── delete_shop_admin.html │ │ │ ├── documents │ │ │ ├── add_document.html │ │ │ ├── document_assign_plan.html │ │ │ ├── edit_document.html │ │ │ └── list_documents.html │ │ │ ├── edit.html │ │ │ ├── email │ │ │ └── edit_customer_sign_up_email.html │ │ │ ├── forgot_password.html │ │ │ ├── index.html │ │ │ ├── invoice │ │ │ └── failed_invoices.html │ │ │ ├── invoices.html │ │ │ ├── layout.html │ │ │ ├── login.html │ │ │ ├── logout.html │ │ │ ├── option │ │ │ ├── add_option.html │ │ │ ├── edit_option.html │ │ │ └── list_options.html │ │ │ ├── order-notes.html │ │ │ ├── pause_subscription.html │ │ │ ├── pricing │ │ │ ├── priceList │ │ │ │ ├── add_priceList.html │ │ │ │ ├── edit_priceList.html │ │ │ │ └── list_priceLists.html │ │ │ └── priceListRule │ │ │ │ ├── add_priceListRule.html │ │ │ │ ├── edit_priceListRule.html │ │ │ │ └── list_priceListRules.html │ │ │ ├── question │ │ │ ├── edit_question.html │ │ │ ├── list_questions.html │ │ │ ├── question_assign_plan.html │ │ │ └── set_question_order.html │ │ │ ├── question_option │ │ │ ├── add_question_option.html │ │ │ ├── edit_question_option.html │ │ │ └── list_question_options.html │ │ │ ├── recent_subscription_cancellations.html │ │ │ ├── refund_subscription.html │ │ │ ├── reset_password.html │ │ │ ├── resume_subscription.html │ │ │ ├── settings │ │ │ ├── api_keys.html │ │ │ ├── custom_thank_you_page.html │ │ │ ├── donations_enabled.html │ │ │ ├── geo_currency_settings.html │ │ │ ├── rename_shop.html │ │ │ ├── set_reply_to_email.html │ │ │ ├── stripe │ │ │ │ └── stripe_connect.html │ │ │ └── vat_settings.html │ │ │ ├── subscriber │ │ │ ├── charge_subscriber.html │ │ │ └── show_subscriber.html │ │ │ ├── subscribers-archived.html │ │ │ ├── subscribers.html │ │ │ ├── subscribers_bulk_operations_index.html │ │ │ ├── transactions.html │ │ │ ├── upcoming_invoices.html │ │ │ ├── upload_logo.html │ │ │ └── uploads │ │ │ ├── list_files.html │ │ │ └── upload_files.html │ ├── api │ │ └── __init__.py │ ├── checkout │ │ ├── __init__.py │ │ └── templates │ │ │ ├── donation_form.html │ │ │ ├── donation_summary.html │ │ │ ├── new_customer.html │ │ │ ├── order_summary.html │ │ │ └── thankyou.html │ ├── document │ │ ├── __init__.py │ │ └── templates │ │ │ └── list_documents.html │ ├── iframe │ │ ├── __init__.py │ │ └── templates │ │ │ └── show-iframe-embed.html │ ├── pages │ │ ├── __init__.py │ │ └── templates │ │ │ ├── add_page.html │ │ │ ├── delete_page.html │ │ │ ├── delete_pages_list.html │ │ │ ├── edit_page.html │ │ │ ├── edit_pages_list.html │ │ │ ├── module_pages_index.html │ │ │ └── update_private_pages.html │ ├── seo │ │ ├── __init__.py │ │ └── templates │ │ │ ├── list-urls.html │ │ │ └── set-page-title.html │ ├── style │ │ ├── __init__.py │ │ └── templates │ │ │ └── show-custom-css.html │ └── subscriber │ │ ├── __init__.py │ │ └── templates │ │ └── subscriber │ │ ├── account.html │ │ ├── forgot_password.html │ │ ├── layout.html │ │ ├── list_files.html │ │ ├── login.html │ │ ├── reset_password.html │ │ ├── subscriber_failed_invoices.html │ │ ├── subscriber_invoices.html │ │ ├── subscriptions.html │ │ └── update_choices.html ├── custom_pages │ └── .gitkeep ├── database.py ├── email.py ├── emails │ ├── donation.jinja2.html │ ├── subscriber-payment-failed-notification.jinja2.html │ ├── subscriber-reset-password.jinja2.html │ ├── update-choices.jinja2.html │ ├── user-new-subscriber-notification.jinja2.html │ ├── user-reset-password.jinja2.html │ └── welcome.jinja2.html ├── forms.py ├── logger.py ├── models.py ├── notifications.py ├── receivers.py ├── schemas │ ├── __init__.py │ └── schemas.py ├── settings.py ├── signals.py ├── static │ └── .gitkeep ├── tasks.py ├── themes │ ├── .gitkeep │ ├── theme-builder │ │ ├── builder │ │ │ ├── _formhelpers.html │ │ │ ├── changed.html │ │ │ ├── changes.html │ │ │ ├── choose.html │ │ │ ├── collect-membership-fees.html │ │ │ ├── errors │ │ │ │ ├── 404.html │ │ │ │ └── 500.html │ │ │ ├── faq.html │ │ │ ├── features.html │ │ │ ├── layout.html │ │ │ ├── login.html │ │ │ ├── new_customer.html │ │ │ ├── order_summary.html │ │ │ ├── pricing.html │ │ │ ├── products.html │ │ │ ├── refund-policy.html │ │ │ ├── select-package.html │ │ │ ├── shops.html │ │ │ ├── start-building.html │ │ │ ├── subscription-website-builder-uk.html │ │ │ ├── subscriptionbilling.html │ │ │ ├── subscriptionsoftware.html │ │ │ ├── thankyou.html │ │ │ ├── total.html │ │ │ ├── view-plan.html │ │ │ └── why-subscribie.html │ │ └── static │ │ │ ├── app.js │ │ │ ├── credit.png │ │ │ ├── feature1.png │ │ │ ├── feature2.png │ │ │ ├── feature3.png │ │ │ ├── gocardless-blue-rgb_2018.svg │ │ │ ├── gocardless-white-rgb_2018.svg │ │ │ ├── google-icon.svg │ │ │ ├── google-signin-component.js │ │ │ ├── google-signin-template.css │ │ │ ├── google_tag_manager.jpg │ │ │ ├── happy-shopper.svg │ │ │ ├── home.css │ │ │ ├── iconfinder_Circled_Facebook_svg_5279111.png │ │ │ ├── iconfinder_Circled_Instagram_svg_5279112.png │ │ │ ├── iconfinder_Circled_Twitter_svg_5279123.png │ │ │ ├── item1.svg │ │ │ ├── item2.svg │ │ │ ├── item3.svg │ │ │ ├── meta-thumbnail.png │ │ │ ├── money.svg │ │ │ ├── no-credit.png │ │ │ ├── onboarding.svg │ │ │ ├── photos │ │ │ └── .gitkeep │ │ │ ├── right_top.png │ │ │ ├── shop.svg │ │ │ ├── snackbar.min.css │ │ │ ├── snackbar.min.js │ │ │ ├── start-a-subscription-website-example.png │ │ │ ├── start.svg │ │ │ ├── start2.svg │ │ │ ├── steps │ │ │ ├── 1.svg │ │ │ ├── 2.svg │ │ │ ├── 3.svg │ │ │ └── 4.svg │ │ │ ├── stripe.svg │ │ │ ├── style.css │ │ │ ├── subscription-embed-widgetpng.png │ │ │ └── tick.svg │ └── theme-jesmond │ │ ├── jesmond │ │ ├── choose.html │ │ ├── errors │ │ │ ├── 404.html │ │ │ ├── 500.html │ │ │ └── ui-error.html │ │ ├── layout.html │ │ ├── macros │ │ │ └── plan_card.html │ │ ├── set_options.html │ │ ├── set_questions.html │ │ └── view-plan.html │ │ └── static │ │ ├── box.svg │ │ ├── cc.svg │ │ ├── cc_white.svg │ │ ├── fb.svg │ │ ├── google-icon.svg │ │ ├── google_tag_manager.jpg │ │ ├── insta.svg │ │ ├── item1.svg │ │ ├── item2.svg │ │ ├── item3.svg │ │ ├── logo.svg │ │ ├── money.svg │ │ ├── mutli-box.svg │ │ ├── onboarding.svg │ │ ├── open.svg │ │ ├── order.svg │ │ ├── packing_peanuts.png │ │ ├── spectrum │ │ ├── spectrum.min.css │ │ └── spectrum.min.js │ │ ├── start.svg │ │ ├── stripe.svg │ │ ├── style.css │ │ ├── tawk_logo.png │ │ ├── tawk_property_id.png │ │ ├── tick.svg │ │ └── twitter.svg ├── translations │ ├── de │ │ └── LC_MESSAGES │ │ │ ├── messages.mo │ │ │ └── messages.po │ ├── es │ │ └── LC_MESSAGES │ │ │ ├── messages.mo │ │ │ └── messages.po │ ├── fr │ │ └── LC_MESSAGES │ │ │ ├── messages.mo │ │ │ └── messages.po │ └── hr │ │ └── LC_MESSAGES │ │ ├── messages.mo │ │ └── messages.po ├── uploads │ └── .gitkeep ├── utils.py └── views.py ├── test.sh ├── tests ├── amber.yaml ├── browser-automated-tests-playwright │ ├── .env.example │ ├── delete-connect-account-id.js │ ├── e2e │ │ ├── 1005_shop_owner_terms_and_conditions_creation.spec.js │ │ ├── 1005_subscriber_terms_and_condition_check_test.spec.js │ │ ├── 1065_shop_owner_enabling_donations.spec.js │ │ ├── 1065_subscriber_checkout_donation.spec.js │ │ ├── 1219_custom_thank_you_url.spec.js │ │ ├── 121_shop_owner_public_page_creation.spec.js │ │ ├── 130-1_shop_owner_can_create_choice_options.spec.js │ │ ├── 1333-1_subscriber_order_free_plan_with_question_attached.spec.js │ │ ├── 1333_shop_owner_add_free_text_question.spec.js │ │ ├── 133_shop_owner_plan_creation.spec.js │ │ ├── 133_subscriber_order_plan_with_cooling_off.spec.js │ │ ├── 1431_shop_owner_bulk_pause_payment_collection_all_subscribers.spec.js │ │ ├── 147_shop_owner_pause_resume_and_cancel_subscriptions.spec.js │ │ ├── 1_stripe_connect.spec.js │ │ ├── 212_shop_owner_slogan_creation.spec.js │ │ ├── 264_subscriber_order_plan_with_choice_options_and_required_note.spec.js │ │ ├── 275_shop_owner_changing_plans_order.spec.js │ │ ├── 293-1_subscriber_order_plan_with_only_recurring_charge.spec.js │ │ ├── 293-2_subscriber_order_plan_with_only_upfront_charge.spec.js │ │ ├── 293-3_subscriber_order_plan_with_weekly_recurring_and_upfront_charge.spec.js │ │ ├── 293_subscriber_order_plan_with_only_upfront_charge.js │ │ ├── 293_subscriber_order_plan_with_recurring_and_upfront_charge.js │ │ ├── 334_shop_owner_private_page_creation.spec.js │ │ ├── 387_shop_owner_change_shop_colour.spec.js │ │ ├── 452_shop_owner_categories_creation.spec.js │ │ ├── 463_shop_owner_adding_vat.spec.js │ │ ├── 463_subscriber_ordering_plan_with_VAT.spec.js │ │ ├── 475_shop_owner_create_free_plan_with_question_attached.spec.js │ │ ├── 475_subscriber_order_plan_with_free_trial.spec.js │ │ ├── 516_subscriber_order_plan_with_cancel_at.spec.js │ │ ├── 619_shop_owner_transaction_filter_by_name_and_by_plan_title.spec.js │ │ ├── 623_subscriber_magic_login.spec.js │ │ ├── 704_shop_owner_magic_login_receives_email.js │ │ ├── 872_uploading_plan_picture.spec.js │ │ ├── 905-subscriber-search-by-email-and-name.spec.js │ │ ├── 939_subscriber_order_free_plan_with_terms_and_conditions.spec.js │ │ ├── 993_subscriber_change_card_details.spec.js │ │ ├── checkShopOwnerLogin.js │ │ ├── checkSubscriberLogin.js │ │ ├── features │ │ │ ├── admin_login.js │ │ │ ├── clear_db.js │ │ │ ├── fetch_upcomming_invoices.js │ │ │ └── set_test_name_cookie.js │ │ └── test_prod_new_customer_can_sign_up.js │ ├── github.spec.js │ ├── logo-subscribie.png │ ├── playwright.config.ts │ ├── requirements.txt │ ├── run-playwright-tests.py │ ├── test-videos │ │ └── .gitkeep │ ├── worker2.spec.js │ └── worker3.spec.js ├── conftest.py ├── delete_stripe_accounts_bulk.py └── test_subscribie.py └── vassals-inject-config.ini /.all-contributorsrc: -------------------------------------------------------------------------------- 1 | { 2 | "projectName": "subscribie", 3 | "projectOwner": "Subscribie", 4 | "repoType": "github", 5 | "repoHost": "https://github.com", 6 | "files": [ 7 | "CONTRIBUTING.md" 8 | ], 9 | "imageSize": 100, 10 | "commit": true, 11 | "commitConvention": "none", 12 | "contributors": [], 13 | "contributorsPerLine": 7 14 | } 15 | -------------------------------------------------------------------------------- /.autorc: -------------------------------------------------------------------------------- 1 | { 2 | "plugins": [ 3 | "git-tag", 4 | "conventional-commits", 5 | "first-time-contributor", 6 | "released" 7 | ], 8 | "owner": "subscribie", 9 | "repo": "subscribie", 10 | "name": "subscribie-bot", 11 | "email": "noreply@subscribie.co.uk" 12 | } 13 | -------------------------------------------------------------------------------- /.dockerignore: -------------------------------------------------------------------------------- 1 | draft.toml 2 | charts/ 3 | NOTICE 4 | LICENSE 5 | data.db* 6 | venv 7 | .venv 8 | __pycache__ 9 | dist 10 | .git 11 | -------------------------------------------------------------------------------- /.flake8: -------------------------------------------------------------------------------- 1 | [flake8] 2 | max-line-length = 88 3 | ignore=E402, W503 4 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Is your feature request related to a problem? Please describe.** 11 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 12 | 13 | **Describe the solution you'd like** 14 | A clear and concise description of what you want to happen. 15 | 16 | **Describe alternatives you've considered** 17 | A clear and concise description of any alternative solutions or features you've considered. 18 | 19 | **Additional context** 20 | Add any other context or screenshots about the feature request here. 21 | -------------------------------------------------------------------------------- /.github/pull_request_template.md: -------------------------------------------------------------------------------- 1 | Issue ref: # 2 | 3 | Screenshot before: 4 | 5 | 6 | Screenshot after: 7 | 8 | 9 | How to run test(s) for this PR see: [Testing](https://docs.subscribie.co.uk/docs/architecture/testing/) 10 | -------------------------------------------------------------------------------- /.github/workflows/check-online-status.yml: -------------------------------------------------------------------------------- 1 | name: Check online status 2 | 3 | on: 4 | workflow_dispatch: 5 | schedule: 6 | # Runs "at minute 50 past every hour" (see https://crontab.guru) 7 | - cron: '50 * * * *' 8 | jobs: 9 | build: 10 | name: Check public urls OK 11 | runs-on: ubuntu-latest 12 | steps: 13 | - name: check urls load OK 14 | run: | 15 | curl -Isf ${{ secrets.SUBSCRIBIE_URL }} | head -n 1 16 | curl -Isf ${{ secrets.SUBSCRIBIE_URL }}/blog/ | head -n 1 17 | -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | name: Release 2 | 3 | on: 4 | push: 5 | branches: 6 | - master 7 | paths-ignore: 8 | - 'docs/**' 9 | workflow_dispatch: 10 | 11 | jobs: 12 | release: 13 | runs-on: ubuntu-latest 14 | if: "!contains(github.event.head_commit.message, 'ci skip') && !contains(github.event.head_commit.message, 'skip ci')" 15 | steps: 16 | - uses: actions/checkout@v4 17 | 18 | - name: Prepare repository 19 | run: git fetch --unshallow --tags 20 | 21 | - name: Display the environment variables and their values 22 | run: | 23 | curl -L -o /tmp/auto.gz https://github.com/intuit/auto/releases/download/v11.1.6/auto-linux.gz 24 | gzip -d /tmp/auto.gz 25 | chmod +x /tmp/auto 26 | 27 | - name: Create Release 28 | env: 29 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 30 | run: | 31 | npx /tmp/auto shipit 32 | 33 | -------------------------------------------------------------------------------- /.github/workflows/remove-pr-preview.yml: -------------------------------------------------------------------------------- 1 | name: remove pr preview 2 | on: 3 | pull_request: 4 | types: [closed] 5 | 6 | jobs: 7 | Delete: 8 | environment: testing 9 | runs-on: ubuntu-latest 10 | steps: 11 | - name: remove pr preview 12 | env: 13 | SSH_PRIVATE_KEY: ${{ secrets.SSH_PRIVATE_KEY }} 14 | DOKKU_HOST: ${{ secrets.DOKKU_HOST }} 15 | run: | 16 | set -x 17 | mkdir -p ~/.ssh 18 | ssh-keyscan ${{ secrets.DOKKU_HOST }}>> ~/.ssh/known_hosts 19 | eval `ssh-agent -s` 20 | ssh-add - <<< "$SSH_PRIVATE_KEY" 21 | echo SUBDOMAIN=`echo "${{ github.head_ref }}" | tr '[:upper:]' '[:lower:]' | cut -c -60 | rev | sed 's/[^[:alnum:]]//1' | rev` >> $GITHUB_ENV 22 | echo deleting dokku app ${{ env.SUBDOMAIN }} 23 | ssh dokku@$DOKKU_HOST -C "dokku -- --force apps:destroy ${{ env.SUBDOMAIN }}" 24 | -------------------------------------------------------------------------------- /.github/workflows/removing-inactive-pr-preview.yml: -------------------------------------------------------------------------------- 1 | name: Daily pull request activity check 2 | on: 3 | workflow_dispatch: 4 | schedule: 5 | - cron: "0 0 * * *" 6 | 7 | jobs: 8 | daily-job: 9 | runs-on: ubuntu-latest 10 | steps: 11 | - name: Checkout repository 12 | uses: actions/checkout@v4 13 | 14 | - name: Set up Python 15 | uses: actions/setup-python@v2 16 | with: 17 | python-version: 3.8 18 | 19 | - name: Install dependencies 20 | run: | 21 | python -m pip install --upgrade pip 22 | pip install requests 23 | 24 | - name: Get Pull Request Age 25 | env: 26 | DOKKU_HOST: ${{ secrets.DOKKU_HOST }} 27 | SSH_PRIVATE_KEY: ${{ secrets.SSH_PRIVATE_KEY }} 28 | run: | 29 | set -x 30 | mkdir -p ~/.ssh 31 | ssh-keyscan ${{ secrets.DOKKU_HOST }}>> ~/.ssh/known_hosts 32 | eval `ssh-agent -s` 33 | ssh-add - <<< "$SSH_PRIVATE_KEY" 34 | echo deleting dokku app ${{ github.head_ref }} 35 | python .github/workflows/remove-inactive-pr-previews.py 36 | 37 | -------------------------------------------------------------------------------- /.github/workflows/testing-stripe-prod-and-test-webhooks.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | name: testing stripe prod and test webhooks 4 | on: 5 | schedule: 6 | - cron: "0 9 * * *" # 9am 7 | - cron: "0 19 * * *" # 7pm 8 | workflow_dispatch: 9 | jobs: 10 | testing-stripe-prod-and-test-webhooks: 11 | runs-on: ubuntu-22.04 12 | timeout-minutes: 5 13 | environment: production 14 | steps: 15 | - uses: actions/checkout@v2 16 | with: 17 | fetch-depth: 0 18 | 19 | - uses: actions/setup-node@v1 20 | 21 | - name: testing stripe production webhooks 22 | run: | 23 | set -e 24 | curl -v -H 'Content-Type: application/json' ${{ secrets.PROD_ANNOUNCER }} -d '{"stripe_connect_account_id":0, "site_url": "example.com"}' | grep 'example.com' 25 | if [ $? == '0' ] 26 | then 27 | echo "production stripe webhook is working" 28 | else 29 | echo "production stripe webhook not working" 30 | exit 1 31 | fi 32 | 33 | - name: testing stripe test webhooks 34 | run: | 35 | set -e 36 | curl -v -H 'Content-Type: application/json' ${{ secrets.TEST_ANNOUNCER }} -d '{"stripe_connect_account_id":0, "site_url": "example.com"}' | grep 'example.com' 37 | 38 | if [ $? == '0' ] 39 | then 40 | echo "testing stripe webhook is working" 41 | else 42 | echo "testing stripe webhook not working" 43 | exit 1 44 | fi 45 | 46 | -------------------------------------------------------------------------------- /.github/workflows/update-onboarding-site.yml: -------------------------------------------------------------------------------- 1 | name: Update Onboarding Site 2 | on: 3 | workflow_dispatch: 4 | push: 5 | paths: 6 | - 'subscribie/themes/theme-builder/**' 7 | jobs: 8 | update_onboarding: 9 | name: Update onboarding 10 | runs-on: ubuntu-22.04 11 | steps: 12 | - name: Setup ssh access 13 | run: | 14 | set -x 15 | mkdir -p ~/.ssh 16 | eval `ssh-agent -s` 17 | ssh-add - <<< "${{ secrets.ONBOARDING_PRIVATE_KEY }}" 18 | ssh-keyscan ${{ secrets.ONBOARDING_HOST }}>> ~/.ssh/known_hosts 19 | - name: Pull new site & reload 20 | run: | 21 | set -x 22 | eval `ssh-agent -s` 23 | ssh-add - <<< "${{ secrets.UPDATE_ALL_SITES_PRIVATE_KEY}}" 24 | ssh ${{ secrets.ONBOARDING_USER }}@${{ secrets.ONBOARDING_HOST }} -C "cd ${{ secrets.SHAREDREPO_PATH }}; git fetch; git rebase origin/master;" 25 | ssh ${{ secrets.ONBOARDING_USER }}@${{ secrets.ONBOARDING_HOST }} -C "cd ${{ secrets.ONBOARDING_WEBSITE_PATH }}; touch *.ini; " 26 | 27 | -------------------------------------------------------------------------------- /.github/workflows/verify-prod-onboarding.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: Verify Prod Onbording 3 | on: 4 | schedule: 5 | - cron: "0 9 * * *" # 9am 6 | - cron: "0 19 * * *" # 7pm 7 | workflow_dispatch: 8 | jobs: 9 | deploy-pr: 10 | runs-on: ubuntu-22.04 11 | timeout-minutes: 15 12 | environment: production 13 | steps: 14 | - uses: actions/checkout@v4 15 | with: 16 | fetch-depth: 0 17 | - uses: actions/setup-node@v4 18 | - name: Install playwright dependencies 19 | run: npm ci 20 | - name: Install playwright browsers 21 | run: npx playwright install --with-deps 22 | 23 | - name: Run & Record browser automated tests (Playwright) 24 | env: 25 | PLAYWRIGHT_HEADLESS: true 26 | run: | 27 | set -x 28 | node --unhandled-rejections=strict tests/browser-automated-tests-playwright/e2e/test_prod_new_customer_can_sign_up.js 29 | - uses: actions/upload-artifact@v4 30 | if: ${{ always() }} 31 | with: 32 | name: Screenshots-and-video-artifacts 33 | path: | 34 | ./*.png 35 | ./tests/browser-automated-tests-playwright/videos/* 36 | 37 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | settings.yaml 2 | settings.yml 3 | *.pem 4 | venv/ 5 | .venv 6 | *.swp 7 | *.pyc 8 | __pycache__/ 9 | .pytest_cache/ 10 | .coverage 11 | htmlcov/ 12 | 13 | dist/ 14 | build/ 15 | *.egg-info/ 16 | .env 17 | Subscribie.egg-info* 18 | subscribie.egg-info/* 19 | build/* 20 | dist/* 21 | data.db 22 | data.db* 23 | modules/ 24 | *.db 25 | *.pub 26 | id_rsa 27 | .vscode 28 | .mypy_cache 29 | .project 30 | .pylintrc 31 | node_modules 32 | *chromium.png 33 | *webkit.png 34 | .env 35 | .env* 36 | .env.docker 37 | *.webm 38 | public 39 | resources/ 40 | node_modules/ 41 | package-lock.json 42 | .hugo_build.lock 43 | .pem 44 | test-results 45 | tests/browser-automated-tests-playwright/index.spec.js-snapshots/* 46 | tests/browser-automated-tests-playwright/worker* 47 | tests/browser-automated-tests-playwright/e2e/*-snapshots 48 | tests/browser-automated-tests-playwright/test-videos/* 49 | tests/browser-automated-tests-playwright/graphviz_output* 50 | subscribie/static/* 51 | subscribie/custom_pages/* 52 | playwright-report 53 | .terraform 54 | *.pkl 55 | emails 56 | *.bk 57 | email-queue 58 | uploads/* 59 | -------------------------------------------------------------------------------- /.python-version: -------------------------------------------------------------------------------- 1 | cpython-x86_64-linux@3.12.0 2 | -------------------------------------------------------------------------------- /CHECKS: -------------------------------------------------------------------------------- 1 | /choose Soap Subscription -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | # syntax = docker/dockerfile:experimental 2 | FROM python:3.12-slim-bullseye 3 | WORKDIR /usr/src/app 4 | RUN apt-get update && apt-get install -y \ 5 | libffi-dev libcurl4-openssl-dev bash gcc sqlite3 \ 6 | build-essential curl 7 | 8 | COPY . /usr/src/app/subscribie/ 9 | WORKDIR /usr/src/app/subscribie/ 10 | RUN --mount=type=cache,target=/root/.cache/pip pip install -r requirements.lock 11 | RUN --mount=type=cache,target=/root/.cache/pip pip install uwsgi 12 | EXPOSE 5000 13 | ENTRYPOINT [ "./entrypoint.sh" ] 14 | -------------------------------------------------------------------------------- /adding-env-settings.sh: -------------------------------------------------------------------------------- 1 | #! /bin/bash 2 | # Please make sure you are in the right directory 3 | #1. Run This Code with the new settings 4 | #2. Merge the pull request (all sites will reload automatically) 5 | 6 | PATH_TO_SITES=$2 7 | NEW_SETTINGS=$1 8 | if [ "$#" -ne 2 ] 9 | then 10 | echo "adding-settings-env.sh missing arguments" 11 | echo "Two arguments required" 12 | echo "Argument1 = newsetting='value'" 13 | echo "Argument2 = path/to/the/.env" 14 | echo "EXAMPLE" 15 | echo "./adding-settings-env.sh PATH_TO_SITES='/etc/home/' /etc/" 16 | else 17 | find $PATH_TO_SITES -maxdepth 2 -mindepth 2 -type f -name '.env' -exec grep $NEW_SETTINGS {} + 18 | if [ $? -ne 0 ] 19 | then 20 | echo "Adding new env setting..." 21 | find $PATH_TO_SITES -maxdepth 2 -mindepth 2 -type f -name '.env' -exec sh -c "echo $NEW_SETTINGS >> {}" \; 22 | echo "env setting succesfully added" 23 | exit 0 24 | else 25 | echo "The setting already exists" 26 | exit 1 27 | fi 28 | fi 29 | -------------------------------------------------------------------------------- /babel.cfg: -------------------------------------------------------------------------------- 1 | [python: subscribie/**.py] 2 | [jinja2: subscribie/themes/**.html] 3 | [jinja2: subscribie/blueprints/**.html] 4 | -------------------------------------------------------------------------------- /docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: "3.8" 2 | services: 3 | web: 4 | build: . 5 | ports: 6 | - "5000:80" 7 | env_file: 8 | - .env 9 | volumes: 10 | - type: bind 11 | source: . 12 | target: /usr/src/app/subscribie 13 | -------------------------------------------------------------------------------- /docs/.gitmodules: -------------------------------------------------------------------------------- 1 | 2 | [submodule "themes/docsy"] 3 | path = themes/docsy 4 | url = https://github.com/google/docsy 5 | -------------------------------------------------------------------------------- /docs/.nvmrc: -------------------------------------------------------------------------------- 1 | lts/* 2 | -------------------------------------------------------------------------------- /docs/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM klakegg/hugo:ext-alpine 2 | 3 | RUN apk add git && \ 4 | git config --global --add safe.directory /src 5 | -------------------------------------------------------------------------------- /docs/assets/scss/_variables_project.scss: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | Add styles or override variables from the theme here. 4 | 5 | */ 6 | 7 | -------------------------------------------------------------------------------- /docs/content/en/blog/_index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Subscribie Blog" 3 | linkTitle: "Blog" 4 | menu: 5 | main: 6 | weight: 30 7 | --- 8 | 9 | 10 | This is the **blog** section. It has two categories: News and Releases. 11 | 12 | Files in these directories will be listed in reverse chronological order. 13 | 14 | -------------------------------------------------------------------------------- /docs/content/en/blog/news/_index.md: -------------------------------------------------------------------------------- 1 | 2 | --- 3 | title: "News About Subscribie" 4 | linkTitle: "News" 5 | weight: 20 6 | --- 7 | 8 | 9 | -------------------------------------------------------------------------------- /docs/content/en/blog/news/first-post/featured-sunset-get.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Subscribie/subscribie/4ba736e39a1e867186fee4e4ec28ae8b4b1d3a3e/docs/content/en/blog/news/first-post/featured-sunset-get.png -------------------------------------------------------------------------------- /docs/content/en/blog/releases/_index.md: -------------------------------------------------------------------------------- 1 | 2 | --- 3 | title: "New Releases" 4 | linkTitle: "Releases" 5 | weight: 20 6 | --- 7 | 8 | 9 | -------------------------------------------------------------------------------- /docs/content/en/community/_index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Community 3 | menu: 4 | main: 5 | weight: 40 6 | --- 7 | 8 | 9 | -------------------------------------------------------------------------------- /docs/content/en/docs/Architecture/_index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Architecture" 3 | linkTitle: "Architecture" 4 | weight: 8 5 | description: > 6 | {{< alert color="warning" >}}This section is for developers- if you're looking to use Subscribie, 7 | then please read the documentation for users.{{< /alert >}} 8 | Implementation and system design information that potential project contributors can consult. 9 | 10 | --- 11 | 12 | {{% pageinfo %}} 13 | See [Subscribie architecture on Github](https://github.com/Subscribie/subscribie#architecture) 14 | {{% /pageinfo %}} -------------------------------------------------------------------------------- /docs/content/en/docs/Architecture/webhooks.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Webhooks" 3 | date: 2022-11-05 4 | weight: 2 5 | description: > 6 | How to configure webhooks to integrate Subscribie with your other applications. 7 | --- 8 | 9 | 10 | # Register your webhook endpoint via an API request 11 | 12 | 1. [Authenticate with Subscribie](https://docs.subscribie.co.uk/#authentication) 13 | 2. Send a `POST` request with your webhook endpoint address (see example below) 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /docs/content/en/docs/Concepts/_index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Concepts" 3 | linkTitle: "Concepts" 4 | weight: 30 5 | description: > 6 | What does your user need to understand about your project in order to use it - or potentially contribute to it? 7 | --- 8 | 9 | {{% pageinfo %}} 10 | This is a placeholder page that shows you how to use this template site. 11 | {{% /pageinfo %}} 12 | 13 | For many projects, users may not need much information beyond the information in the [Overview](/docs/overview/), so this section is **optional**. However if there are areas where your users will need a more detailed understanding of a given term or feature in order to do anything useful with your project (or to not make mistakes when using it) put that information in this section. For example, you may want to add some conceptual pages if you have a large project with many components and a complex architecture. 14 | 15 | Remember to focus on what the user needs to know, not just what you think is interesting about your project! If they don’t need to understand your original design decisions to use or contribute to the project, don’t put them in, or include your design docs in your repo and link to them. Similarly, most users will probably need to know more about how features work when in use rather than how they are implemented. Consider a separate architecture page for more detailed implementation and system design information that potential project contributors can consult. 16 | 17 | 18 | -------------------------------------------------------------------------------- /docs/content/en/docs/Concepts/plan.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Plans" 3 | linkTitle: "Plan" 4 | date: 2022-11-05 5 | weight: 2 6 | description: > 7 | A **Plan** can be _subscribed_ to by a **Subscriber**, which may result in a recurring **Subscription** if there 8 | is a recurring charge. 9 | --- 10 | 11 | {{% pageinfo %}} 12 | Not all Plans have a recurring charge: for example a free Plan. However, _all_ Plans have a Subscriber. 13 | When thinking about Subscriptions, it's helpful to think about Subscriptions and Payments as different things. 14 | {{% /pageinfo %}} 15 | -------------------------------------------------------------------------------- /docs/content/en/docs/Concepts/proration.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Proration" 3 | date: 2024-08-04 4 | weight: 2 5 | description: > 6 | Proration (also known as "pro-rata") in Subscribie refers to the calculation of a charge according to the amount a Subscription has been used in relation to time. 7 | As a shop owner, from your `Admin dashboard` `->` `Edit Plans` screen, you can configure a Plan to either "Do not prorate" or "Prorate". 8 | --- 9 | 10 | 11 | ## Do not prorate 12 | 13 | "Do not prorate" means to charge subscribers the full amount of the subscription, even if it ends before the period is over. 14 | 15 | 16 | ## Prorate (on) 17 | 18 | Prorate (on) means in the event that a Subscription is cancelled before the subscription period is over, then *don't* charge the subscriber of this [Plan]({{< ref "Plan" >}} "Plan") the full 19 | amount, instead charge only the used amount of the current period. 20 | 21 | For example, if a monthly subscription ends partway through the month, the final charge will be less since it is prorated based on the time used. 22 | 23 | -------------------------------------------------------------------------------- /docs/content/en/docs/Examples/_index.md: -------------------------------------------------------------------------------- 1 | 2 | --- 3 | title: "Examples" 4 | linkTitle: "Examples" 5 | weight: 3 6 | date: 2017-01-05 7 | description: > 8 | Example Subscribie Subscription Shop 9 | --- 10 | 11 | {{% pageinfo %}} 12 | Do you know? You can *[create a test shop here](https://subscribie.co.uk/)*. 13 | 14 | {{% /pageinfo %}} 15 | 16 | # Football Club example shop 17 | 18 | > This example shop below shows the key subscription software features: 19 | - Online sign-up for your customers to choose from the plans you create 20 | - Flexibiliy to offer different plans & choice options 21 | - Not displayed, but you can also offer 'Free' plans, trial plans, and up-front charges 22 | - For more options 23 | 24 | If you'd prefer to visit the example shop directly, go to: [footballclub.subscriby.shop](https://footballclub.subscriby.shop) 25 | 26 | -------------------------------------------------------------------------------- /docs/content/en/docs/Tasks/add-a-logo-to-a-shop.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Add a Logo to a shop" 3 | date: 2022-11-17 4 | weight: 5 5 | description: > 6 | Upload your own logo to your subscription shop 7 | --- 8 | 9 | Learn how to add a slogan, this will be displayed in your shop's banner below your shop's name. 10 | 11 | ## Steps to Add a Logo 12 | 13 | Step 1: Go to the *Upload Logo* section in your Subscribie dashboard. 14 | 15 | ![](https://subscribie.co.uk/blog/content/images/size/w1000/2023/02/add-a-logo-to-subscribie-shop-1-1.webp) 16 | 17 | Step 2: Click on "Choose File" and select your logo from your computer. 18 | 19 | ![](https://subscribie.co.uk/blog/content/images/size/w1000/2023/02/add-a-logo-to-subscribie-shop-2-1.webp) 20 | 21 | Step 3: Once you've chosen your logo, click on "Save". 22 | 23 | ![](https://subscribie.co.uk/blog/content/images/size/w1000/2023/02/add-a-logo-to-subscribie-shop-3-1.webp) 24 | 25 | Now, your logo will now be visible on your Subscribie subscription shop. Customers will see your logo when they visit your shop. 26 | 27 | You can also [add a slogan](https://docs.subscribie.co.uk/docs/tasks/add-a-slogan/) and [change the color of your shop.](https://docs.subscribie.co.uk/docs/tasks/change-shop-colour/) 28 | 29 | ### Watch this Tutorial to Add a Logo 30 | 31 | [![Watch the video](https://github.com/Subscribie/subscribie/assets/30567984/733e7f6c-f3cf-4724-aae4-b652f66c5eda)](https://youtube.com/watch?v=KcmhZfccR0w) -------------------------------------------------------------------------------- /docs/content/en/docs/Tasks/add-a-slogan.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Add a Slogan" 3 | date: 2022-11-17 4 | weight: 5 5 | description: > 6 | Add your own Slogan to your shop. This will be displayed in your shop. 7 | --- 8 | 9 | Learn how to add a slogan, this will be displayed in your shop's banner below your shop's name. 10 | 11 | ## Steps to Add a Slogan 12 | 13 | Step 1: Log into your Shop Dashboard. 14 | 15 | ![](https://subscribie.co.uk/blog/content/images/size/w1000/2022/11/image-64.png) 16 | 17 | Step 2: Under the *"Edit/Add Plans"* section, click *"Edit Plan".* 18 | 19 | ![](https://subscribie.co.uk/blog/content/images/size/w1000/2022/11/image-87.png) 20 | 21 | Step 3: Here type your Slogan in the *"Slogan"* Text box. 22 | 23 | ![](https://subscribie.co.uk/blog/content/images/size/w1000/2022/11/image-88.png) 24 | 25 | Now, your slogan will reflect on your shop page! 26 | 27 | You can also [add a logo](https://docs.subscribie.co.uk/docs/tasks/add-a-logo-to-a-shop) and [change the color of your shop.](https://docs.subscribie.co.uk/docs/tasks/change-shop-colour/) 28 | 29 | ### Watch the Tutorial to Add a Slogan 30 | 31 | [![Watch the video](https://github.com/Subscribie/subscribie/assets/30567984/1a930b73-ec9c-47a3-9f75-97ede3ec8c50)](https://www.youtube.com/watch?v=NfU1ReK2EB8) -------------------------------------------------------------------------------- /docs/content/en/docs/Tasks/add-team-members.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Add Team Members to Shop" 3 | date: 2022-11-28 4 | weight: 5 5 | description: > 6 | A guide to adding your team members to manage your subscription shop. 7 | --- 8 | 9 | Team members who are added can help manage your shop through the dashboard easily. 10 | 11 | ## Steps to Add Team Members to Subscription 12 | 13 | Step 1:** Log into your Shop Dashboard. 14 | 15 | ![](https://subscribie.co.uk/blog/content/images/size/w1000/2022/11/image-27.png) 16 | 17 | Step 2:** Under **"Users, Passwords & Cards details"** Tab choose **"Add Admin Shop".** 18 | 19 | ![](https://subscribie.co.uk/blog/content/images/size/w1000/2022/11/image-127.png) 20 | 21 | Step 3:** Enter the Email of your teammate and create a password. 22 | 23 | ![](https://subscribie.co.uk/blog/content/images/size/w1000/2022/11/image-128.png) 24 | 25 | Step 4:** Click **Save.** 26 | 27 | ![](https://subscribie.co.uk/blog/content/images/size/w1000/2022/11/image-129.png) 28 | 29 | Now you have added a team member to your shop! 30 | 31 | ### Watch the Tutorial to Add Team Members to Shop 32 | 33 | [![Watch the video](https://github.com/Subscribie/subscribie/assets/30567984/c90b6847-aef5-4edd-abb1-8973a7fbb7ba)](https://youtu.be/d5FTaMPmrgg) -------------------------------------------------------------------------------- /docs/content/en/docs/Tasks/adding-vat.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Charge VAT Automatically" 3 | date: 2022-11-09 4 | weight: 5 5 | description: > 6 | Need to charge VAT? Learn how you can automatically charge value added tax (VAT) to all your subscription plans 7 | --- 8 | 9 | Does your shop need to charge VAT for your products and services? You can enable the option to auto-calculate VAT with these steps. 10 | 11 | > VAT is not enabled by default for shops. 12 | 13 | ## Steps to add VAT to your Subsciption Plans. 14 | 15 | Step 1: On your Dashboard go to *"Manage My Shop"*. 16 | 17 | ![](https://subscribie.co.uk/blog/content/images/2022/10/image.png) 18 | 19 | Step 2: Scroll to the bottom of the list and under *"Shop Settings"* choose *"VAT Settings"*. 20 | 21 | ![](https://subscribie.co.uk/blog/content/images/2022/10/image-1.png) 22 | 23 | Step 3: To activate VAT choose *"Yes. Charge VAT at 20%"* and click *"Save"* 24 | 25 | ![](https://subscribie.co.uk/blog/content/images/2022/10/image-2.png) 26 | 27 | Now your shop is ready to charge VAT to your customers who sign up to your shop on Subscribie! 28 | Invoices generated will automatically have vat added during checkout and subsequent automaic charges. 29 | 30 | ### Watch the Tutorial to Charge VAT Automatically 31 | 32 | [![Watch the video](https://github.com/Subscribie/subscribie/assets/30567984/9614eef6-1c37-4356-962e-94a744ea4552)](https://youtu.be/XqM7Q2nvC3c) -------------------------------------------------------------------------------- /docs/content/en/docs/Tasks/collect-notes-from-customers.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Collect Order Notes" 3 | date: 2023-04-24 4 | weight: 5 5 | description: > 6 | Need a way to collect notes from customers? Learn how to collect order notes from customers as they sign-up. 7 | --- 8 | 9 | ## Steps to allow subscribers to add notes during sign-up 10 | 11 | Step 1: Go to *Edit Plans*, under the *Edit/Add Plans* tab. 12 | 13 | ![](https://subscribie.co.uk/blog/content/images/size/w1000/2023/04/image-12.png) 14 | 15 | Step 2: Under the plan, you would like to add a custom note to, enable "*Require Customer Note*". 16 | 17 | ![](https://subscribie.co.uk/blog/content/images/2023/04/image-13.png) 18 | 19 | Step 3: Enter instructions on what you would like your customers to fill out in the notes section in the *"Message to customer"* box 20 | 21 | ![](https://subscribie.co.uk/blog/content/images/2023/04/image-14.png) 22 | 23 | Step 4: Now, scroll down and Click Save 24 | 25 | ![](https://subscribie.co.uk/blog/content/images/size/w1000/2023/04/image-15.png) 26 | 27 | You subscribers can now add notes during sign-up to your plan. 28 | 29 | ### Watch the Tutorial to Collect Order Notes 30 | 31 | [![Watch the video](https://github.com/Subscribie/subscribie/assets/30567984/a661a514-5ee0-4172-bc36-25cc7af7cb54)](https://youtu.be/KOrKf8AXMM0) -------------------------------------------------------------------------------- /docs/content/en/docs/Tasks/create-a-private-plan.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Create a Private Plan" 3 | date: 2022-11-16 4 | weight: 5 5 | description: > 6 | A guide to creating a private subscription plan that is not visible in your shop. 7 | --- 8 | 9 | Follow these steps to create an account private plan, these private plans will not be visible on your shop's signup page but can accessed through the plan's link. Learn how to [create a subscription plan link here.](https://docs.subscribie.co.uk/docs/tasks/create-plan-link/) 10 | 11 | ## Steps to Create a Private Plan 12 | 13 | Step 1: Log into your Dashboard. 14 | 15 | ![](https://subscribie.co.uk/blog/content/images/size/w1000/2022/11/image-64.png) 16 | 17 | Step 2: Under the *"Edit/Add Plans"* section, click *"Edit Plan".* 18 | 19 | ![](https://subscribie.co.uk/blog/content/images/size/w1000/2022/11/image-65.png) 20 | 21 | Step 3: Here select the *"Private"* checkbox and click *Save.* 22 | 23 | ![](https://subscribie.co.uk/blog/content/images/size/w1000/2022/11/image-66.png) 24 | 25 | You have successfully created a private plan! Now, it will not be visable on your shop page, it can be shared through the subscription plan link. 26 | 27 | ### Watch the Tutorial for Creating a Private Plan 28 | 29 | [![Watch the video](https://github.com/Subscribie/subscribie/assets/30567984/e38a7158-650d-4557-8786-84df86a3ee25)](https://youtu.be/cFpvuSMOZq0) -------------------------------------------------------------------------------- /docs/content/en/docs/Tasks/create-a-seasonal-plan.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Create a Seasonal Plan" 3 | date: 2022-11-16 4 | weight: 5 5 | description: > 6 | Learn to create a seasonal subscription plan that ends at a specified date. 7 | --- 8 | 9 | A Sesonal Plan, which is also known as a Limited Plan, stops collecting payments after a specified date. To set up a seasonal plan that auto cancels, follow these steps. 10 | 11 | ## Steps to Create a Seasonal Plan 12 | 13 | Step 1: Log into your Shop Dashboard. 14 | 15 | ![](https://subscribie.co.uk/blog/content/images/size/w1000/2022/11/image-64.png) 16 | 17 | Step 2: Under the *"Edit/Add Plans"* section, click *"Edit Plan".* 18 | 19 | ![](https://subscribie.co.uk/blog/content/images/size/w1000/2022/11/image-77.png) 20 | 21 | Step 3: Here select the *"Cancel at"* checkbox, add the date and time you would like to end the subscription and click *Save.* 22 | 23 | ![](https://subscribie.co.uk/blog/content/images/2022/11/image-78.png) 24 | 25 | Now you have successfully created a limited-time Subscription Plan for your customers and potential Subscribers! 26 | Learn how you can [share your seasonal plans with a link.](https://docs.subscribie.co.uk/docs/tasks/create-plan-link/) 27 | 28 | ### Watch the Tutorial to Create a Seasonal Plan 29 | 30 | [![Watch the video](https://github.com/Subscribie/subscribie/assets/30567984/c95c9e71-5d58-4095-a8fe-435d90f3d86b)](https://youtu.be/AFYHSsXrqUE) -------------------------------------------------------------------------------- /docs/content/en/docs/Tasks/create-plan-link.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Create a Plan Link" 3 | date: 2022-11-16 4 | weight: 5 5 | description: > 6 | A guide to creating a link for a specific plan to share to subscribers. 7 | --- 8 | 9 | A Plan link can be used to share a specific plan to your customers so that they can pay and sign up to the subscription plan. 10 | 11 | > This is useful for sharing [private plans](https://docs.subscribie.co.uk/docs/tasks/create-a-private-plan/). 12 | 13 | ## Steps to Create a Plan Link 14 | 15 | Step 1: Log into your Shop Dashboard. 16 | 17 | ![](https://subscribie.co.uk/blog/content/images/size/w1000/2022/11/image-64.png) 18 | 19 | Step 2: Under the *"Edit/Add Plans"* section, click *"Edit Plan".* 20 | 21 | ![](https://subscribie.co.uk/blog/content/images/size/w1000/2022/11/image-77.png) 22 | 23 | Step 3: Here select the *"Cancel at"* checkbox, add the date and time you would like to end the subscription and click *Save.* 24 | 25 | ![](https://subscribie.co.uk/blog/content/images/size/w1000/2022/11/image-77.png) 26 | 27 | Now you have successfully created a limited-time Subscription Plan for your customers! 28 | 29 | ### Watch the Tutorial to Create a Plan Link 30 | 31 | [![Watch the video](https://github.com/Subscribie/subscribie/assets/30567984/4c08655a-1999-4586-9e47-9ba0f0f7ab77)](https://youtu.be/y1Z2Bh2MD9k) -------------------------------------------------------------------------------- /docs/content/en/docs/Tasks/create-private-pages.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Create a Private Page" 3 | date: 2022-11-10 4 | weight: 5 5 | description: > 6 | A guide to make any page in your shop into a Private Page. Private Pages are hidden pages that do not appear in your shop publically. 7 | --- 8 | 9 | Learn how to add a private page that is only accessable by your subscribers by following these steps. 10 | 11 | ## Steps to Create a Private Page 12 | 13 | Step 1: Log into your store and navigate to your Shop Dashboard. 14 | 15 | ![](https://github.com/Subscribie/subscribie/assets/30567984/5793910c-3d38-43de-9623-24777f4feb44) 16 | 17 | Step 2: Click the *"Modules"* tab and select *"List Pages"* under the *"Pages"* category. 18 | 19 | ![](https://github.com/Subscribie/subscribie/assets/30567984/96a92837-b34d-43cc-a62e-7cb2d95e21d7) 20 | 21 | Step 3: Select *"Set Private Pages"* 22 | 23 | ![](https://github.com/Subscribie/subscribie/assets/30567984/1c4e411a-be79-4bed-8aa3-7bfff95ac4fd) 24 | 25 | Step 4: Choose the Page and click *Submit.* 26 | 27 | > Select all the pages you wish to private in this step. 28 | 29 | ![](https://github.com/Subscribie/subscribie/assets/30567984/7d0f1b59-27b4-4577-a8dd-249cead5e1e9) 30 | 31 | Now you have created a private page. 32 | 33 | ### Watch the Tutorial to Create a Private Page 34 | 35 | [![Watch the video](https://github.com/Subscribie/subscribie/assets/30567984/d5d2165b-137a-4544-ae3c-171a0e1634c6)](https://youtu.be/iTM2peen1TM) -------------------------------------------------------------------------------- /docs/content/en/docs/Tasks/delete-files.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Delete a File from a Shop" 3 | date: 2022-11-18 4 | weight: 5 5 | description: > 6 | A guide to delete files from your shop perminantly. 7 | --- 8 | 9 | You learnt how to [add files to your shop](https://docs.subscribie.co.uk/docs/tasks/upload-files/), but what you uploaded the wrong file? Dont worry, we'll show you how to delete a file from your shop with these steps! 10 | 11 | > Be sure you are deleting the correct files, you can not recover deleted files once they are deleted. 12 | 13 | ## Steps to Delete a File from a Shop 14 | 15 | Step 1: Log into your Shop Dashboard. 16 | 17 | ![](https://subscribie.co.uk/blog/content/images/size/w1000/2022/11/image-64.png) 18 | 19 | Step 2: Click *"List Files"* 20 | 21 | ![](https://subscribie.co.uk/blog/content/images/size/w1000/2022/11/image-102.png) 22 | 23 | Step 3: Click *"Delete"* to remove the file you would like to delete. 24 | 25 | ![](https://subscribie.co.uk/blog/content/images/size/w1000/2022/11/image-103.png) 26 | 27 | You have now successfully deleted the file. 28 | 29 | ### Watch this Tutorial to Delete Files from your Shop 30 | 31 | [![Watch the video](https://github.com/Subscribie/subscribie/assets/30567984/07fcafe0-d7b1-4470-93b2-16aefc37584d)](https://youtu.be/AHMx0lbSD3Y) -------------------------------------------------------------------------------- /docs/content/en/docs/Tasks/embed-subscribie-into-your-website.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Embed Subscribie in a Website" 3 | date: 2022-11-18 4 | weight: 5 5 | description: > 6 | Want to add subscribie to your site? Follow this easy guide to embed Subscribie into your website. 7 | --- 8 | 9 | ## Steps to Embed Subscribie in a Website 10 | 11 | Step 1: Log into your Dashboard. 12 | 13 | ![](https://subscribie.co.uk/blog/content/images/size/w1000/2022/11/image-64.png) 14 | 15 | Step 2: Go to *Modules* and choose *Get Embed Code* under *iFrame Embed.* 16 | 17 | ![](https://subscribie.co.uk/blog/content/images/size/w1000/2022/11/image-118.png) 18 | 19 | Step 3: Copy the text under *"Copy the embed code into your website".* 20 | 21 | ![](https://subscribie.co.uk/blog/content/images/size/w1000/2022/11/image-119.png) 22 | 23 | Step 4: Paste the copied text to your page. 24 | 25 | > If you would like a simpler option, simply create a link to your subscription plans from your website to Subscribie. To set that up, create an account on Subscribie, and then add a link in your website menu to your subscription plans. That is the easiest least complicated approach. 26 | 27 | ### Video Tutorial to Embed Subscribie in a Website 28 | 29 | [![Watch the video](https://github.com/Subscribie/subscribie/assets/30567984/a5cde524-56f6-481a-ae24-b254cddc9014)](https://youtu.be/jY-2q61VbjI) -------------------------------------------------------------------------------- /docs/content/en/docs/Tasks/enable-donations.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Enable Donations" 3 | date: 2023-03-21 4 | weight: 5 5 | description: > 6 | Need to collect donations? Learn how to enbale donations in your shop. 7 | --- 8 | 9 | ## Steps to Enable Donations 10 | 11 | Step 1: Log into your Shop Dashboard. 12 | ![](https://subscribie.co.uk/p/wp-content/uploads/2023/03/Screenshot-2023-03-21-192142-1024x472.png) 13 | 14 | Step 2: Go to *Donation Settings* under *Shop Settings* at the bottom of the dashboard. 15 | 16 | ![](https://subscribie.co.uk/p/wp-content/uploads/2023/03/Screenshot-2023-03-21-192328-1024x435.png) 17 | 18 | Step 3: Enable Donations and click *Save*. 19 | 20 | ![](https://subscribie.co.uk/p/wp-content/uploads/2023/03/Screenshot-2023-03-21-192419-1024x475.png) 21 | 22 | ### Donations is now enabled in your shop. You can view it at the top of your dashboard in blue. 23 | 24 | ![](https://subscribie.co.uk/p/wp-content/uploads/2023/03/Screenshot-2023-03-21-192647-1024x448.png) 25 | 26 | You can find the Donate option on the right side of your shop's header/banner. 27 | 28 | Need a way to see your donations and filter them? Check out our guide to [viewing and exporting your donation transactions.](https://docs.subscribie.co.uk/docs/tasks/view-and-export-transactions-and-donations/) 29 | 30 | ### Video Tutorial to Enable Donations 31 | 32 | [![Watch the video](https://github.com/Subscribie/subscribie/assets/30567984/cbe68cbd-cacc-46b4-90ce-0c7aa634333d)](https://youtu.be/NaVN0LAysdU) -------------------------------------------------------------------------------- /docs/content/en/docs/Tasks/export-subscribers-from-your-shop.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Export Subscribers from your shop" 3 | date: 2023-04-24 4 | weight: 5 5 | description: > 6 | Need a way export your subscriber's data? Learn how to export Subscribers from your Shop as a CSV file. 7 | --- 8 | 9 | Subscribie allows you to export your subscriber list as a CSV file. 10 | 11 | ## Steps to export Subscribers from your shop 12 | 13 | Step 1: Log into your Shop 14 | 15 | ![](https://subscribie.co.uk/blog/content/images/size/w1000/2023/04/image-26.png) 16 | 17 | Step 2: Click *Export Subscribers* under *My Subscribers.* 18 | 19 | ![](https://subscribie.co.uk/blog/content/images/size/w1000/2023/04/image-24.png) 20 | 21 | Step 3: Review the `csv` export 22 | 23 | The file will contain your subscriber information, in the CSV file format. 24 | 25 | ![](https://subscribie.co.uk/blog/content/images/size/w1000/2023/04/image-25.png) 26 | 27 | ### Video Tutorial to Export Subscriber Data 28 | 29 | [![Watch the video](https://github.com/Subscribie/subscribie/assets/30567984/86c00f22-3add-433c-acab-1cb4e04ad85b)](https://youtu.be/6vSQcQ5nCDc) -------------------------------------------------------------------------------- /docs/content/en/docs/Tasks/filter-transactions.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Filter Transactions" 3 | date: 2022-11-18 4 | weight: 5 5 | description: > 6 | Need to search and filter subscription? Here's a guide on how to filter transactions. 7 | --- 8 | 9 | Subscribie offers the facility to filter transactions, learn how to with these easy steps. 10 | 11 | >This can be done by filtering with the subscriber's name or the plan's title. 12 | 13 | ## Steps to Filter a Transaction 14 | 15 | Step 1: Log into your Shop Dashboard. 16 | 17 | ![](https://subscribie.co.uk/blog/content/images/size/w1000/2022/11/image-64.png) 18 | 19 | Step 2: Click *"View Transactions / Manage Funds"* under *"All transactions / Manage Refunds".* 20 | 21 | ![](https://subscribie.co.uk/blog/content/images/size/w1000/2022/11/image-121.png) 22 | 23 | Step 3: Here, you can search for the *Subscriber Name* or *Plan Title.* 24 | 25 | ![](https://subscribie.co.uk/blog/content/images/size/w1000/2022/11/image-122.png) 26 | 27 | Now you can view the Filtered Transactions. 28 | 29 | ### Video Tutorial to Filter Transactions 30 | 31 | [![Watch the video](https://github.com/Subscribie/subscribie/assets/30567984/935cfe90-2a89-4225-8194-b8e3a3f7007f)](https://youtu.be/c3j2DAoxWDU) -------------------------------------------------------------------------------- /docs/content/en/docs/Tasks/refund-customer-subscriptions.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Refund Customer Subscription Payments" 3 | date: 2023-04-24 4 | weight: 5 5 | description: > 6 | How to refund payments. 7 | --- 8 | 9 | ## Steps to refund payments 10 | 11 | Step 1: In your dashboard, go to *View Transactions / Manage Refunds* under the *All Transactions / Manage Refunds* tab. 12 | 13 | ![](https://subscribie.co.uk/blog/content/images/size/w1000/2023/04/image-9.png) 14 | 15 | Step 2: View the transaction you would like to refund and click *Refund.* 16 | 17 | ![](https://subscribie.co.uk/blog/content/images/size/w1000/2023/04/image-10.png) 18 | 19 | Step 3: You will now be prompted with a box asking if you are sure you want to refund, so choose *Yes.* 20 | 21 | ![](https://subscribie.co.uk/blog/content/images/size/w1000/2023/04/image-11.png) 22 | 23 | You have now successfully initiated your refund, you can rest assured that your customer will receive their refund within 3 to 10 business days. 24 | 25 | >Note: If this is part of an active subscription, future payments will still be taken. If you want to cancel future subscription charges, see [how to pause or cancel a subscription]({{< ref "docs/tasks/pause-a-subscribers-subscription/_index" >}}) 26 | 27 | ### Video Tutorial for Refunding a Subscription 28 | 29 | [![Watch the video](https://github.com/Subscribie/subscribie/assets/30567984/ee4f2ebc-e7ef-4aba-9978-375ff5ff8e4a)](https://youtu.be/jgMdWjfzZSY) -------------------------------------------------------------------------------- /docs/content/en/docs/Tasks/reordering-plans.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Reorder Plans" 3 | date: 2022-11-11 4 | weight: 5 5 | description: > 6 | Learn how to organise your subscription shop by reordering plans. 7 | --- 8 | 9 | ## Steps to Reorder Plans 10 | 11 | Step 1: Log into your Shop Dashboard. 12 | 13 | ![](https://subscribie.co.uk/blog/content/images/size/w1000/2022/11/image.png) 14 | 15 | Step 2: Under the *"Edit/Add Plans"* section, click *"Edit Plans".* 16 | 17 | ![](https://subscribie.co.uk/blog/content/images/size/w1000/2022/11/image-3.png) 18 | 19 | Step 3: Here, select the plan, scroll down to *"Position",* and set the value that changes the position of the plan. 20 | 21 | >*"0 (zero)"* denotes the first position and so on. 22 | 23 | ![](https://subscribie.co.uk/blog/content/images/size/w1000/2022/11/image-1.png) 24 | 25 | Step 4: Click *"save".* 26 | 27 | ![](https://subscribie.co.uk/blog/content/images/size/w1000/2022/11/image-2.png) 28 | 29 | Now you have successfully rearranged your plans in your shop! 30 | 31 | Want to make your subscription shop more organised? Learn how you can [categorise your subscription plans.](https://docs.subscribie.co.uk/docs/tasks/categorise-subscription-plans/) 32 | 33 | ### Watch the Tutorial to Reorder Plans 34 | 35 | [![Watch the video](https://github.com/Subscribie/subscribie/assets/30567984/f44d9e0d-b39c-4b78-b46a-7f4af69061a7)](https://youtu.be/45249uk_t4E) -------------------------------------------------------------------------------- /docs/content/en/docs/Tasks/shop-owners-updating-credit-card-details.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Updating Credit Card details for Shop Owners" 3 | date: 2022-11-11 4 | weight: 5 5 | description: > 6 | How to update your credit card details as a shop owner. 7 | --- 8 | 9 | ## Steps to Update your credit card details 10 | 11 | #Step 1: 12 | * On your Admin dashboard scroll down and click **Users, Passwords & Cards details** 13 | 14 | #Step 2: 15 | * After the dropdown, click **Change My Card details**. It will redirect you to your profile side of subscribie where you will need to enter your credentials. 16 | > Note: If you can't remember your Subscribie credentials, use the [forgotten password](https://subscribie.co.uk/account/login) link on the login page. 17 | 18 | #Step 3: 19 | * After logging in, scroll down and click **update payment method**. 20 | 21 | #Step 4: 22 | * Follow the steps and click **Save**. 23 | 24 | #Step 5: 25 | * After updating your credentials, you can scroll down the dashboard to check the 4 last digit of your new card which will be that it was changed succesfully! 26 | 27 | -------------------------------------------------------------------------------- /docs/content/en/docs/Tasks/update-subscription-card-details.md: -------------------------------------------------------------------------------- 1 | 2 | --- 3 | title: "Update/Change Subscription Card Details" 4 | date: 2023-06-06 5 | weight: 5 6 | description: > 7 | Just changed your card and need to pay for your Subscribie subscription? Follow these steps to Update/Change Subscription Card Details 8 | --- 9 | 10 | ## Steps to Update/Change Subscription Card Details 11 | 12 | Step 1: In your Dashboard, Click on *Users, Passwords & Cards details.* 13 | 14 | ![](https://subscribie.co.uk/blog/content/images/size/w1000/2023/06/image-1.png) 15 | 16 | Step 2: Click *Change my Card details.* 17 | 18 | ![](https://subscribie.co.uk/blog/content/images/size/w1000/2023/06/image-4.png) 19 | 20 | Step 3: Enter your Login Details. 21 | 22 | ![](https://subscribie.co.uk/blog/content/images/2023/06/image-14.png) 23 | 24 | Step 4: Click *Update Payment Method*. 25 | 26 | ![](https://subscribie.co.uk/blog/content/images/size/w1000/2023/06/image-5.png) 27 | 28 | Step 5: Enter your card details and click *Save*. 29 | 30 | ![](https://subscribie.co.uk/blog/content/images/size/w1000/2023/06/image-6.png) 31 | 32 | That's it! You have successfully updated your card details and can continue to use Subscribie. 33 | 34 | ### Watch the Tutorial to Update/Change Subscription Card Details 35 | 36 | [![Watch the video](https://github.com/Subscribie/subscribie/assets/30567984/bb49bd29-6c4a-42d0-87a9-752d13978875)](https://www.youtube.com/watch?v=ZWl5hRhu_xM) -------------------------------------------------------------------------------- /docs/content/en/docs/Tasks/upload-files.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Upload Files to a Shop" 3 | date: 2022-11-17 4 | weight: 5 5 | description: > 6 | Need to upload files for your customers? Learn how to add files to a shop. 7 | --- 8 | 9 | Subscribie allows shop owners to upload simple files like documents, photos and short videos. These can be viewed and downloaded by customers in your shop webiste. To upload file, follow these steps. 10 | 11 | ## Steps to Upload Files to a Shop 12 | 13 | Step 1: Log into your Dashboard. 14 | 15 | ![](https://subscribie.co.uk/blog/content/images/size/w1000/2022/11/image-64.png) 16 | 17 | Step 2: Click *"Upload Files"* 18 | 19 | ![](https://subscribie.co.uk/blog/content/images/size/w1000/2022/11/image-99.png) 20 | 21 | Step 3: Click *"Choose Files"* and upload the files needed and Click *"Save"* 22 | 23 | ![](https://subscribie.co.uk/blog/content/images/size/w1000/2022/11/image-100.png) 24 | 25 | You have now successfully added Files that can only be accessed by subscribers through your shop. 26 | 27 | Need to delete a file? Check out our guide on how to [delete an uploaded file.](https://docs.subscribie.co.uk/docs/tasks/delete-files/) 28 | 29 | ### Video Tutorial to Upload Files 30 | 31 | [![Watch the video](https://github.com/Subscribie/subscribie/assets/30567984/a08471cb-f1ee-4b82-8d58-f8358cc98788)](https://www.youtube.com/watch?v=QzafljOrHV8) -------------------------------------------------------------------------------- /docs/content/en/docs/Tutorials/_index.md: -------------------------------------------------------------------------------- 1 | 2 | --- 3 | title: "Tutorials" 4 | linkTitle: "Tutorials" 5 | weight: 8 6 | date: 2017-01-04 7 | description: > 8 | Find all the tutorials you need to create a subscription to collect payments. 9 | --- 10 | 11 | {{% pageinfo %}} 12 | See also Subscribie blog for [guides & articles on collecting Subscription payments](https://subscribie.co.uk/blog/). 13 | {{% /pageinfo %}} 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /docs/content/en/docs/Tutorials/create-a-subscription.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Create a Subscription" 3 | date: 2022-11-11 4 | weight: 5 5 | description: > 6 | How to Create a subscription from scrach 7 | --- 8 | 9 | ## Steps to Create a Subscription 10 | 11 | Step 1: On the main page of Subscribie.co.uk, click *Get Started* 12 | 13 | ![](https://i.imgur.com/mcejWLl.png) 14 | 15 | Step 2: Fill in your *Business Name, E-mail* and type a *password* then scroll down. 16 | 17 | ![](https://i.imgur.com/qgi8ELb.png) 18 | 19 | Step 3: Provide the necessary information to set up your subscription. 20 | 21 | Here you will have to fill in: 22 | - The *name* you would like to give your subscription (Example: Membership Subscription) 23 | - The *amount of money* for the subscription 24 | - The *interval* between subscription payments, for example, weekly, monthly and yearly. 25 | - A short *description* explaining your subscription. 26 | 27 | Once you have provided the following information, click *Save.* 28 | 29 | ![](https://i.imgur.com/8X3gc36.png) 30 | 31 | Step 4: Once you have clicked *Save*, Subscribie will build your website and redirect you to the shop dashboard. 32 | 33 | ![](https://i.imgur.com/mh6qlyX.png) 34 | 35 | ### Now you have created a Subscription. 36 | 37 | Next, [learn how to activate payment collection to start automating payment collection.](https://docs.subscribie.co.uk/docs/tutorials/link-stripe-to-shop/) -------------------------------------------------------------------------------- /docs/content/en/docs/_index.md: -------------------------------------------------------------------------------- 1 | 2 | --- 3 | title: "Documentation" 4 | linkTitle: "Documentation" 5 | weight: 20 6 | menu: 7 | main: 8 | weight: 20 9 | --- 10 | 11 | {{% pageinfo %}} 12 | This documenation is how to use Subscribie, if you're just starting out [create an account](https://subscribie.co.uk/) to start your shop. 13 | {{% /pageinfo %}} 14 | 15 | Read this documentatino to understand how to use Subscribie to collect subscription payments and automate payments for your business. 16 | 17 | -------------------------------------------------------------------------------- /docs/content/en/featured-background.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Subscribie/subscribie/4ba736e39a1e867186fee4e4ec28ae8b4b1d3a3e/docs/content/en/featured-background.jpg -------------------------------------------------------------------------------- /docs/content/en/search.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Search Results 3 | layout: search 4 | 5 | --- 6 | 7 | -------------------------------------------------------------------------------- /docs/docker-compose.yaml: -------------------------------------------------------------------------------- 1 | version: "3.3" 2 | 3 | services: 4 | 5 | site: 6 | image: docsy/docsy-example 7 | build: 8 | context: . 9 | command: server 10 | ports: 11 | - "1313:1313" 12 | volumes: 13 | - .:/src 14 | -------------------------------------------------------------------------------- /docs/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/google/docsy-example 2 | 3 | go 1.12 4 | 5 | require ( 6 | github.com/FortAwesome/Font-Awesome v0.0.0-20220831210243-d3a7818c253f // indirect 7 | github.com/google/docsy v0.5.1 // indirect 8 | github.com/twbs/bootstrap v4.6.2+incompatible // indirect 9 | ) 10 | -------------------------------------------------------------------------------- /docs/go.sum: -------------------------------------------------------------------------------- 1 | github.com/FortAwesome/Font-Awesome v0.0.0-20220831210243-d3a7818c253f h1:bvkUptSRPZBr3Kxuk+bnWCEmQ5MtEJX5fjezyV0bC3g= 2 | github.com/FortAwesome/Font-Awesome v0.0.0-20220831210243-d3a7818c253f/go.mod h1:IUgezN/MFpCDIlFezw3L8j83oeiIuYoj28Miwr/KUYo= 3 | github.com/google/docsy v0.5.1 h1:D/ZdFKiE29xM/gwPwQzmkyXhcbQGkReRS6aGrF7lnYk= 4 | github.com/google/docsy v0.5.1/go.mod h1:maoUAQU5H/d+FrZIB4xg1EVWAx7RyFMGSDJyWghm31E= 5 | github.com/google/docsy/dependencies v0.5.1/go.mod h1:EDGc2znMbGUw0RW5kWwy2oGgLt0iVXBmoq4UOqstuNE= 6 | github.com/twbs/bootstrap v4.6.2+incompatible h1:TDa+R51BTiy1wEHSYjmqDb8LxNl/zaEjAOpRE9Hwh/o= 7 | github.com/twbs/bootstrap v4.6.2+incompatible/go.mod h1:fZTSrkpSf0/HkL0IIJzvVspTt1r9zuf7XlZau8kpcY0= 8 | -------------------------------------------------------------------------------- /docs/layouts/404.html: -------------------------------------------------------------------------------- 1 | {{ define "main"}} 2 |
3 |
4 |

Not found

5 |

Oops! This page doesn't exist. Try going back to our home page.

6 | 7 |

You can learn how to make a 404 page like this in Custom 404 Pages.

8 |
9 |
10 | {{ end }} 11 | -------------------------------------------------------------------------------- /docs/layouts/sitemap.xml: -------------------------------------------------------------------------------- 1 | {{ printf "" | safeHTML }} 2 | 4 | {{ range .Data.Pages }} 5 | {{- if .Permalink -}} 6 | 7 | https://docs.subscribie.co.uk{{ .Permalink }}{{ if not .Lastmod.IsZero }} 8 | {{ safeHTML ( .Lastmod.Format "2006-01-02T15:04:05-07:00" ) }}{{ end }}{{ with .Sitemap.ChangeFreq }} 9 | {{ . }}{{ end }}{{ if ge .Sitemap.Priority 0.0 }} 10 | {{ .Sitemap.Priority }}{{ end }}{{ if .IsTranslated }}{{ range .Translations }} 11 | {{ end }} 16 | {{ end }} 21 | 22 | {{- end -}} 23 | {{ end }} 24 | 25 | -------------------------------------------------------------------------------- /docs/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "tech-doc-hugo", 3 | "version": "0.0.1", 4 | "description": "Hugo theme for technical documentation.", 5 | "main": "none.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "repository": { 10 | "type": "git", 11 | "url": "git+https://github.com/google/docsy-example.git" 12 | }, 13 | "author": "", 14 | "license": "ISC", 15 | "bugs": { 16 | "url": "https://github.com/google/docsy-example/issues" 17 | }, 18 | "homepage": "https://github.com/google/docsy-example#readme", 19 | "devDependencies": { 20 | "autoprefixer": "^10.4.0", 21 | "postcss": "^8.3.7", 22 | "postcss-cli": "^9.1.0" 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /docs/run-docs.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | hugo serve --port 4444 4 | -------------------------------------------------------------------------------- /docs/smoketest-docs.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -x 4 | echo Checking docs are still live with curl 5 | RET=$(curl -s -o /dev/null -w "%{http_code}" https://docs.subscribie.co.uk) 6 | 7 | echo $RET 8 | 9 | if [ $RET -ne 200 ]; then 10 | echo Could not curl docs url 11 | exit 255 12 | fi 13 | -------------------------------------------------------------------------------- /email-queue/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Subscribie/subscribie/4ba736e39a1e867186fee4e4ec28ae8b4b1d3a3e/email-queue/.gitkeep -------------------------------------------------------------------------------- /emperor.ini: -------------------------------------------------------------------------------- 1 | [uwsgi] 2 | strict-mode = true 3 | protocol = uwsgi 4 | master = true 5 | enable-threads = true 6 | lazy-apps = true 7 | emperor = ./vassals/*/*.ini 8 | 9 | # See https://uwsgi-docs.readthedocs.io/en/latest/Emperor.html#passing-configuration-parameters-to-all-vassals 10 | vassals-include = vassals-inject-config.ini 11 | 12 | # See https://uwsgi-docs.readthedocs.io/en/latest/OnDemandVassals.html 13 | emperor-on-demand-extension = .socket 14 | fastrouter = 127.0.0.1:8001 15 | fastrouter-subscription-server = /tmp/sock2 16 | vacuum = true 17 | 18 | log-format = %(host) - %(addr) - %(user) [%(ltime)] "%(method) %(uri) %(proto)" %(status) %(size) "%(referer)" "%(uagent)" 19 | -------------------------------------------------------------------------------- /entrypoint.sh: -------------------------------------------------------------------------------- 1 | #! /bin/bash 2 | set -euxo pipefail 3 | 4 | export FLASK_APP=subscribie 5 | export FLASK_DEBUG=1 6 | 7 | if [ -a settings.yaml ] 8 | then 9 | echo "settings.yaml exists already so not copying from settings.yaml.example" 10 | else 11 | echo "settings.yaml not found, so copying from settings.yaml.example" 12 | cp settings.yaml.example settings.yaml 13 | if [ ! -d "modules" ]; then 14 | echo creating modules directory because it didn\'t exit 15 | mkdir modules 16 | fi 17 | 18 | # Set DB URI & PATH 19 | sed -i 's#SQLALCHEMY_DATABASE_URI.*#SQLALCHEMY_DATABASE_URI: "sqlite:////usr/src/app/data.db"#g' settings.yaml 20 | sed -i 's#DB_FULL_PATH.*#DB_FULL_PATH: "/usr/src/app/data.db"#g' settings.yaml 21 | 22 | # Set static dir 23 | sed -i 's#TEMPLATE_BASE_DIR.*#TEMPLATE_BASE_DIR: "/usr/src/app/subscribie/subscribie/themes/"#g' settings.yaml 24 | sed -i 's#UPLOADED_IMAGES_DEST.*#UPLOADED_IMAGES_DEST: "/usr/src/app/subscribie/subscribie/static/"#g' settings.yaml 25 | fi 26 | 27 | 28 | flask db upgrade 29 | 30 | flask initdb 31 | 32 | exec uwsgi --http :5000 --workers 1 --threads 2 --py-call-uwsgi-fork-hooks --wsgi-file subscribie.wsgi --touch-chain-reload subscribie.wsgi --chdir /usr/src/app/subscribie/ 33 | 34 | -------------------------------------------------------------------------------- /migrations/README: -------------------------------------------------------------------------------- 1 | Generic single-database configuration. -------------------------------------------------------------------------------- /migrations/alembic.ini: -------------------------------------------------------------------------------- 1 | # A generic, single database configuration. 2 | 3 | [alembic] 4 | # template used to generate migration files 5 | # file_template = %%(rev)s_%%(slug)s 6 | 7 | # set to 'true' to run the environment during 8 | # the 'revision' command, regardless of autogenerate 9 | # revision_environment = false 10 | -------------------------------------------------------------------------------- /migrations/script.py.mako: -------------------------------------------------------------------------------- 1 | """${message} 2 | 3 | Revision ID: ${up_revision} 4 | Revises: ${down_revision | comma,n} 5 | Create Date: ${create_date} 6 | 7 | """ 8 | from alembic import op 9 | import sqlalchemy as sa 10 | ${imports if imports else ""} 11 | 12 | # revision identifiers, used by Alembic. 13 | revision = ${repr(up_revision)} 14 | down_revision = ${repr(down_revision)} 15 | branch_labels = ${repr(branch_labels)} 16 | depends_on = ${repr(depends_on)} 17 | 18 | 19 | def upgrade(): 20 | ${upgrades if upgrades else "pass"} 21 | 22 | 23 | def downgrade(): 24 | ${downgrades if downgrades else "pass"} 25 | -------------------------------------------------------------------------------- /migrations/versions/00477315ded9_add_created_at_column_stripe_invoice_.py: -------------------------------------------------------------------------------- 1 | """add_created_at_column_stripe_invoice_table 2 | 3 | Revision ID: 00477315ded9 4 | Revises: 041d569f7762 5 | Create Date: 2022-04-07 17:49:50.146114 6 | 7 | """ 8 | 9 | from alembic import op 10 | import sqlalchemy as sa 11 | 12 | 13 | # revision identifiers, used by Alembic. 14 | revision = "00477315ded9" 15 | down_revision = "041d569f7762" 16 | branch_labels = None 17 | depends_on = None 18 | 19 | 20 | def upgrade(): 21 | with op.batch_alter_table("stripe_invoice") as batch_op: 22 | batch_op.add_column(sa.Column("created_at", sa.DateTime(), nullable=True)) 23 | 24 | 25 | def downgrade(): 26 | pass 27 | -------------------------------------------------------------------------------- /migrations/versions/041d569f7762_add_column_created_to_stripe_invoices_.py: -------------------------------------------------------------------------------- 1 | """add_column_created_to_stripe_invoices_table 2 | 3 | Revision ID: 041d569f7762 4 | Revises: c57ff5a7436a 5 | Create Date: 2022-04-07 17:33:30.075127 6 | 7 | """ 8 | 9 | from alembic import op 10 | import sqlalchemy as sa 11 | 12 | 13 | # revision identifiers, used by Alembic. 14 | revision = "041d569f7762" 15 | down_revision = "c57ff5a7436a" 16 | branch_labels = None 17 | depends_on = None 18 | 19 | 20 | def upgrade(): 21 | with op.batch_alter_table("stripe_invoice") as batch_op: 22 | batch_op.add_column(sa.Column("created", sa.Integer(), nullable=True)) 23 | 24 | 25 | def downgrade(): 26 | pass 27 | -------------------------------------------------------------------------------- /migrations/versions/063ddc60bef1_association_table_plan_question.py: -------------------------------------------------------------------------------- 1 | """association_table_plan_question 2 | 3 | Revision ID: 063ddc60bef1 4 | Revises: c5bec71f1499 5 | Create Date: 2024-05-09 22:00:42.022150 6 | 7 | """ 8 | 9 | from alembic import op 10 | import sqlalchemy as sa 11 | 12 | 13 | # revision identifiers, used by Alembic. 14 | revision = "063ddc60bef1" 15 | down_revision = "c5bec71f1499" 16 | branch_labels = None 17 | depends_on = None 18 | 19 | 20 | def upgrade(): 21 | op.create_table( 22 | "plan_question_associations", 23 | sa.Column("question_id", sa.Integer(), nullable=True), 24 | sa.Column("plan_id", sa.Integer(), nullable=True), 25 | sa.ForeignKeyConstraint( 26 | ["plan_id"], 27 | ["plan.id"], 28 | ), 29 | sa.ForeignKeyConstraint( 30 | ["question_id"], 31 | ["question.id"], 32 | ), 33 | ) 34 | 35 | 36 | def downgrade(): 37 | pass 38 | -------------------------------------------------------------------------------- /migrations/versions/07cc236f0a6d_remove_stripe_subscription_id_from_.py: -------------------------------------------------------------------------------- 1 | """remove stripe_subscription_id from Subscription model 2 | 3 | Revision ID: 07cc236f0a6d 4 | Revises: f3579efd3331 5 | Create Date: 2020-12-04 14:59:11.346386 6 | 7 | """ 8 | 9 | from alembic import op 10 | 11 | 12 | # revision identifiers, used by Alembic. 13 | revision = "07cc236f0a6d" 14 | down_revision = "f3579efd3331" 15 | branch_labels = None 16 | depends_on = None 17 | 18 | 19 | def upgrade(): 20 | with op.batch_alter_table("subscription") as batch_op: 21 | batch_op.drop_column("stripe_subscription_id") 22 | 23 | 24 | def downgrade(): 25 | pass 26 | -------------------------------------------------------------------------------- /migrations/versions/084669093d74_add_stripe_cancel_at_to_subscription_.py: -------------------------------------------------------------------------------- 1 | """add stripe_cancel_at to Subscription model 2 | 3 | Revision ID: 084669093d74 4 | Revises: b28487bfca0f 5 | Create Date: 2021-05-04 22:55:42.753614 6 | 7 | """ 8 | 9 | from alembic import op 10 | import sqlalchemy as sa 11 | 12 | 13 | # revision identifiers, used by Alembic. 14 | revision = "084669093d74" 15 | down_revision = "b28487bfca0f" 16 | branch_labels = None 17 | depends_on = None 18 | 19 | 20 | def upgrade(): 21 | with op.batch_alter_table("subscription") as batch_op: 22 | batch_op.add_column(sa.Column("stripe_cancel_at", sa.String(), nullable=True)) 23 | 24 | 25 | def downgrade(): 26 | pass 27 | -------------------------------------------------------------------------------- /migrations/versions/08dcbc5f9c6d_merge_abfb5c2f77e6_spamemaildomain_and_.py: -------------------------------------------------------------------------------- 1 | """Merge abfb5c2f77e6 SpamEmailDomain and d8c120e8212e add proration_behavior stripe_proration_behavior 2 | 3 | Revision ID: 08dcbc5f9c6d 4 | Revises: abfb5c2f77e6, d8c120e8212e 5 | Create Date: 2025-01-20 21:23:49.963312 6 | 7 | """ 8 | 9 | from alembic import op 10 | import sqlalchemy as sa 11 | 12 | 13 | # revision identifiers, used by Alembic. 14 | revision = "08dcbc5f9c6d" 15 | down_revision = ("abfb5c2f77e6", "d8c120e8212e") 16 | branch_labels = None 17 | depends_on = None 18 | 19 | 20 | def upgrade(): 21 | pass 22 | 23 | 24 | def downgrade(): 25 | pass 26 | -------------------------------------------------------------------------------- /migrations/versions/1653ed33cbd4_add_subscribie_checkout_session_id_to_.py: -------------------------------------------------------------------------------- 1 | """add subscribie_checkout_session_id to Subscription 2 | 3 | Revision ID: 1653ed33cbd4 4 | Revises: ee8e62e05b40 5 | Create Date: 2020-11-11 12:08:45.878277 6 | 7 | """ 8 | 9 | from alembic import op 10 | import sqlalchemy as sa 11 | 12 | 13 | # revision identifiers, used by Alembic. 14 | revision = "1653ed33cbd4" 15 | down_revision = "ee8e62e05b40" 16 | branch_labels = None 17 | depends_on = None 18 | 19 | 20 | def upgrade(): 21 | with op.batch_alter_table("subscription") as batch_op: 22 | batch_op.add_column( 23 | sa.Column("subscribie_checkout_session_id", sa.String(), nullable=True) 24 | ) 25 | 26 | 27 | def downgrade(): 28 | pass 29 | -------------------------------------------------------------------------------- /migrations/versions/1d4b6d333c16_.py: -------------------------------------------------------------------------------- 1 | """empty message 2 | 3 | Revision ID: 1d4b6d333c16 4 | Revises: c7a493cd99d4 5 | Create Date: 2024-05-18 20:05:40.299194 6 | 7 | """ 8 | 9 | # revision identifiers, used by Alembic. 10 | revision = "1d4b6d333c16" 11 | down_revision = "c7a493cd99d4" 12 | branch_labels = None 13 | depends_on = None 14 | 15 | 16 | def upgrade(): 17 | pass 18 | 19 | 20 | def downgrade(): 21 | pass 22 | -------------------------------------------------------------------------------- /migrations/versions/207556b3039b_add_custom_thank_you_url_column.py: -------------------------------------------------------------------------------- 1 | """add custom thank you url column 2 | 3 | Revision ID: 207556b3039b 4 | Revises: 7640c2a9be5b 5 | Create Date: 2023-09-01 19:35:12.241628 6 | 7 | """ 8 | 9 | from alembic import op 10 | import sqlalchemy as sa 11 | 12 | 13 | # revision identifiers, used by Alembic. 14 | revision = "207556b3039b" 15 | down_revision = "7640c2a9be5b" 16 | branch_labels = None 17 | depends_on = None 18 | 19 | 20 | def upgrade(): 21 | op.add_column( 22 | "setting", sa.Column("custom_thank_you_url", sa.String(), nullable=True) 23 | ) 24 | 25 | 26 | def downgrade(): 27 | pass 28 | -------------------------------------------------------------------------------- /migrations/versions/21b64f9d73dd_add_trial_period_days_to_plan_model.py: -------------------------------------------------------------------------------- 1 | """add trial_period_days to Plan model 2 | 3 | Revision ID: 21b64f9d73dd 4 | Revises: d04243b7bd47 5 | Create Date: 2021-03-24 22:54:05.568960 6 | 7 | """ 8 | 9 | from alembic import op 10 | import sqlalchemy as sa 11 | 12 | 13 | # revision identifiers, used by Alembic. 14 | revision = "21b64f9d73dd" 15 | down_revision = "d04243b7bd47" 16 | branch_labels = None 17 | depends_on = None 18 | 19 | 20 | def upgrade(): 21 | with op.batch_alter_table("plan") as batch_op: 22 | batch_op.add_column(sa.Column("trial_period_days", sa.Integer(), default=0)) 23 | 24 | 25 | def downgrade(): 26 | pass 27 | -------------------------------------------------------------------------------- /migrations/versions/2378e3286d5b_correct_store_cancel_at_at_int.py: -------------------------------------------------------------------------------- 1 | """correct store cancel_at at int 2 | 3 | Revision ID: 2378e3286d5b 4 | Revises: b3c13acc1013 5 | Create Date: 2021-05-09 21:28:01.250318 6 | 7 | """ 8 | 9 | from alembic import op 10 | import sqlalchemy as sa 11 | 12 | 13 | # revision identifiers, used by Alembic. 14 | revision = "2378e3286d5b" 15 | down_revision = "b3c13acc1013" 16 | branch_labels = None 17 | depends_on = None 18 | 19 | 20 | def upgrade(): 21 | with op.batch_alter_table("plan") as batch_op: 22 | batch_op.alter_column( 23 | "cancel_at", 24 | type_=sa.Integer(), 25 | nullable=True, 26 | existing_type=sa.Boolean(), 27 | default=False, 28 | ) 29 | 30 | with op.batch_alter_table("subscription") as batch_op: 31 | batch_op.alter_column( 32 | "stripe_cancel_at", 33 | type_=sa.Integer(), 34 | nullable=True, 35 | default=False, 36 | existing_type=sa.Boolean(), 37 | ) 38 | 39 | 40 | def downgrade(): 41 | pass 42 | -------------------------------------------------------------------------------- /migrations/versions/262c26af9630_add_has_min_sell_price_has_min_interval_.py: -------------------------------------------------------------------------------- 1 | """add has_min_sell_price has_min_interval_amount 2 | 3 | Revision ID: 262c26af9630 4 | Revises: 938b171f97ec 5 | Create Date: 2022-12-23 14:50:18.143177 6 | 7 | """ 8 | 9 | from alembic import op 10 | import sqlalchemy as sa 11 | 12 | 13 | # revision identifiers, used by Alembic. 14 | revision = "262c26af9630" 15 | down_revision = "938b171f97ec" 16 | branch_labels = None 17 | depends_on = None 18 | 19 | 20 | def upgrade(): 21 | with op.batch_alter_table("price_list_rule") as batch_op: 22 | batch_op.add_column( 23 | sa.Column("has_min_sell_price", sa.Boolean(), nullable=True) 24 | ) 25 | 26 | with op.batch_alter_table("price_list_rule") as batch_op: 27 | batch_op.add_column( 28 | sa.Column("has_min_interval_amount", sa.Boolean(), nullable=True) 29 | ) 30 | 31 | 32 | def downgrade(): 33 | pass 34 | -------------------------------------------------------------------------------- /migrations/versions/2c7e021d9a69_remove_stripe_publishable_key_stripe_.py: -------------------------------------------------------------------------------- 1 | """remove stripe_publishable_key & stripe_secret_key from model 2 | 3 | Revision ID: 2c7e021d9a69 4 | Revises: f0e91df9fbf1 5 | Create Date: 2020-11-02 11:21:21.027943 6 | 7 | """ 8 | 9 | from alembic import op 10 | 11 | 12 | # revision identifiers, used by Alembic. 13 | revision = "2c7e021d9a69" 14 | down_revision = "f0e91df9fbf1" 15 | branch_labels = None 16 | depends_on = None 17 | 18 | 19 | def upgrade(): 20 | with op.batch_alter_table("payment_provider") as batch_op: 21 | batch_op.drop_column("stripe_publishable_key") 22 | batch_op.drop_column("stripe_secret_key") 23 | 24 | 25 | def downgrade(): 26 | pass 27 | -------------------------------------------------------------------------------- /migrations/versions/2f3f0b5d2bde_add_archived_to_person_class.py: -------------------------------------------------------------------------------- 1 | """add archived to Person class 2 | 3 | Revision ID: 2f3f0b5d2bde 4 | Revises: 500f2d55c5d3 5 | Create Date: 2021-02-28 23:13:51.486171 6 | 7 | """ 8 | 9 | from alembic import op 10 | import sqlalchemy as sa 11 | 12 | 13 | # revision identifiers, used by Alembic. 14 | revision = "2f3f0b5d2bde" 15 | down_revision = "500f2d55c5d3" 16 | branch_labels = None 17 | depends_on = None 18 | 19 | 20 | def upgrade(): 21 | with op.batch_alter_table("person") as batch_op: 22 | batch_op.add_column( 23 | sa.Column("archived", sa.Boolean(), nullable=True, default=0) 24 | ) 25 | 26 | 27 | def downgrade(): 28 | pass 29 | -------------------------------------------------------------------------------- /migrations/versions/3447b58b5c69_add_is_longform_question_to_question.py: -------------------------------------------------------------------------------- 1 | """add is_longform_question to question 2 | 3 | Revision ID: 3447b58b5c69 4 | Revises: da154873f3ab 5 | Create Date: 2024-06-17 21:31:27.252460 6 | 7 | """ 8 | 9 | from alembic import op 10 | import sqlalchemy as sa 11 | 12 | 13 | # revision identifiers, used by Alembic. 14 | revision = "3447b58b5c69" 15 | down_revision = "da154873f3ab" 16 | branch_labels = None 17 | depends_on = None 18 | 19 | 20 | def upgrade(): 21 | 22 | with op.batch_alter_table("question", schema=None) as batch_op: 23 | batch_op.add_column( 24 | sa.Column( 25 | "is_longform_question", sa.Boolean(), nullable=True, default=False 26 | ) 27 | ) 28 | 29 | 30 | def downgrade(): 31 | pass 32 | -------------------------------------------------------------------------------- /migrations/versions/3a54f4b1187d_add_order_to_association_table_plan_.py: -------------------------------------------------------------------------------- 1 | """add order to association_table_plan_question 2 | 3 | Revision ID: 3a54f4b1187d 4 | Revises: 1d4b6d333c16 5 | Create Date: 2024-05-19 18:13:11.397272 6 | 7 | """ 8 | 9 | from alembic import op 10 | import sqlalchemy as sa 11 | 12 | 13 | # revision identifiers, used by Alembic. 14 | revision = "3a54f4b1187d" 15 | down_revision = "1d4b6d333c16" 16 | branch_labels = None 17 | depends_on = None 18 | 19 | 20 | def upgrade(): 21 | with op.batch_alter_table("plan_question_associations", schema=None) as batch_op: 22 | batch_op.add_column(sa.Column("order", sa.Integer(), nullable=True)) 23 | 24 | 25 | def downgrade(): 26 | pass 27 | -------------------------------------------------------------------------------- /migrations/versions/3a8f3089d09d_create_upcoming_invoice_table.py: -------------------------------------------------------------------------------- 1 | """create upcoming invoice table 2 | 3 | Revision ID: 3a8f3089d09d 4 | Revises: c48dccfb0df5 5 | Create Date: 2021-05-31 21:24:34.681376 6 | 7 | """ 8 | 9 | from alembic import op 10 | import sqlalchemy as sa 11 | 12 | 13 | # revision identifiers, used by Alembic. 14 | revision = "3a8f3089d09d" 15 | down_revision = "c48dccfb0df5" 16 | branch_labels = None 17 | depends_on = None 18 | 19 | 20 | def upgrade(): 21 | op.create_table( 22 | "upcoming_invoice", 23 | sa.Column("id", sa.Integer(), nullable=False), 24 | sa.Column("created_at", sa.DateTime(), nullable=True), 25 | sa.Column("stripe_subscription_id", sa.String(), nullable=True), 26 | sa.Column("stripe_invoice_status", sa.String(), nullable=True), 27 | sa.Column("stripe_amount_due", sa.String(), nullable=True), 28 | sa.Column("stripe_amount_paid", sa.String(), nullable=True), 29 | sa.Column("stripe_currency", sa.String(), nullable=True), 30 | sa.Column("stripe_next_payment_attempt", sa.String(), nullable=True), 31 | sa.Column("subscription_uuid", sa.Integer(), nullable=True), 32 | sa.ForeignKeyConstraint( 33 | ["subscription_uuid"], 34 | ["subscription.uuid"], 35 | ), 36 | sa.PrimaryKeyConstraint("id"), 37 | ) 38 | 39 | 40 | def downgrade(): 41 | pass 42 | -------------------------------------------------------------------------------- /migrations/versions/3abcbb0428ef_add_stripe_connect_account_id_to_.py: -------------------------------------------------------------------------------- 1 | """add stripe_connect_account_id to PaymentProvider model 2 | 3 | Revision ID: 3abcbb0428ef 4 | Revises: 790aae5a7013 5 | Create Date: 2020-09-23 17:17:30.127947 6 | 7 | """ 8 | 9 | from alembic import op 10 | import sqlalchemy as sa 11 | 12 | 13 | # revision identifiers, used by Alembic. 14 | revision = "3abcbb0428ef" 15 | down_revision = "790aae5a7013" 16 | branch_labels = None 17 | depends_on = None 18 | 19 | 20 | def upgrade(): 21 | with op.batch_alter_table("payment_provider") as batch_op: 22 | batch_op.add_column( 23 | sa.Column("stripe_connect_account_id", sa.String(), nullable=True) 24 | ) 25 | 26 | 27 | def downgrade(): 28 | pass 29 | -------------------------------------------------------------------------------- /migrations/versions/429b32b9ad20_add_plan_documents_association.py: -------------------------------------------------------------------------------- 1 | """add plan documents association 2 | 3 | Revision ID: 429b32b9ad20 4 | Revises: fc7ac6f06521 5 | Create Date: 2022-11-17 01:07:18.115335 6 | 7 | """ 8 | 9 | from alembic import op 10 | import sqlalchemy as sa 11 | 12 | 13 | # revision identifiers, used by Alembic. 14 | revision = "429b32b9ad20" 15 | down_revision = "fc7ac6f06521" 16 | branch_labels = None 17 | depends_on = None 18 | 19 | 20 | def upgrade(): 21 | """ 22 | Ability to link plan->documents 23 | and document->plans 24 | Many to many relationship. 25 | """ 26 | op.create_table( 27 | "plan_document_associations", 28 | sa.Column("plan_uuid", sa.Integer(), nullable=False), 29 | sa.Column("document_uuid", sa.Integer(), nullable=False), 30 | sa.ForeignKeyConstraint( 31 | ["document_uuid"], 32 | ["document.uuid"], 33 | ), 34 | sa.ForeignKeyConstraint( 35 | ["plan_uuid"], 36 | ["plan.uuid"], 37 | ), 38 | ) 39 | 40 | 41 | def downgrade(): 42 | pass 43 | -------------------------------------------------------------------------------- /migrations/versions/4694133a683a_merge_5d8_default_currency_and_7fba_add_.py: -------------------------------------------------------------------------------- 1 | """Merge 5d8 default_currency and 7fba add api_key_secret_live and test 2 | 3 | Revision ID: 4694133a683a 4 | Revises: 5d8da4e0a709, 7fba2877d034 5 | Create Date: 2022-03-18 19:57:24.832565 6 | 7 | """ 8 | 9 | # revision identifiers, used by Alembic. 10 | revision = "4694133a683a" 11 | down_revision = ("5d8da4e0a709", "7fba2877d034") 12 | branch_labels = None 13 | depends_on = None 14 | 15 | 16 | def upgrade(): 17 | pass 18 | 19 | 20 | def downgrade(): 21 | pass 22 | -------------------------------------------------------------------------------- /migrations/versions/48074e6225c6_add_subscription_stripe_ended_at.py: -------------------------------------------------------------------------------- 1 | """add subscription stripe_ended_at 2 | 3 | Revision ID: 48074e6225c6 4 | Revises: 207556b3039b 5 | Create Date: 2024-02-11 17:21:19.287478 6 | 7 | """ 8 | 9 | from alembic import op 10 | import sqlalchemy as sa 11 | 12 | 13 | # revision identifiers, used by Alembic. 14 | revision = "48074e6225c6" 15 | down_revision = "207556b3039b" 16 | branch_labels = None 17 | depends_on = None 18 | 19 | 20 | def upgrade(): 21 | with op.batch_alter_table("subscription", schema=None) as batch_op: 22 | batch_op.add_column(sa.Column("stripe_ended_at", sa.Integer(), nullable=True)) 23 | 24 | 25 | def downgrade(): 26 | pass 27 | -------------------------------------------------------------------------------- /migrations/versions/500f2d55c5d3_add_logintoken_model.py: -------------------------------------------------------------------------------- 1 | """add LoginToken model 2 | 3 | Revision ID: 500f2d55c5d3 4 | Revises: fd28aefcdb76 5 | Create Date: 2021-02-13 00:04:37.827539 6 | 7 | """ 8 | 9 | from alembic import op 10 | import sqlalchemy as sa 11 | 12 | 13 | # revision identifiers, used by Alembic. 14 | revision = "500f2d55c5d3" 15 | down_revision = "fd28aefcdb76" 16 | branch_labels = None 17 | depends_on = None 18 | 19 | 20 | def upgrade(): 21 | # ### commands auto generated by Alembic - please adjust! ### 22 | op.create_table( 23 | "login_token", 24 | sa.Column("user_uuid", sa.String(), nullable=False), 25 | sa.Column("login_token", sa.String(), nullable=True), 26 | sa.PrimaryKeyConstraint("user_uuid"), 27 | ) 28 | # ### end Alembic commands ### 29 | 30 | 31 | def downgrade(): 32 | # ### commands auto generated by Alembic - please adjust! ### 33 | op.drop_table("login_token") 34 | # ### end Alembic commands ### 35 | -------------------------------------------------------------------------------- /migrations/versions/5259c05704c4_merge_has_min_sell_price_has_min_.py: -------------------------------------------------------------------------------- 1 | """Merge has_min_sell_price has_min_interval_amount with is_donation 2 | 3 | Revision ID: 5259c05704c4 4 | Revises: 262c26af9630, 94790e701430 5 | Create Date: 2023-05-15 13:51:56.186900 6 | 7 | """ 8 | 9 | # revision identifiers, used by Alembic. 10 | revision = "5259c05704c4" 11 | down_revision = ("262c26af9630", "94790e701430") 12 | branch_labels = None 13 | depends_on = None 14 | 15 | 16 | def upgrade(): 17 | pass 18 | 19 | 20 | def downgrade(): 21 | pass 22 | -------------------------------------------------------------------------------- /migrations/versions/53840eddbb0f_add_taxrate_model.py: -------------------------------------------------------------------------------- 1 | """add TaxRate model 2 | 3 | Revision ID: 53840eddbb0f 4 | Revises: 2f3f0b5d2bde 5 | Create Date: 2021-03-06 17:26:15.092902 6 | 7 | """ 8 | 9 | from alembic import op 10 | import sqlalchemy as sa 11 | 12 | 13 | # revision identifiers, used by Alembic. 14 | revision = "53840eddbb0f" 15 | down_revision = "2f3f0b5d2bde" 16 | branch_labels = None 17 | depends_on = None 18 | 19 | 20 | def upgrade(): 21 | op.create_table( 22 | "tax_rate", 23 | sa.Column("id", sa.Integer(), nullable=False), 24 | sa.Column("stripe_tax_rate_id", sa.String(), nullable=True), 25 | sa.Column("created_at", sa.DateTime(), nullable=True), 26 | sa.PrimaryKeyConstraint("id"), 27 | ) 28 | 29 | 30 | def downgrade(): 31 | pass 32 | -------------------------------------------------------------------------------- /migrations/versions/54495b8316a1_add_currency_to_transactions_table.py: -------------------------------------------------------------------------------- 1 | """add currency to Transactions table 2 | 3 | Revision ID: 54495b8316a1 4 | Revises: 98bd81ff72f9 5 | Create Date: 2022-05-30 01:22:09.158426 6 | 7 | """ 8 | 9 | from alembic import op 10 | import sqlalchemy as sa 11 | 12 | 13 | # revision identifiers, used by Alembic. 14 | revision = "54495b8316a1" 15 | down_revision = "98bd81ff72f9" 16 | branch_labels = None 17 | depends_on = None 18 | 19 | 20 | def upgrade(): 21 | with op.batch_alter_table("transactions") as batch_op: 22 | batch_op.add_column(sa.Column("currency", sa.String(), nullable=True)) 23 | 24 | 25 | def downgrade(): 26 | pass 27 | -------------------------------------------------------------------------------- /migrations/versions/56e852d799d1_add_stripe_webhook_test_columns.py: -------------------------------------------------------------------------------- 1 | """add stripe webhook test columns 2 | 3 | Revision ID: 56e852d799d1 4 | Revises: c5d444ee3ccd 5 | Create Date: 2020-11-02 11:54:29.263880 6 | 7 | """ 8 | 9 | from alembic import op 10 | import sqlalchemy as sa 11 | 12 | 13 | # revision identifiers, used by Alembic. 14 | revision = "56e852d799d1" 15 | down_revision = "c5d444ee3ccd" 16 | branch_labels = None 17 | depends_on = None 18 | 19 | 20 | def upgrade(): 21 | with op.batch_alter_table("payment_provider") as batch_op: 22 | batch_op.add_column( 23 | sa.Column("stripe_test_connect_account_id", sa.String(), nullable=True) 24 | ) 25 | batch_op.add_column( 26 | sa.Column("stripe_test_webhook_endpoint_id", sa.String(), nullable=True) 27 | ) 28 | batch_op.add_column( 29 | sa.Column("stripe_test_webhook_endpoint_secret", sa.String(), nullable=True) 30 | ) 31 | 32 | 33 | def downgrade(): 34 | pass 35 | -------------------------------------------------------------------------------- /migrations/versions/57b068821280_add_primary_plan_question_associations.py: -------------------------------------------------------------------------------- 1 | """add primary plan_question_associations 2 | 3 | Revision ID: 57b068821280 4 | Revises: 3a54f4b1187d 5 | Create Date: 2024-05-19 19:58:41.527688 6 | 7 | """ 8 | 9 | from alembic import op 10 | import sqlalchemy as sa 11 | 12 | 13 | # revision identifiers, used by Alembic. 14 | revision = "57b068821280" 15 | down_revision = "3a54f4b1187d" 16 | branch_labels = None 17 | depends_on = None 18 | 19 | 20 | def upgrade(): 21 | with op.batch_alter_table("plan_question_associations", schema=None) as batch_op: 22 | batch_op.alter_column("question_id", existing_type=sa.INTEGER(), nullable=False) 23 | batch_op.alter_column("plan_id", existing_type=sa.INTEGER(), nullable=False) 24 | 25 | 26 | def downgrade(): 27 | pass 28 | -------------------------------------------------------------------------------- /migrations/versions/5b308deca3d3_add_interval_unit_interval_amount_to_.py: -------------------------------------------------------------------------------- 1 | """add interval_unit interval_amount to subscription 2 | 3 | Revision ID: 5b308deca3d3 4 | Revises: 6d9febd1346e 5 | Create Date: 2022-07-25 22:27:45.930134 6 | 7 | """ 8 | 9 | from alembic import op 10 | import sqlalchemy as sa 11 | 12 | 13 | # revision identifiers, used by Alembic. 14 | revision = "5b308deca3d3" 15 | down_revision = "6d9febd1346e" 16 | branch_labels = None 17 | depends_on = None 18 | 19 | 20 | def upgrade(): 21 | with op.batch_alter_table("subscription") as batch_op: 22 | batch_op.add_column(sa.Column("interval_unit", sa.String(), nullable=True)) 23 | batch_op.add_column(sa.Column("interval_amount", sa.Integer(), nullable=True)) 24 | batch_op.add_column(sa.Column("sell_price", sa.Integer(), nullable=True)) 25 | 26 | 27 | def downgrade(): 28 | pass 29 | -------------------------------------------------------------------------------- /migrations/versions/5d8da4e0a709_add_default_currency_to_setting.py: -------------------------------------------------------------------------------- 1 | """add default_currency to setting 2 | 3 | Revision ID: 5d8da4e0a709 4 | Revises: 96430096c2c7 5 | Create Date: 2022-01-09 23:51:16.207317 6 | 7 | """ 8 | 9 | from alembic import op 10 | import sqlalchemy as sa 11 | 12 | 13 | # revision identifiers, used by Alembic. 14 | revision = "5d8da4e0a709" 15 | down_revision = "96430096c2c7" 16 | branch_labels = None 17 | depends_on = None 18 | 19 | 20 | def upgrade(): 21 | with op.batch_alter_table("setting") as batch_op: 22 | batch_op.add_column(sa.Column("default_currency", sa.String(), nullable=True)) 23 | 24 | 25 | def downgrade(): 26 | pass 27 | -------------------------------------------------------------------------------- /migrations/versions/6738e7241978_add_requires_discount_code_to_.py: -------------------------------------------------------------------------------- 1 | """add requires_discount_code to PriceListRule 2 | 3 | Revision ID: 6738e7241978 4 | Revises: e9e1f148655e 5 | Create Date: 2022-06-29 19:23:53.498096 6 | 7 | """ 8 | 9 | from alembic import op 10 | import sqlalchemy as sa 11 | 12 | 13 | # revision identifiers, used by Alembic. 14 | revision = "6738e7241978" 15 | down_revision = "e9e1f148655e" 16 | branch_labels = None 17 | depends_on = None 18 | 19 | 20 | def upgrade(): 21 | with op.batch_alter_table("price_list_rule") as batch_op: 22 | batch_op.add_column( 23 | sa.Column("requires_discount_code", sa.Boolean(), default=False), 24 | ) 25 | 26 | 27 | def downgrade(): 28 | pass 29 | -------------------------------------------------------------------------------- /migrations/versions/686d588c3c29_remove_stripe_test_webhooksecret_and_id.py: -------------------------------------------------------------------------------- 1 | """remove stripe test webhooksecret and id 2 | 3 | Revision ID: 686d588c3c29 4 | Revises: 56e852d799d1 5 | Create Date: 2020-11-02 15:22:00.449292 6 | 7 | """ 8 | 9 | from alembic import op 10 | 11 | 12 | # revision identifiers, used by Alembic. 13 | revision = "686d588c3c29" 14 | down_revision = "56e852d799d1" 15 | branch_labels = None 16 | depends_on = None 17 | 18 | 19 | def upgrade(): 20 | with op.batch_alter_table("payment_provider") as batch_op: 21 | batch_op.drop_column("stripe_test_webhook_endpoint_id") 22 | batch_op.drop_column("stripe_test_webhook_endpoint_secret") 23 | 24 | 25 | def downgrade(): 26 | pass 27 | -------------------------------------------------------------------------------- /migrations/versions/6ae2db9a982b_add_pricelist_model.py: -------------------------------------------------------------------------------- 1 | """add PriceList model 2 | 3 | Revision ID: 6ae2db9a982b 4 | Revises: 54495b8316a1 5 | Create Date: 2022-06-07 22:00:26.081464 6 | 7 | """ 8 | 9 | from alembic import op 10 | import sqlalchemy as sa 11 | 12 | 13 | # revision identifiers, used by Alembic. 14 | revision = "6ae2db9a982b" 15 | down_revision = "54495b8316a1" 16 | branch_labels = None 17 | depends_on = None 18 | 19 | 20 | def upgrade(): 21 | op.create_table( 22 | "price_list", 23 | sa.Column("id", sa.Integer(), nullable=False), 24 | sa.Column("created_at", sa.DateTime(), nullable=True), 25 | sa.Column("uuid", sa.String(), nullable=True), 26 | sa.Column("name", sa.String(), nullable=True), 27 | sa.Column("start_date", sa.DateTime(), nullable=True), 28 | sa.Column("expire_date", sa.DateTime(), nullable=True), 29 | sa.Column("currency", sa.String(), nullable=False), 30 | sa.PrimaryKeyConstraint("id"), 31 | ) 32 | 33 | 34 | def downgrade(): 35 | pass 36 | -------------------------------------------------------------------------------- /migrations/versions/6cc0e87e8836_add_bg_primary_to_modulestyle_model.py: -------------------------------------------------------------------------------- 1 | """add bg-primary to ModuleStyle model 2 | 3 | Revision ID: 6cc0e87e8836 4 | Revises: 8d9ada7a21cd 5 | Create Date: 2021-01-10 16:53:43.057712 6 | 7 | """ 8 | 9 | from alembic import op 10 | import sqlalchemy as sa 11 | 12 | 13 | # revision identifiers, used by Alembic. 14 | revision = "6cc0e87e8836" 15 | down_revision = "8d9ada7a21cd" 16 | branch_labels = None 17 | depends_on = None 18 | 19 | 20 | def upgrade(): 21 | with op.batch_alter_table("module_style") as batch_op: 22 | batch_op.add_column(sa.Column("bg_primary", sa.String(), nullable=True)) 23 | 24 | 25 | def downgrade(): 26 | pass 27 | -------------------------------------------------------------------------------- /migrations/versions/6d9febd1346e_add_currency_to_subscription_table.py: -------------------------------------------------------------------------------- 1 | """add currency to Subscription table 2 | 3 | Revision ID: 6d9febd1346e 4 | Revises: 6738e7241978 5 | Create Date: 2022-07-25 22:01:11.062099 6 | 7 | """ 8 | 9 | from alembic import op 10 | import sqlalchemy as sa 11 | 12 | 13 | # revision identifiers, used by Alembic. 14 | revision = "6d9febd1346e" 15 | down_revision = "6738e7241978" 16 | branch_labels = None 17 | depends_on = None 18 | 19 | 20 | def upgrade(): 21 | with op.batch_alter_table("subscription") as batch_op: 22 | batch_op.add_column(sa.Column("currency", sa.String(), default="USD")) 23 | 24 | 25 | def downgrade(): 26 | pass 27 | -------------------------------------------------------------------------------- /migrations/versions/746b4765a957_so_that_categories_may_be_ordered.py: -------------------------------------------------------------------------------- 1 | """so that categories may be ordered 2 | 3 | Revision ID: 746b4765a957 4 | Revises: b8e926d239f9 5 | Create Date: 2021-03-21 15:21:16.472897 6 | 7 | """ 8 | 9 | from alembic import op 10 | import sqlalchemy as sa 11 | 12 | 13 | # revision identifiers, used by Alembic. 14 | revision = "746b4765a957" 15 | down_revision = "b8e926d239f9" 16 | branch_labels = None 17 | depends_on = None 18 | 19 | 20 | def upgrade(): 21 | with op.batch_alter_table("category") as batch_op: 22 | batch_op.add_column(sa.Column("position", sa.Integer(), default=0)) 23 | 24 | 25 | def downgrade(): 26 | pass 27 | -------------------------------------------------------------------------------- /migrations/versions/75a87d5ab587_add_back_stripe_subscription_id_to_.py: -------------------------------------------------------------------------------- 1 | """add back stripe_subscription_id to Subscription model 2 | 3 | Revision ID: 75a87d5ab587 4 | Revises: 07cc236f0a6d 5 | Create Date: 2020-12-04 18:07:10.195939 6 | 7 | """ 8 | 9 | from alembic import op 10 | import sqlalchemy as sa 11 | 12 | 13 | # revision identifiers, used by Alembic. 14 | revision = "75a87d5ab587" 15 | down_revision = "07cc236f0a6d" 16 | branch_labels = None 17 | depends_on = None 18 | 19 | 20 | def upgrade(): 21 | with op.batch_alter_table("subscription") as batch_op: 22 | batch_op.add_column( 23 | sa.Column("stripe_subscription_id", sa.String(), nullable=True) 24 | ) 25 | 26 | 27 | def downgrade(): 28 | pass 29 | -------------------------------------------------------------------------------- /migrations/versions/75dffc3851d8_addassociation_table_price_list_to_rule.py: -------------------------------------------------------------------------------- 1 | """addassociation_table_price_list_to_rule 2 | 3 | Revision ID: 75dffc3851d8 4 | Revises: 4e7e3ee8972d 5 | Create Date: 2022-06-19 17:47:37.281829 6 | 7 | """ 8 | 9 | from alembic import op 10 | import sqlalchemy as sa 11 | 12 | 13 | # revision identifiers, used by Alembic. 14 | revision = "75dffc3851d8" 15 | down_revision = "4e7e3ee8972d" 16 | branch_labels = None 17 | depends_on = None 18 | 19 | 20 | def upgrade(): 21 | op.create_table( 22 | "price_list_rules_associations", 23 | sa.Column("price_list_uuid", sa.Integer(), nullable=False), 24 | sa.Column("price_list_rule_uuid", sa.Integer(), nullable=False), 25 | sa.ForeignKeyConstraint( 26 | ["price_list_rule_uuid"], 27 | ["price_list_rule.uuid"], 28 | ), 29 | sa.ForeignKeyConstraint( 30 | ["price_list_uuid"], 31 | ["price_list.uuid"], 32 | ), 33 | ) 34 | 35 | 36 | def downgrade(): 37 | pass 38 | -------------------------------------------------------------------------------- /migrations/versions/7640c2a9be5b_merge_5259c05704c4_and_fbc611c57b7a.py: -------------------------------------------------------------------------------- 1 | """merge 5259c05704c4 and fbc611c57b7a 2 | 3 | Revision ID: 7640c2a9be5b 4 | Revises: fbc611c57b7a, 5259c05704c4 5 | Create Date: 2023-05-16 20:34:09.615241 6 | 7 | """ 8 | 9 | # revision identifiers, used by Alembic. 10 | revision = "7640c2a9be5b" 11 | down_revision = ("fbc611c57b7a", "5259c05704c4") 12 | branch_labels = None 13 | depends_on = None 14 | 15 | 16 | def upgrade(): 17 | pass 18 | 19 | 20 | def downgrade(): 21 | pass 22 | -------------------------------------------------------------------------------- /migrations/versions/790aae5a7013_add_file_model.py: -------------------------------------------------------------------------------- 1 | """add File model 2 | 3 | Revision ID: 790aae5a7013 4 | Revises: 702d6ee9b14f 5 | Create Date: 2020-09-22 14:45:14.686269 6 | 7 | """ 8 | 9 | from alembic import op 10 | import sqlalchemy as sa 11 | 12 | 13 | # revision identifiers, used by Alembic. 14 | revision = "790aae5a7013" 15 | down_revision = "702d6ee9b14f" 16 | branch_labels = None 17 | depends_on = None 18 | 19 | 20 | def upgrade(): 21 | op.create_table( 22 | "file", 23 | sa.Column("id", sa.Integer(), nullable=False), 24 | sa.Column("created_at", sa.DateTime(), nullable=True), 25 | sa.Column("uuid", sa.String(), nullable=True), 26 | sa.Column("file_name", sa.String(), nullable=True), 27 | sa.PrimaryKeyConstraint("id"), 28 | ) 29 | 30 | 31 | def downgrade(): 32 | pass 33 | -------------------------------------------------------------------------------- /migrations/versions/796ff2e47e13_add_charge_vat_to_setting_model.py: -------------------------------------------------------------------------------- 1 | """add charge_vat to Setting model 2 | 3 | Revision ID: 796ff2e47e13 4 | Revises: 53840eddbb0f 5 | Create Date: 2021-03-06 17:54:23.800916 6 | 7 | """ 8 | 9 | from alembic import op 10 | import sqlalchemy as sa 11 | 12 | 13 | # revision identifiers, used by Alembic. 14 | revision = "796ff2e47e13" 15 | down_revision = "53840eddbb0f" 16 | branch_labels = None 17 | depends_on = None 18 | 19 | 20 | def upgrade(): 21 | with op.batch_alter_table("setting") as batch_op: 22 | batch_op.add_column(sa.Column("charge_vat", sa.Boolean(), default=False)) 23 | 24 | 25 | def downgrade(): 26 | pass 27 | -------------------------------------------------------------------------------- /migrations/versions/7d502ba7279c_add_stripe_subscription_id_to_.py: -------------------------------------------------------------------------------- 1 | """add stripe_subscription_id to Subscription model 2 | 3 | Revision ID: 7d502ba7279c 4 | Revises: 1653ed33cbd4 5 | Create Date: 2020-11-13 12:02:40.496271 6 | 7 | """ 8 | 9 | from alembic import op 10 | import sqlalchemy as sa 11 | 12 | 13 | # revision identifiers, used by Alembic. 14 | revision = "7d502ba7279c" 15 | down_revision = "1653ed33cbd4" 16 | branch_labels = None 17 | depends_on = None 18 | 19 | 20 | def upgrade(): 21 | with op.batch_alter_table("subscription") as batch_op: 22 | batch_op.add_column( 23 | sa.Column("stripe_subscription_id", sa.String(), nullable=True) 24 | ) 25 | 26 | 27 | def downgrade(): 28 | pass 29 | -------------------------------------------------------------------------------- /migrations/versions/7fba2877d034_add_api_key_secret_live_api_key_secret_.py: -------------------------------------------------------------------------------- 1 | """add api_key_secret_live api_key_secret_test to secret model 2 | 3 | Revision ID: 7fba2877d034 4 | Revises: dde6bed9a56f 5 | Create Date: 2022-03-08 01:43:18.744690 6 | 7 | """ 8 | 9 | from alembic import op 10 | import sqlalchemy as sa 11 | 12 | 13 | # revision identifiers, used by Alembic. 14 | revision = "7fba2877d034" 15 | down_revision = "dde6bed9a56f" 16 | branch_labels = None 17 | depends_on = None 18 | 19 | 20 | def upgrade(): 21 | with op.batch_alter_table("setting") as batch_op: 22 | batch_op.add_column( 23 | sa.Column("api_key_secret_live", sa.String(), nullable=True) 24 | ) 25 | batch_op.add_column( 26 | sa.Column("api_key_secret_test", sa.String(), nullable=True) 27 | ) 28 | 29 | 30 | def downgrade(): 31 | pass 32 | -------------------------------------------------------------------------------- /migrations/versions/89b4e5e02eac_add_balance_model.py: -------------------------------------------------------------------------------- 1 | """add balance model 2 | 3 | Revision ID: 89b4e5e02eac 4 | Revises: dde6bed9a56f 5 | Create Date: 2022-02-22 22:14:55.030280 6 | 7 | """ 8 | 9 | from alembic import op 10 | import sqlalchemy as sa 11 | 12 | 13 | # revision identifiers, used by Alembic. 14 | revision = "89b4e5e02eac" 15 | down_revision = "dde6bed9a56f" 16 | branch_labels = None 17 | depends_on = None 18 | 19 | 20 | def upgrade(): 21 | op.create_table( 22 | "balance", 23 | sa.Column("uuid", sa.String(), nullable=False), 24 | sa.Column("available_amount", sa.Integer(), nullable=True), 25 | sa.Column("available_currency", sa.String(), nullable=True), 26 | sa.Column("stripe_livemode", sa.Boolean(), nullable=True), 27 | sa.PrimaryKeyConstraint("uuid"), 28 | ) 29 | 30 | 31 | def downgrade(): 32 | pass 33 | -------------------------------------------------------------------------------- /migrations/versions/8c008c1333d5_add_stripe_user_attempted_checkout_flow_.py: -------------------------------------------------------------------------------- 1 | """add stripe_user_attempted_checkout_flow to Subscription 2 | 3 | Revision ID: 8c008c1333d5 4 | Revises: 3447b58b5c69 5 | Create Date: 2024-07-05 20:39:42.709426 6 | 7 | """ 8 | 9 | from alembic import op 10 | import sqlalchemy as sa 11 | 12 | 13 | # revision identifiers, used by Alembic. 14 | revision = "8c008c1333d5" 15 | down_revision = "3447b58b5c69" 16 | branch_labels = None 17 | depends_on = None 18 | 19 | 20 | def upgrade(): 21 | with op.batch_alter_table("subscription", schema=None) as batch_op: 22 | batch_op.add_column( 23 | sa.Column( 24 | "stripe_user_attempted_checkout_flow", sa.Boolean(), default=False 25 | ) 26 | ) 27 | 28 | 29 | def downgrade(): 30 | pass 31 | -------------------------------------------------------------------------------- /migrations/versions/8d9ada7a21cd_add_description_to_plan_model.py: -------------------------------------------------------------------------------- 1 | """add description to plan model 2 | 3 | Revision ID: 8d9ada7a21cd 4 | Revises: 98099ff3eb9c 5 | Create Date: 2021-01-02 21:00:51.067229 6 | 7 | """ 8 | 9 | from alembic import op 10 | import sqlalchemy as sa 11 | 12 | 13 | # revision identifiers, used by Alembic. 14 | revision = "8d9ada7a21cd" 15 | down_revision = "98099ff3eb9c" 16 | branch_labels = None 17 | depends_on = None 18 | 19 | 20 | def upgrade(): 21 | with op.batch_alter_table("plan") as batch_op: 22 | batch_op.add_column(sa.Column("description", sa.String(), nullable=True)) 23 | 24 | 25 | def downgrade(): 26 | pass 27 | -------------------------------------------------------------------------------- /migrations/versions/9189f7033477_add_private_boolean_to_pages_model.py: -------------------------------------------------------------------------------- 1 | """add private boolean to pages model 2 | 3 | Revision ID: 9189f7033477 4 | Revises: 1653ed33cbd4 5 | Create Date: 2020-11-19 11:40:21.304451 6 | 7 | """ 8 | 9 | from alembic import op 10 | import sqlalchemy as sa 11 | 12 | 13 | # revision identifiers, used by Alembic. 14 | revision = "9189f7033477" 15 | down_revision = "1653ed33cbd4" 16 | branch_labels = None 17 | depends_on = None 18 | 19 | 20 | def upgrade(): 21 | with op.batch_alter_table("page") as batch_op: 22 | batch_op.add_column(sa.Column("private", sa.Boolean, default=False)) 23 | 24 | 25 | def downgrade(): 26 | pass 27 | -------------------------------------------------------------------------------- /migrations/versions/938b171f97ec_subscription_to_document_association.py: -------------------------------------------------------------------------------- 1 | """subscription to document association 2 | 3 | Revision ID: 938b171f97ec 4 | Revises: 429b32b9ad20 5 | Create Date: 2022-11-19 22:56:16.153807 6 | 7 | """ 8 | 9 | from alembic import op 10 | import sqlalchemy as sa 11 | 12 | 13 | # revision identifiers, used by Alembic. 14 | revision = "938b171f97ec" 15 | down_revision = "429b32b9ad20" 16 | branch_labels = None 17 | depends_on = None 18 | 19 | 20 | def upgrade(): 21 | # ### commands auto generated by Alembic - please adjust! ### 22 | op.create_table( 23 | "subscription_document_associations", 24 | sa.Column("subscription_uuid", sa.String(), nullable=False), 25 | sa.Column("document_uuid", sa.String(), nullable=False), 26 | sa.ForeignKeyConstraint( 27 | ["document_uuid"], 28 | ["document.uuid"], 29 | ), 30 | sa.ForeignKeyConstraint( 31 | ["subscription_uuid"], 32 | ["subscription.uuid"], 33 | ), 34 | ) 35 | 36 | 37 | def downgrade(): 38 | pass 39 | -------------------------------------------------------------------------------- /migrations/versions/94790e701430_adding_is_donation_in_transaction_table.py: -------------------------------------------------------------------------------- 1 | """adding_is_donation_in_transaction_table 2 | 3 | Revision ID: 94790e701430 4 | Revises: bd63fd27d653 5 | Create Date: 2023-03-02 19:45:02.205558 6 | 7 | """ 8 | 9 | from alembic import op 10 | import sqlalchemy as sa 11 | 12 | 13 | # revision identifiers, used by Alembic. 14 | revision = "94790e701430" 15 | down_revision = "bd63fd27d653" 16 | branch_labels = None 17 | depends_on = None 18 | 19 | 20 | def upgrade(): 21 | with op.batch_alter_table("transactions", schema=None) as batch_op: 22 | batch_op.add_column(sa.Column("is_donation", sa.Boolean(), nullable=True)) 23 | 24 | 25 | def downgrade(): 26 | pass 27 | -------------------------------------------------------------------------------- /migrations/versions/96430096c2c7_added_stripe_pause_collection_to_.py: -------------------------------------------------------------------------------- 1 | """added stripe pause collection to Transaction table 2 | 3 | Revision ID: 96430096c2c7 4 | Revises: b3f47a3f53e2 5 | Create Date: 2021-07-12 20:12:29.813558 6 | 7 | """ 8 | 9 | from alembic import op 10 | import sqlalchemy as sa 11 | 12 | 13 | # revision identifiers, used by Alembic. 14 | revision = "96430096c2c7" 15 | down_revision = "b3f47a3f53e2" 16 | branch_labels = None 17 | depends_on = None 18 | 19 | 20 | def upgrade(): 21 | op.add_column( 22 | "subscription", sa.Column("stripe_pause_collection", sa.String(), nullable=True) 23 | ) 24 | 25 | 26 | def downgrade(): 27 | pass 28 | -------------------------------------------------------------------------------- /migrations/versions/98099ff3eb9c_merge_heads.py: -------------------------------------------------------------------------------- 1 | """merge heads 2 | 3 | Revision ID: 98099ff3eb9c 4 | Revises: 5 | Create Date: 2020-12-10 20:37:39.753780 6 | 7 | """ 8 | 9 | # revision identifiers, used by Alembic. 10 | revision = "98099ff3eb9c" 11 | down_revision = ("75a87d5ab587", "9189f7033477") 12 | branch_labels = None 13 | depends_on = None 14 | 15 | 16 | def upgrade(): 17 | pass 18 | 19 | 20 | def downgrade(): 21 | pass 22 | -------------------------------------------------------------------------------- /migrations/versions/98bd81ff72f9_merge_heads_4694133a683a_00477315ded9.py: -------------------------------------------------------------------------------- 1 | """merge heads 4694133a683a 00477315ded9 2 | 3 | Revision ID: 98bd81ff72f9 4 | Revises: 4694133a683a, 00477315ded9 5 | Create Date: 2022-04-30 21:49:45.330623 6 | 7 | """ 8 | 9 | # revision identifiers, used by Alembic. 10 | revision = "98bd81ff72f9" 11 | down_revision = ("4694133a683a", "00477315ded9") 12 | branch_labels = None 13 | depends_on = None 14 | 15 | 16 | def upgrade(): 17 | pass 18 | 19 | 20 | def downgrade(): 21 | pass 22 | -------------------------------------------------------------------------------- /migrations/versions/a4d35e9917f7_add_geo_currency_enabled_to_settings.py: -------------------------------------------------------------------------------- 1 | """add geo_currency_enabled to settings 2 | 3 | Revision ID: a4d35e9917f7 4 | Revises: 8c008c1333d5 5 | Create Date: 2024-07-09 04:21:25.517787 6 | 7 | """ 8 | 9 | from alembic import op 10 | import sqlalchemy as sa 11 | 12 | 13 | # revision identifiers, used by Alembic. 14 | revision = "a4d35e9917f7" 15 | down_revision = "8c008c1333d5" 16 | branch_labels = None 17 | depends_on = None 18 | 19 | 20 | def upgrade(): 21 | with op.batch_alter_table("setting", schema=None) as batch_op: 22 | batch_op.add_column( 23 | sa.Column( 24 | "geo_currency_enabled", sa.Boolean(), nullable=True, default=False 25 | ) 26 | ) 27 | 28 | 29 | def downgrade(): 30 | pass 31 | -------------------------------------------------------------------------------- /migrations/versions/abc1ff0c85e0_add_mailchimp_integration_columns.py: -------------------------------------------------------------------------------- 1 | """add mailchimp integration columns 2 | 3 | Revision ID: abc1ff0c85e0 4 | Revises: a4d35e9917f7 5 | Create Date: 2024-08-25 13:14:48.912208 6 | 7 | """ 8 | 9 | from alembic import op 10 | import sqlalchemy as sa 11 | 12 | 13 | # revision identifiers, used by Alembic. 14 | revision = "abc1ff0c85e0" 15 | down_revision = "a4d35e9917f7" 16 | branch_labels = None 17 | depends_on = None 18 | 19 | 20 | def upgrade(): 21 | with op.batch_alter_table("integration", schema=None) as batch_op: 22 | batch_op.add_column(sa.Column("mailchimp_api_key", sa.String(), nullable=True)) 23 | batch_op.add_column(sa.Column("mailchimp_list_id", sa.String(), nullable=True)) 24 | batch_op.add_column(sa.Column("mailchimp_active", sa.Boolean(), nullable=True)) 25 | 26 | 27 | def downgrade(): 28 | pass 29 | -------------------------------------------------------------------------------- /migrations/versions/abfb5c2f77e6_add_spamemaildomain.py: -------------------------------------------------------------------------------- 1 | """add SpamEmailDomain 2 | 3 | Revision ID: abfb5c2f77e6 4 | Revises: abc1ff0c85e0 5 | Create Date: 2024-11-11 21:27:48.094799 6 | 7 | """ 8 | 9 | from alembic import op 10 | import sqlalchemy as sa 11 | 12 | 13 | # revision identifiers, used by Alembic. 14 | revision = "abfb5c2f77e6" 15 | down_revision = "abc1ff0c85e0" 16 | branch_labels = None 17 | depends_on = None 18 | 19 | 20 | def upgrade(): 21 | op.create_table( 22 | "spam_email_domain", 23 | sa.Column("id", sa.Integer(), nullable=False), 24 | sa.Column("uuid", sa.String(), nullable=True), 25 | sa.Column("ts", sa.DateTime(), nullable=True), 26 | sa.Column("domain", sa.String(), nullable=True), 27 | sa.Column("archived", sa.Boolean(), nullable=True), 28 | sa.Column("created_at", sa.DateTime(), nullable=True), 29 | sa.PrimaryKeyConstraint("id"), 30 | ) 31 | 32 | 33 | def downgrade(): 34 | pass 35 | -------------------------------------------------------------------------------- /migrations/versions/b28487bfca0f_merge_c39_add_cancel_at_and_d7b_add_.py: -------------------------------------------------------------------------------- 1 | """Merge c39 add cancel_at and d7b add stripe_status 2 | 3 | Revision ID: b28487bfca0f 4 | Revises: c39dd6d1961f, d7b1aaee84ab 5 | Create Date: 2021-05-03 14:57:43.633763 6 | 7 | """ 8 | 9 | # revision identifiers, used by Alembic. 10 | revision = "b28487bfca0f" 11 | down_revision = ("c39dd6d1961f", "d7b1aaee84ab") 12 | branch_labels = None 13 | depends_on = None 14 | 15 | 16 | def upgrade(): 17 | pass 18 | 19 | 20 | def downgrade(): 21 | pass 22 | -------------------------------------------------------------------------------- /migrations/versions/b3c13acc1013_store_cancel_at_as_int.py: -------------------------------------------------------------------------------- 1 | """store cancel_at as int 2 | 3 | Revision ID: b3c13acc1013 4 | Revises: 084669093d74 5 | Create Date: 2021-05-09 14:12:15.268759 6 | 7 | """ 8 | 9 | from alembic import op 10 | import sqlalchemy as sa 11 | 12 | 13 | # revision identifiers, used by Alembic. 14 | revision = "b3c13acc1013" 15 | down_revision = "084669093d74" 16 | branch_labels = None 17 | depends_on = None 18 | 19 | 20 | def upgrade(): 21 | with op.batch_alter_table("plan") as batch_op: 22 | batch_op.alter_column( 23 | "cancel_at", 24 | type_=sa.Boolean(), 25 | nullable=True, 26 | existing_type=sa.String(), 27 | default=False, 28 | ) 29 | 30 | with op.batch_alter_table("subscription") as batch_op: 31 | batch_op.alter_column( 32 | "stripe_cancel_at", type_=sa.Boolean(), nullable=True, default=False 33 | ) 34 | 35 | 36 | def downgrade(): 37 | pass 38 | -------------------------------------------------------------------------------- /migrations/versions/b3f47a3f53e2_add_hascreatedat_to_all_models.py: -------------------------------------------------------------------------------- 1 | """add HasCreatedAt to all models 2 | 3 | Revision ID: b3f47a3f53e2 4 | Revises: 3a8f3089d09d 5 | Create Date: 2021-06-05 14:52:15.700299 6 | 7 | """ 8 | 9 | from alembic import op 10 | import sqlalchemy as sa 11 | 12 | 13 | # revision identifiers, used by Alembic. 14 | revision = "b3f47a3f53e2" 15 | down_revision = "3a8f3089d09d" 16 | branch_labels = None 17 | depends_on = None 18 | 19 | 20 | def upgrade(): 21 | with op.batch_alter_table("email_template") as batch_op: 22 | batch_op.add_column(sa.Column("created_at", sa.DateTime(), nullable=True)) 23 | 24 | with op.batch_alter_table("login_token") as batch_op: 25 | batch_op.add_column(sa.Column("created_at", sa.DateTime(), nullable=True)) 26 | 27 | with op.batch_alter_table("module_seo_page_title") as batch_op: 28 | batch_op.add_column(sa.Column("created_at", sa.DateTime(), nullable=True)) 29 | 30 | with op.batch_alter_table("setting") as batch_op: 31 | batch_op.add_column(sa.Column("created_at", sa.DateTime(), nullable=True)) 32 | 33 | 34 | def downgrade(): 35 | pass 36 | -------------------------------------------------------------------------------- /migrations/versions/b767faeb4c0d_add_private_to_plan_model.py: -------------------------------------------------------------------------------- 1 | """add private to plan model 2 | 3 | Revision ID: b767faeb4c0d 4 | Revises: 21b64f9d73dd 5 | Create Date: 2021-03-27 00:26:17.579713 6 | 7 | """ 8 | 9 | from alembic import op 10 | import sqlalchemy as sa 11 | 12 | 13 | # revision identifiers, used by Alembic. 14 | revision = "b767faeb4c0d" 15 | down_revision = "21b64f9d73dd" 16 | branch_labels = None 17 | depends_on = None 18 | 19 | 20 | def upgrade(): 21 | with op.batch_alter_table("plan") as batch_op: 22 | batch_op.add_column(sa.Column("private", sa.Boolean(), default=False)) 23 | 24 | 25 | def downgrade(): 26 | pass 27 | -------------------------------------------------------------------------------- /migrations/versions/b8e926d239f9_create_category_table.py: -------------------------------------------------------------------------------- 1 | """create category table 2 | 3 | Revision ID: b8e926d239f9 4 | Revises: e0919a39645f 5 | Create Date: 2021-03-18 20:28:24.894968 6 | 7 | """ 8 | 9 | from alembic import op 10 | import sqlalchemy as sa 11 | 12 | 13 | # revision identifiers, used by Alembic. 14 | revision = "b8e926d239f9" 15 | down_revision = "e0919a39645f" 16 | branch_labels = None 17 | depends_on = None 18 | 19 | 20 | def upgrade(): 21 | # ### commands auto generated by Alembic - please adjust! ### 22 | op.create_table( 23 | "category", 24 | sa.Column("id", sa.Integer(), nullable=False), 25 | sa.Column("uuid", sa.String(), nullable=True), 26 | sa.Column("created_at", sa.DateTime(), nullable=True), 27 | sa.Column("name", sa.String(), nullable=True), 28 | sa.PrimaryKeyConstraint("id"), 29 | ) 30 | with op.batch_alter_table("plan") as batch_op: 31 | batch_op.add_column(sa.Column("category_uuid", sa.Integer(), nullable=True)) 32 | batch_op.create_foreign_key( 33 | "fk_category_uuid", "category", ["category_uuid"], ["uuid"] 34 | ) 35 | 36 | 37 | def downgrade(): 38 | pass 39 | -------------------------------------------------------------------------------- /migrations/versions/bb76d2149316_add_parent_plan_revision_uuid_to_plan.py: -------------------------------------------------------------------------------- 1 | """add parent_plan_revision_uuid to plan 2 | 3 | Revision ID: bb76d2149316 4 | Revises: 48074e6225c6 5 | Create Date: 2024-02-16 23:22:02.230866 6 | 7 | """ 8 | 9 | from alembic import op 10 | import sqlalchemy as sa 11 | 12 | 13 | # revision identifiers, used by Alembic. 14 | revision = "bb76d2149316" 15 | down_revision = "48074e6225c6" 16 | branch_labels = None 17 | depends_on = None 18 | 19 | 20 | def upgrade(): 21 | with op.batch_alter_table("plan", schema=None) as batch_op: 22 | batch_op.add_column( 23 | sa.Column("parent_plan_revision_uuid", sa.String(), nullable=True) 24 | ) 25 | 26 | 27 | def downgrade(): 28 | pass 29 | -------------------------------------------------------------------------------- /migrations/versions/bd63fd27d653_add_donations_columns_in_settings.py: -------------------------------------------------------------------------------- 1 | """add-donations-columns-in-settings 2 | 3 | Revision ID: bd63fd27d653 4 | Revises: 938b171f97ec 5 | Create Date: 2023-02-15 13:54:54.675597 6 | 7 | """ 8 | 9 | from alembic import op 10 | import sqlalchemy as sa 11 | 12 | 13 | # revision identifiers, used by Alembic. 14 | revision = "bd63fd27d653" 15 | down_revision = "938b171f97ec" 16 | branch_labels = None 17 | depends_on = None 18 | 19 | 20 | def upgrade(): 21 | with op.batch_alter_table("setting", schema=None) as batch_op: 22 | batch_op.add_column(sa.Column("donations_enabled", sa.Boolean(), nullable=True)) 23 | 24 | 25 | def downgrade(): 26 | pass 27 | -------------------------------------------------------------------------------- /migrations/versions/c39dd6d1961f_add_cancel_at_to_plan_model.py: -------------------------------------------------------------------------------- 1 | """add cancel_at to plan model 2 | 3 | Revision ID: c39dd6d1961f 4 | Revises: c751fe53a042 5 | Create Date: 2021-04-25 15:29:11.034541 6 | 7 | """ 8 | 9 | from alembic import op 10 | import sqlalchemy as sa 11 | 12 | 13 | # revision identifiers, used by Alembic. 14 | revision = "c39dd6d1961f" 15 | down_revision = "c751fe53a042" 16 | branch_labels = None 17 | depends_on = None 18 | 19 | 20 | def upgrade(): 21 | with op.batch_alter_table("plan") as batch_op: 22 | batch_op.add_column(sa.Column("cancel_at", sa.String(), nullable=True)) 23 | 24 | 25 | def downgrade(): 26 | pass 27 | -------------------------------------------------------------------------------- /migrations/versions/c48dccfb0df5_add_password_expired_to_user_and_.py: -------------------------------------------------------------------------------- 1 | """add password_expired to user and subscriber models 2 | 3 | Revision ID: c48dccfb0df5 4 | Revises: 2378e3286d5b 5 | Create Date: 2021-05-22 14:07:47.465185 6 | 7 | """ 8 | 9 | from alembic import op 10 | import sqlalchemy as sa 11 | 12 | 13 | # revision identifiers, used by Alembic. 14 | revision = "c48dccfb0df5" 15 | down_revision = "2378e3286d5b" 16 | branch_labels = None 17 | depends_on = None 18 | 19 | 20 | def upgrade(): 21 | with op.batch_alter_table("person") as batch_op: 22 | batch_op.add_column(sa.Column("password_expired", sa.Boolean(), nullable=True)) 23 | 24 | with op.batch_alter_table("user") as batch_op: 25 | batch_op.add_column(sa.Column("password_expired", sa.Boolean(), nullable=True)) 26 | 27 | 28 | def downgrade(): 29 | pass 30 | -------------------------------------------------------------------------------- /migrations/versions/c57ff5a7436a_.py: -------------------------------------------------------------------------------- 1 | """empty message 2 | 3 | Revision ID: c57ff5a7436a 4 | Revises: 5e756a48f86d, 7fba2877d034 5 | Create Date: 2022-03-15 19:30:28.091766 6 | 7 | """ 8 | 9 | # revision identifiers, used by Alembic. 10 | revision = "c57ff5a7436a" 11 | down_revision = ("5e756a48f86d", "7fba2877d034") 12 | branch_labels = None 13 | depends_on = None 14 | 15 | 16 | def upgrade(): 17 | pass 18 | 19 | 20 | def downgrade(): 21 | pass 22 | -------------------------------------------------------------------------------- /migrations/versions/c5bec71f1499_add_question_table.py: -------------------------------------------------------------------------------- 1 | """add question table 2 | 3 | Revision ID: c5bec71f1499 4 | Revises: bb76d2149316 5 | Create Date: 2024-05-08 21:30:41.805887 6 | 7 | """ 8 | 9 | from alembic import op 10 | import sqlalchemy as sa 11 | 12 | 13 | # revision identifiers, used by Alembic. 14 | revision = "c5bec71f1499" 15 | down_revision = "bb76d2149316" 16 | branch_labels = None 17 | depends_on = None 18 | 19 | 20 | def upgrade(): 21 | op.create_table( 22 | "question", 23 | sa.Column("id", sa.Integer(), nullable=False), 24 | sa.Column("uuid", sa.String(), nullable=False), 25 | sa.Column("created_at", sa.DateTime(), nullable=False), 26 | sa.Column("title", sa.String(), nullable=False), 27 | sa.PrimaryKeyConstraint("id"), 28 | ) 29 | 30 | 31 | def downgrade(): 32 | pass 33 | -------------------------------------------------------------------------------- /migrations/versions/c5d444ee3ccd_rename_stripe_webhook_and_account_cols_.py: -------------------------------------------------------------------------------- 1 | """rename stripe webhook and account cols payment_provider 2 | 3 | Revision ID: c5d444ee3ccd 4 | Revises: 2c7e021d9a69 5 | Create Date: 2020-11-02 11:31:22.184012 6 | 7 | """ 8 | 9 | from alembic import op 10 | 11 | # revision identifiers, used by Alembic. 12 | revision = "c5d444ee3ccd" 13 | down_revision = "2c7e021d9a69" 14 | branch_labels = None 15 | depends_on = None 16 | 17 | 18 | def upgrade(): 19 | with op.batch_alter_table("payment_provider") as batch_op: 20 | batch_op.alter_column( 21 | "stripe_webhook_endpoint_id", 22 | new_column_name="stripe_live_webhook_endpoint_id", 23 | ) 24 | batch_op.alter_column( 25 | "stripe_webhook_endpoint_secret", 26 | new_column_name="stripe_live_webhook_endpoint_secret", 27 | ) 28 | batch_op.alter_column( 29 | "stripe_connect_account_id", 30 | new_column_name="stripe_live_connect_account_id", 31 | ) 32 | 33 | 34 | def downgrade(): 35 | pass 36 | -------------------------------------------------------------------------------- /migrations/versions/c70cd4900c96_add_answer_model.py: -------------------------------------------------------------------------------- 1 | """add answer model 2 | 3 | Revision ID: c70cd4900c96 4 | Revises: 063ddc60bef1 5 | Create Date: 2024-05-14 21:18:13.745275 6 | 7 | """ 8 | 9 | from alembic import op 10 | import sqlalchemy as sa 11 | 12 | 13 | # revision identifiers, used by Alembic. 14 | revision = "c70cd4900c96" 15 | down_revision = "063ddc60bef1" 16 | branch_labels = None 17 | depends_on = None 18 | 19 | 20 | def upgrade(): 21 | op.create_table( 22 | "answer", 23 | sa.Column("id", sa.Integer(), nullable=False), 24 | sa.Column("created_at", sa.DateTime(), nullable=True), 25 | sa.Column("question_id", sa.Integer(), nullable=True), 26 | sa.Column("question_title", sa.String(), nullable=True), 27 | sa.Column("response", sa.String(), nullable=True), 28 | sa.Column("subscription_id", sa.Integer(), nullable=True), 29 | sa.ForeignKeyConstraint( 30 | ["subscription_id"], 31 | ["subscription.id"], 32 | ), 33 | sa.PrimaryKeyConstraint("id"), 34 | ) 35 | 36 | 37 | def downgrade(): 38 | pass 39 | -------------------------------------------------------------------------------- /migrations/versions/c751fe53a042_add_external_refund_id_to_transaction_.py: -------------------------------------------------------------------------------- 1 | """add external_refund_id to transaction model 2 | 3 | Revision ID: c751fe53a042 4 | Revises: b767faeb4c0d 5 | Create Date: 2021-04-08 15:19:14.355699 6 | 7 | """ 8 | 9 | from alembic import op 10 | import sqlalchemy as sa 11 | 12 | 13 | # revision identifiers, used by Alembic. 14 | revision = "c751fe53a042" 15 | down_revision = "b767faeb4c0d" 16 | branch_labels = None 17 | depends_on = None 18 | 19 | 20 | def upgrade(): 21 | with op.batch_alter_table("transactions") as batch_op: 22 | batch_op.add_column(sa.Column("external_refund_id", sa.String(), nullable=True)) 23 | 24 | 25 | def downgrade(): 26 | pass 27 | -------------------------------------------------------------------------------- /migrations/versions/c7a493cd99d4_create_questionoption_model.py: -------------------------------------------------------------------------------- 1 | """create QuestionOption model 2 | 3 | Revision ID: c7a493cd99d4 4 | Revises: c70cd4900c96 5 | Create Date: 2024-05-18 20:02:36.104426 6 | 7 | """ 8 | 9 | from alembic import op 10 | import sqlalchemy as sa 11 | 12 | 13 | # revision identifiers, used by Alembic. 14 | revision = "c7a493cd99d4" 15 | down_revision = "c70cd4900c96" 16 | branch_labels = None 17 | depends_on = None 18 | 19 | 20 | def upgrade(): 21 | op.create_table( 22 | "question_option", 23 | sa.Column("id", sa.Integer(), nullable=False), 24 | sa.Column("question_id", sa.Integer(), nullable=True), 25 | sa.Column("created_at", sa.DateTime(), nullable=True), 26 | sa.Column("title", sa.String(), nullable=True), 27 | sa.Column("description", sa.Text(), nullable=True), 28 | sa.Column("primary_icon", sa.String(), nullable=True), 29 | sa.ForeignKeyConstraint( 30 | ["question_id"], 31 | ["question.id"], 32 | ), 33 | sa.PrimaryKeyConstraint("id"), 34 | ) 35 | 36 | with op.batch_alter_table("question", schema=None) as batch_op: 37 | batch_op.alter_column("uuid", existing_type=sa.VARCHAR(), nullable=True) 38 | batch_op.alter_column("created_at", existing_type=sa.DATETIME(), nullable=True) 39 | batch_op.alter_column("title", existing_type=sa.VARCHAR(), nullable=True) 40 | 41 | 42 | def downgrade(): 43 | pass 44 | -------------------------------------------------------------------------------- /migrations/versions/d04243b7bd47_add_custom_code_to_setting_model.py: -------------------------------------------------------------------------------- 1 | """add custom_code to Setting model 2 | 3 | Revision ID: d04243b7bd47 4 | Revises: 746b4765a957 5 | Create Date: 2021-03-24 18:16:54.944191 6 | 7 | """ 8 | 9 | from alembic import op 10 | import sqlalchemy as sa 11 | 12 | 13 | # revision identifiers, used by Alembic. 14 | revision = "d04243b7bd47" 15 | down_revision = "746b4765a957" 16 | branch_labels = None 17 | depends_on = None 18 | 19 | 20 | def upgrade(): 21 | with op.batch_alter_table("setting") as batch_op: 22 | batch_op.add_column(sa.Column("custom_code", sa.String(), nullable=True)) 23 | 24 | 25 | def downgrade(): 26 | pass 27 | -------------------------------------------------------------------------------- /migrations/versions/d7b1aaee84ab_add_stripe_status_to_subscription_model.py: -------------------------------------------------------------------------------- 1 | """add stripe_status to subscription model 2 | 3 | Revision ID: d7b1aaee84ab 4 | Revises: c751fe53a042 5 | Create Date: 2021-05-01 23:05:25.344813 6 | 7 | """ 8 | 9 | from alembic import op 10 | import sqlalchemy as sa 11 | 12 | 13 | # revision identifiers, used by Alembic. 14 | revision = "d7b1aaee84ab" 15 | down_revision = "c751fe53a042" 16 | branch_labels = None 17 | depends_on = None 18 | 19 | 20 | def upgrade(): 21 | with op.batch_alter_table("subscription") as batch_op: 22 | batch_op.add_column(sa.Column("stripe_status", sa.String(), nullable=True)) 23 | 24 | 25 | def downgrade(): 26 | pass 27 | -------------------------------------------------------------------------------- /migrations/versions/d8c120e8212e_add_proration_behavior_stripe_proration_.py: -------------------------------------------------------------------------------- 1 | """add proration_behavior stripe_proration_behavior plan subscription 2 | 3 | Revision ID: d8c120e8212e 4 | Revises: a4d35e9917f7 5 | Create Date: 2024-07-27 22:21:26.823294 6 | 7 | """ 8 | 9 | from alembic import op 10 | import sqlalchemy as sa 11 | 12 | 13 | # revision identifiers, used by Alembic. 14 | revision = "d8c120e8212e" 15 | down_revision = "a4d35e9917f7" 16 | branch_labels = None 17 | depends_on = None 18 | 19 | 20 | def upgrade(): 21 | # "none" not to be confused with "None" 22 | # See 23 | # https://docs.stripe.com/api/subscriptions/create#create_subscription-proration_behavior 24 | with op.batch_alter_table("plan", schema=None) as batch_op: 25 | batch_op.add_column( 26 | sa.Column("proration_behavior", sa.String(), nullable=True, default="none") 27 | ) 28 | 29 | # "none" not to be confused with "None" 30 | # See 31 | # https://docs.stripe.com/api/subscriptions/create#create_subscription-proration_behavior 32 | with op.batch_alter_table("subscription", schema=None) as batch_op: 33 | batch_op.add_column( 34 | sa.Column( 35 | "stripe_proration_behavior", sa.String(), nullable=True, default="none" 36 | ) 37 | ) 38 | 39 | 40 | def downgrade(): 41 | pass 42 | -------------------------------------------------------------------------------- /migrations/versions/da154873f3ab_add_created_at_uuid_to_.py: -------------------------------------------------------------------------------- 1 | """add created_at uuid to PlanQuestionAssociation 2 | 3 | Revision ID: da154873f3ab 4 | Revises: 57b068821280 5 | Create Date: 2024-05-19 21:59:10.555714 6 | 7 | """ 8 | 9 | from alembic import op 10 | import sqlalchemy as sa 11 | 12 | 13 | # revision identifiers, used by Alembic. 14 | revision = "da154873f3ab" 15 | down_revision = "57b068821280" 16 | branch_labels = None 17 | depends_on = None 18 | 19 | 20 | def upgrade(): 21 | with op.batch_alter_table("plan_question_associations", schema=None) as batch_op: 22 | batch_op.add_column(sa.Column("created_at", sa.DateTime(), nullable=True)) 23 | batch_op.add_column(sa.Column("uuid", sa.String(), nullable=True)) 24 | 25 | 26 | def downgrade(): 27 | pass 28 | -------------------------------------------------------------------------------- /migrations/versions/dde6bed9a56f_add_shop_activated_to_setting_model.py: -------------------------------------------------------------------------------- 1 | """add shop_activated to setting model 2 | 3 | Revision ID: dde6bed9a56f 4 | Revises: 96430096c2c7 5 | Create Date: 2022-01-25 10:04:41.225725 6 | 7 | """ 8 | 9 | from alembic import op 10 | import sqlalchemy as sa 11 | 12 | 13 | # revision identifiers, used by Alembic. 14 | revision = "dde6bed9a56f" 15 | down_revision = "96430096c2c7" 16 | branch_labels = None 17 | depends_on = None 18 | 19 | 20 | def upgrade(): 21 | with op.batch_alter_table("setting") as batch_op: 22 | batch_op.add_column(sa.Column("shop_activated", sa.Boolean(), default=0)) 23 | 24 | 25 | def downgrade(): 26 | pass 27 | -------------------------------------------------------------------------------- /migrations/versions/e0919a39645f_add_stripe_livemode_column_to_taxrate_.py: -------------------------------------------------------------------------------- 1 | """add stripe_livemode column to TaxRate model 2 | 3 | Revision ID: e0919a39645f 4 | Revises: 796ff2e47e13 5 | Create Date: 2021-03-06 18:23:31.252540 6 | 7 | """ 8 | 9 | from alembic import op 10 | import sqlalchemy as sa 11 | 12 | 13 | # revision identifiers, used by Alembic. 14 | revision = "e0919a39645f" 15 | down_revision = "796ff2e47e13" 16 | branch_labels = None 17 | depends_on = None 18 | 19 | 20 | def upgrade(): 21 | with op.batch_alter_table("tax_rate") as batch_op: 22 | batch_op.add_column(sa.Column("stripe_livemode", sa.Boolean())) 23 | 24 | 25 | def downgrade(): 26 | pass 27 | -------------------------------------------------------------------------------- /migrations/versions/e0a8901cde76_add_default_country_code_to_settings_.py: -------------------------------------------------------------------------------- 1 | """add default_country_code to settings table 2 | 3 | Revision ID: e0a8901cde76 4 | Revises: f064a641532c 5 | Create Date: 2022-10-06 00:04:42.866952 6 | 7 | """ 8 | 9 | from alembic import op 10 | import sqlalchemy as sa 11 | 12 | 13 | # revision identifiers, used by Alembic. 14 | revision = "e0a8901cde76" 15 | down_revision = "f064a641532c" 16 | branch_labels = None 17 | depends_on = None 18 | 19 | 20 | def upgrade(): 21 | with op.batch_alter_table("setting") as batch_op: 22 | batch_op.add_column( 23 | sa.Column("default_country_code", sa.String(), nullable=True) 24 | ) 25 | 26 | 27 | def downgrade(): 28 | pass 29 | -------------------------------------------------------------------------------- /migrations/versions/e9e1f148655e_add_association_table_plan_to_price_.py: -------------------------------------------------------------------------------- 1 | """add association_table_plan_to_price_lists 2 | 3 | Revision ID: e9e1f148655e 4 | Revises: 75dffc3851d8 5 | Create Date: 2022-06-19 22:31:08.394131 6 | 7 | """ 8 | 9 | from alembic import op 10 | import sqlalchemy as sa 11 | 12 | 13 | # revision identifiers, used by Alembic. 14 | revision = "e9e1f148655e" 15 | down_revision = "75dffc3851d8" 16 | branch_labels = None 17 | depends_on = None 18 | 19 | 20 | def upgrade(): 21 | # ### commands auto generated by Alembic - please adjust! ### 22 | op.create_table( 23 | "plan_price_list_associations", 24 | sa.Column("plan_uuid", sa.String(), nullable=False), 25 | sa.Column("price_list_uuid", sa.String(), nullable=True), 26 | sa.ForeignKeyConstraint( 27 | ["plan_uuid"], 28 | ["plan.uuid"], 29 | ), 30 | sa.ForeignKeyConstraint( 31 | ["price_list_uuid"], 32 | ["price_list.uuid"], 33 | ), 34 | ) 35 | 36 | 37 | def downgrade(): 38 | pass 39 | -------------------------------------------------------------------------------- /migrations/versions/ee8e62e05b40_add_back_stripe_test_mode_colums.py: -------------------------------------------------------------------------------- 1 | """add back stripe test mode colums 2 | 3 | Revision ID: ee8e62e05b40 4 | Revises: 686d588c3c29 5 | Create Date: 2020-11-02 16:38:32.337427 6 | 7 | """ 8 | 9 | from alembic import op 10 | import sqlalchemy as sa 11 | 12 | 13 | # revision identifiers, used by Alembic. 14 | revision = "ee8e62e05b40" 15 | down_revision = "686d588c3c29" 16 | branch_labels = None 17 | depends_on = None 18 | 19 | 20 | def upgrade(): 21 | with op.batch_alter_table("payment_provider") as batch_op: 22 | batch_op.add_column( 23 | sa.Column("stripe_test_webhook_endpoint_id", sa.String(), nullable=True) 24 | ) 25 | batch_op.add_column( 26 | sa.Column("stripe_test_webhook_endpoint_secret", sa.String(), nullable=True) 27 | ) 28 | 29 | 30 | def downgrade(): 31 | pass 32 | -------------------------------------------------------------------------------- /migrations/versions/f064a641532c_set_stripe_active_default_false_and_add_.py: -------------------------------------------------------------------------------- 1 | """Set stripe_active default false and add interval_unit interval_amount to subscription 2 | 3 | Revision ID: f064a641532c 4 | Revises: fcd870ab34b8, 5b308deca3d3 5 | Create Date: 2022-09-13 12:18:31.520291 6 | 7 | """ 8 | 9 | from alembic import op 10 | import sqlalchemy as sa 11 | 12 | 13 | # revision identifiers, used by Alembic. 14 | revision = "f064a641532c" 15 | down_revision = ("fcd870ab34b8", "5b308deca3d3") 16 | branch_labels = None 17 | depends_on = None 18 | 19 | 20 | def upgrade(): 21 | pass 22 | 23 | 24 | def downgrade(): 25 | pass 26 | -------------------------------------------------------------------------------- /migrations/versions/f0e91df9fbf1_add_stripe_livemode_to_payment_provider.py: -------------------------------------------------------------------------------- 1 | """add stripe_livemode to payment_provider 2 | 3 | Revision ID: f0e91df9fbf1 4 | Revises: 3abcbb0428ef 5 | Create Date: 2020-10-01 16:30:38.155152 6 | 7 | """ 8 | 9 | from alembic import op 10 | import sqlalchemy as sa 11 | 12 | 13 | # revision identifiers, used by Alembic. 14 | revision = "f0e91df9fbf1" 15 | down_revision = "3abcbb0428ef" 16 | branch_labels = None 17 | depends_on = None 18 | 19 | 20 | def upgrade(): 21 | with op.batch_alter_table("payment_provider") as batch_op: 22 | batch_op.add_column(sa.Column("stripe_livemode", sa.Boolean(), nullable=True)) 23 | 24 | 25 | def downgrade(): 26 | with op.batch_alter_table("payment_provider") as batch_op: 27 | batch_op.drop_column("stripe_livemode") 28 | -------------------------------------------------------------------------------- /migrations/versions/f3579efd3331_add_stripe_external_id_to_subscription_.py: -------------------------------------------------------------------------------- 1 | """add stripe_external_id to Subscription model 2 | 3 | Revision ID: f3579efd3331 4 | Revises: 7d502ba7279c 5 | Create Date: 2020-12-04 14:51:09.699273 6 | 7 | """ 8 | 9 | from alembic import op 10 | import sqlalchemy as sa 11 | 12 | 13 | # revision identifiers, used by Alembic. 14 | revision = "f3579efd3331" 15 | down_revision = "7d502ba7279c" 16 | branch_labels = None 17 | depends_on = None 18 | 19 | 20 | def upgrade(): 21 | with op.batch_alter_table("subscription") as batch_op: 22 | batch_op.add_column(sa.Column("stripe_external_id", sa.String(), nullable=True)) 23 | 24 | 25 | def downgrade(): 26 | pass 27 | -------------------------------------------------------------------------------- /migrations/versions/fbc611c57b7a_add_hasreadonly_read_only_mixin_to_.py: -------------------------------------------------------------------------------- 1 | """add HasReadOnly read_only mixin to documents model 2 | 3 | Revision ID: fbc611c57b7a 4 | Revises: 94790e701430 5 | Create Date: 2023-05-11 22:44:20.776241 6 | 7 | """ 8 | 9 | from alembic import op 10 | import sqlalchemy as sa 11 | 12 | 13 | # revision identifiers, used by Alembic. 14 | revision = "fbc611c57b7a" 15 | down_revision = "94790e701430" 16 | branch_labels = None 17 | depends_on = None 18 | 19 | 20 | def upgrade(): 21 | op.add_column("document", sa.Column("read_only", sa.Boolean(), nullable=True)) 22 | 23 | 24 | def downgrade(): 25 | pass 26 | -------------------------------------------------------------------------------- /migrations/versions/fc7ac6f06521_add_document_table.py: -------------------------------------------------------------------------------- 1 | """add Document table 2 | 3 | Revision ID: fc7ac6f06521 4 | Revises: e0a8901cde76 5 | Create Date: 2022-11-16 22:56:12.898374 6 | 7 | """ 8 | 9 | from alembic import op 10 | import sqlalchemy as sa 11 | 12 | 13 | # revision identifiers, used by Alembic. 14 | revision = "fc7ac6f06521" 15 | down_revision = "e0a8901cde76" 16 | branch_labels = None 17 | depends_on = None 18 | 19 | 20 | def upgrade(): 21 | op.create_table( 22 | "document", 23 | sa.Column("archived", sa.Boolean(), nullable=False), 24 | sa.Column("id", sa.Integer(), nullable=False), 25 | sa.Column("created_at", sa.DateTime(), nullable=True), 26 | sa.Column("uuid", sa.String(), nullable=True), 27 | sa.Column("name", sa.String(), nullable=True), 28 | sa.Column("type", sa.String(), nullable=True), 29 | sa.Column("body", sa.String(), nullable=True), 30 | sa.PrimaryKeyConstraint("id"), 31 | ) 32 | 33 | 34 | def downgrade(): 35 | pass 36 | -------------------------------------------------------------------------------- /migrations/versions/fcd870ab34b8_set_stripe_active_default_false.py: -------------------------------------------------------------------------------- 1 | """Set stripe_active default false 2 | 3 | Revision ID: fcd870ab34b8 4 | Revises: 00477315ded9 5 | Create Date: 2022-09-12 14:37:30.182327 6 | 7 | """ 8 | 9 | from alembic import op 10 | from sqlalchemy import text 11 | 12 | # revision identifiers, used by Alembic. 13 | revision = "fcd870ab34b8" 14 | down_revision = "00477315ded9" 15 | branch_labels = None 16 | depends_on = None 17 | 18 | 19 | def upgrade(): 20 | with op.batch_alter_table("payment_provider") as batch_op: 21 | batch_op.alter_column( 22 | "stripe_active", 23 | server_default=text("0"), 24 | ) 25 | 26 | 27 | def downgrade(): 28 | pass 29 | -------------------------------------------------------------------------------- /migrations/versions/fd28aefcdb76_add_css_properties_json_remove_bg_.py: -------------------------------------------------------------------------------- 1 | """add css_properties_json remove bg_primary column 2 | 3 | Revision ID: fd28aefcdb76 4 | Revises: 6cc0e87e8836 5 | Create Date: 2021-01-16 13:12:55.795750 6 | 7 | """ 8 | 9 | from alembic import op 10 | import sqlalchemy as sa 11 | 12 | 13 | # revision identifiers, used by Alembic. 14 | revision = "fd28aefcdb76" 15 | down_revision = "6cc0e87e8836" 16 | branch_labels = None 17 | depends_on = None 18 | 19 | 20 | def upgrade(): 21 | with op.batch_alter_table("module_style") as batch_op: 22 | batch_op.add_column( 23 | sa.Column("css_properties_json", sa.String(), nullable=True) 24 | ) 25 | batch_op.drop_column("bg_primary") 26 | 27 | 28 | def downgrade(): 29 | pass 30 | -------------------------------------------------------------------------------- /operational_scripts/README.md: -------------------------------------------------------------------------------- 1 | (useful?) operational scripts 2 | -------------------------------------------------------------------------------- /operational_scripts/generate-compiled-language-files-3.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # Credit: https://blog.miguelgrinberg.com/post/the-flask-mega-tutorial-part-xiii-i18n-and-l10n 4 | # The messages.po file is a sort of source file for translations. When you want to start using these translated texts, this file needs to be compiled into a format that is efficient to be used by the application at run-time. To compile all the translations for the application, you can use the pybabel compile command as follows: 5 | 6 | 7 | pybabel compile -d ../subscribie/translations/ 8 | -------------------------------------------------------------------------------- /operational_scripts/generate-language-catalog-2.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # Credit: 4 | # https://blog.miguelgrinberg.com/post/the-flask-mega-tutorial-part-xiii-i18n-and-l10n 5 | # 6 | # The pybabel init command takes the messages.pot file as input and writes a new language catalog to the directory given in the -d option for the language specified in the -l option. I'm going to be installing all the translations in the app/translations directory, because that is where Flask-Babel will expect translation files to be by default. The command will create a es subdirectory inside this directory for the Spanish data files. In particular, there will be a new file named app/translations/es/LC_MESSAGES/messages.po, that is where the translations need to be made. 7 | 8 | pybabel init -i messages.pot -d ../subscribie/translations/ -l de 9 | -------------------------------------------------------------------------------- /operational_scripts/generate-pot-file-1.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # Ref 4 | # Credit: https://blog.miguelgrinberg.com/post/the-flask-mega-tutorial-part-xiii-i18n-and-l10n 5 | # The pybabel extract command reads the configuration file given in the -F option, then scans all the code and template files in the directories that match the configured sources, starting from the directory given in the command (the current directory or . in this case). By default, pybabel will look for _() as a text marker, but I have also used the lazy version, which I imported as _l(), so I need to tell the tool to look for those too with the -k _l. The -o option provides the name of the output file. 6 | 7 | pybabel extract -F babel.cfg -k _l -o messages.pot ../ 8 | -------------------------------------------------------------------------------- /operational_scripts/openit.mjs: -------------------------------------------------------------------------------- 1 | import fs from 'fs' 2 | import YAML from 'yaml' 3 | 4 | const file = fs.readFileSync('./settings.yaml', 'utf8') 5 | 6 | let settings = YAML.parse(file) 7 | 8 | console.log(settings) 9 | 10 | -------------------------------------------------------------------------------- /operational_scripts/recover-database.py: -------------------------------------------------------------------------------- 1 | import sqlite3 2 | 3 | from datetime import datetime 4 | 5 | date_format = "%Y-%m-%d %H:%M:%S.%f" 6 | # Connect to the SQLite database 7 | conn = sqlite3.connect("data.db") 8 | 9 | # Create a cursor object using the cursor() method 10 | cursor = conn.cursor() 11 | 12 | # Selecting the 'stripe_invoice_raw_json' column from the 'stripe_invoice' table 13 | query = "SELECT id, created_at, stripe_invoice_raw_json FROM stripe_invoice" 14 | 15 | # Executing the query 16 | cursor.execute(query) 17 | 18 | # Fetch all rows from the executed query 19 | rows = cursor.fetchall() 20 | 21 | count = 0 22 | errors = 0 23 | # Looping over each row and printing the 'stripe_invoice_raw_json' column 24 | for row in rows: 25 | count += 1 26 | print(row[1]) 27 | datetime.strptime(row[1], date_format) 28 | try: 29 | if row[0] == "example": 30 | update_query = "UPDATE table_name SET column_name = ? WHERE id = ?" 31 | cursor.execute( 32 | update_query, 33 | ("foo", "bar"), 34 | ) 35 | conn.commit() 36 | except ValueError as e: 37 | print(e) 38 | errors += 1 39 | 40 | # Close the connection 41 | conn.close() 42 | 43 | print(f"Total rows: {count}") 44 | print(f"Total errors: {errors}") 45 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "subscribie", 3 | "version": "1.0.0", 4 | "description": "Subscription website builder", 5 | "main": "index.js", 6 | "directories": { 7 | "test": "tests" 8 | }, 9 | "dependencies": { 10 | "yaml": "^2.7.0" 11 | }, 12 | "devDependencies": { 13 | "@playwright/test": "^1.50.0", 14 | "@types/node": "^22.10.10" 15 | }, 16 | "scripts": { 17 | "test": "node tests/browser-automated-tests-playwright/index.js" 18 | }, 19 | "repository": { 20 | "type": "git", 21 | "url": "git+https://github.com/Subscribie/subscribie.git" 22 | }, 23 | "author": "", 24 | "license": "GPL-3.0-or-later", 25 | "bugs": { 26 | "url": "https://github.com/Subscribie/subscribie/issues" 27 | }, 28 | "homepage": "https://github.com/Subscribie/subscribie#readme" 29 | } 30 | -------------------------------------------------------------------------------- /pyproject.toml: -------------------------------------------------------------------------------- 1 | [project] 2 | name = "subscribie" 3 | version = "v0.1.181" 4 | description = "Collect recurring payments online - subscription payments collection automation" 5 | authors = [ 6 | { name = "Karma Computing", email = "subscribie@karmacomputing.co.uk" } 7 | ] 8 | dependencies = [ 9 | "graphviz", 10 | "graphlib", 11 | "wheel", 12 | "Flask", 13 | "flask_cors", 14 | "Flask-Reuploaded", 15 | "Flask-WTF", 16 | "email-validator", 17 | "Flask-Mail", 18 | "requests", 19 | "blinker", 20 | "stripe", 21 | "GitPython", 22 | "pathlib", 23 | "pytest", 24 | "Flask-SQLAlchemy", 25 | "Flask-Migrate", 26 | "Flask-Babel", 27 | "pyjwt[crypto]", 28 | "py-auth-header-parser", 29 | "pydantic", 30 | "backoff", 31 | "coloredlogs", 32 | "python-dateutil", 33 | "currency-symbols", 34 | "pycryptodome", 35 | "pycountry", 36 | "SQLAlchemy", 37 | "scipy", 38 | "pandas", 39 | "scikit-learn", 40 | "black", 41 | "strictyaml", 42 | "sentry-sdk[flask]>=2.14.0", 43 | ] 44 | readme = "README.md" 45 | requires-python = ">= 3.12" 46 | 47 | [project.scripts] 48 | 49 | [build-system] 50 | requires = ["hatchling"] 51 | build-backend = "hatchling.build" 52 | 53 | [tool.rye] 54 | managed = true 55 | dev-dependencies = [] 56 | 57 | [tool.hatch.metadata] 58 | allow-direct-references = true 59 | 60 | [tool.hatch.build.targets.wheel] 61 | packages = ["./"] 62 | -------------------------------------------------------------------------------- /rename-shop.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -x # Prints each command before executing it 3 | set -e # Exit the script immidietly if an error happens 4 | 5 | # Usage: 6 | # ./rename-shop.sh 7 | # 8 | 9 | OLD_DOMAIN=$1 10 | NEW_DOMAIN=$2 11 | NEW_INI=$NEW_DOMAIN".ini" 12 | PATH_TO_SITES=$3 13 | 14 | cd $PATH_TO_SITES 15 | 16 | # Check that the new-name does not already exist 17 | if [ -d $NEW_DOMAIN ] 18 | then 19 | echo "$NEW_DOMAIN already exists" 20 | exit 1 21 | fi 22 | 23 | # Rename the directory from old-name to new-name 24 | cp -r $OLD_DOMAIN $NEW_DOMAIN #rename directory 25 | mv $NEW_DOMAIN/$OLD_DOMAIN.ini $NEW_DOMAIN/$NEW_INI #rename ini file 26 | 27 | # Update the .ini file 28 | sed -i.bk "s/$OLD_DOMAIN/$NEW_DOMAIN/g" $NEW_DOMAIN/$NEW_INI 29 | # Update the .env file 30 | sed -i.bk "s/$OLD_DOMAIN/$NEW_DOMAIN/g" $NEW_DOMAIN/.env 31 | # Rename the .ini file, without this, the uwsigi server keeps the old config 32 | mv $NEW_DOMAIN/$NEW_INI $NEW_DOMAIN/$NEW_NAME.disabled 33 | mv $NEW_DOMAIN/$NEW_NAME.disabled $NEW_DOMAIN/$NEW_INI 34 | 35 | # delete old site (the data.db will stay because is being used) 36 | rm -r $OLD_DOMAIN 37 | -------------------------------------------------------------------------------- /run.sh: -------------------------------------------------------------------------------- 1 | . venv/bin/activate 2 | export FLASK_APP=subscribie 3 | export FLASK_DEBUG=1 4 | flask run 5 | -------------------------------------------------------------------------------- /runtests.sh: -------------------------------------------------------------------------------- 1 | #! /bin/bash 2 | . venv/bin/activate 3 | python -m pytest 4 | export PLAYWRIGHT_HEADLESS=false 5 | export PLAYWRIGHT_HOST=http://127.0.0.1:5000/ 6 | cd tests/browser-automated-tests-playwright 7 | npx playwright test 8 | cd - # go back to previous current working directory 9 | -------------------------------------------------------------------------------- /subscribie.wsgi: -------------------------------------------------------------------------------- 1 | import sys 2 | import os 3 | import logging 4 | 5 | PYTHON_LOG_LEVEL = os.getenv('PYTHON_LOG_LEVEL', logging.INFO) 6 | 7 | logging.basicConfig(level=PYTHON_LOG_LEVEL) 8 | 9 | def load(): 10 | path_inject = os.getenv('PYTHON_PATH_INJECT') 11 | if path_inject is not None: 12 | logging.info(f"Injecting python path {path_inject}") 13 | sys.path.insert(0, path_inject) 14 | 15 | load() 16 | 17 | from subscribie import create_app 18 | 19 | application = create_app() 20 | -------------------------------------------------------------------------------- /subscribie/TelegramHTTPHandler.py: -------------------------------------------------------------------------------- 1 | from logging.handlers import HTTPHandler 2 | import requests 3 | 4 | 5 | class TelegramHTTPHandler(HTTPHandler): 6 | def __init__(self, *args, **kwargs): 7 | super().__init__(*args, **kwargs) 8 | 9 | def emit(self, record): 10 | """ 11 | Emit log record to Telegram 12 | """ 13 | try: 14 | host = self.host 15 | if self.secure: 16 | scheme = "https://" 17 | else: 18 | scheme = "http://" 19 | url = self.url 20 | data = str(self.mapLogRecord(record))[ 21 | 0:4000 22 | ] # Truncate to max Telegram message size 23 | url = f"{url}{data}" 24 | requests.get(scheme + host + "/" + url) 25 | except Exception: 26 | self.handleError(record) 27 | -------------------------------------------------------------------------------- /subscribie/blueprints/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Subscribie/subscribie/4ba736e39a1e867186fee4e4ec28ae8b4b1d3a3e/subscribie/blueprints/__init__.py -------------------------------------------------------------------------------- /subscribie/blueprints/admin/static/Mailchimp-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Subscribie/subscribie/4ba736e39a1e867186fee4e4ec28ae8b4b1d3a3e/subscribie/blueprints/admin/static/Mailchimp-logo.png -------------------------------------------------------------------------------- /subscribie/blueprints/admin/static/box.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /subscribie/blueprints/admin/static/custom_style.css: -------------------------------------------------------------------------------- 1 | .kcBlue{ 2 | 3 | background-image: linear-gradient(to right, #6a11cb 0%, #2575fc 100%); 4 | 5 | } 6 | 7 | @media (max-width: 768px) { 8 | .section { 9 | padding: 0; 10 | } 11 | 12 | .table-scroll { 13 | display: inline-block; 14 | overflow-x: scroll; 15 | } 16 | 17 | .pagination { 18 | margin-bottom: 1rem; 19 | } 20 | } 21 | 22 | 23 | @media screen and (max-width:768px) { 24 | table.mobile-optimised { 25 | display:block; 26 | } 27 | table.mobile-optimised thead { 28 | display:none 29 | } 30 | table.mobile-optimised td { 31 | display: block; 32 | border: none; 33 | } 34 | table.mobile-optimised tbody, table.mobile-optimised tr { 35 | display:block 36 | } 37 | .mobile-optimised td:before { 38 | content:attr(data-th); 39 | display:block; 40 | font-weight:bold; 41 | margin:0 0 2px; 42 | color:#000; 43 | } 44 | .mobile-optimised tbody tr { 45 | border: 1px solid rgba(0,0,0,.125); 46 | margin-bottom:10px; 47 | } 48 | } 49 | 50 | 51 | textarea { 52 | padding: 10px; 53 | } 54 | -------------------------------------------------------------------------------- /subscribie/blueprints/admin/static/fb.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /subscribie/blueprints/admin/static/google_tag_manager.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Subscribie/subscribie/4ba736e39a1e867186fee4e4ec28ae8b4b1d3a3e/subscribie/blueprints/admin/static/google_tag_manager.jpg -------------------------------------------------------------------------------- /subscribie/blueprints/admin/static/insta.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /subscribie/blueprints/admin/static/js/app.js: -------------------------------------------------------------------------------- 1 | const check_input = document.querySelectorAll('.toggle'); 2 | const extra_fields = document.querySelectorAll('.extra_fields'); 3 | 4 | check_input.forEach((input, i) => { 5 | function showExtraFields() { 6 | if (input.checked == true) { 7 | extra_fields.item(i).style.display = 'block'; 8 | } else { 9 | extra_fields.item(i).style.display = 'none'; 10 | } 11 | } 12 | 13 | showExtraFields(); //show or don't show extra fields when page load 14 | 15 | input.addEventListener('click', () => { 16 | showExtraFields(); //show or don't show extra fields when checkbox checked or unchecked 17 | }); 18 | }); -------------------------------------------------------------------------------- /subscribie/blueprints/admin/static/packing_peanuts.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Subscribie/subscribie/4ba736e39a1e867186fee4e4ec28ae8b4b1d3a3e/subscribie/blueprints/admin/static/packing_peanuts.png -------------------------------------------------------------------------------- /subscribie/blueprints/admin/static/tawk_logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Subscribie/subscribie/4ba736e39a1e867186fee4e4ec28ae8b4b1d3a3e/subscribie/blueprints/admin/static/tawk_logo.png -------------------------------------------------------------------------------- /subscribie/blueprints/admin/static/tawk_property_id.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Subscribie/subscribie/4ba736e39a1e867186fee4e4ec28ae8b4b1d3a3e/subscribie/blueprints/admin/static/tawk_property_id.png -------------------------------------------------------------------------------- /subscribie/blueprints/admin/static/tick.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Subscription Builder - Success 5 | Created with Sketch. 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /subscribie/blueprints/admin/static/twitter.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /subscribie/blueprints/admin/templates/_formhelpers.html: -------------------------------------------------------------------------------- 1 | {% macro render_field(field) %} 2 |
{{ field.label }} 3 |
{{ field(**kwargs)|safe }} 4 | {% if field.errors %} 5 |
    6 | {% for error in field.errors %} 7 |
  • {{ error }}
  • 8 | {% endfor %} 9 |
10 | {% endif %} 11 |
12 | {% endmacro %} 13 | -------------------------------------------------------------------------------- /subscribie/blueprints/admin/templates/admin/forgot_password.html: -------------------------------------------------------------------------------- 1 | {% extends "admin/layout.html" %} 2 | {% block title %} Reset Password {% endblock %} 3 | 4 | {% block body %} 5 | 6 |

Reset your password

7 | 8 |
9 |
10 |

We will send you an email to reset your password.

11 |
12 | {{ form.csrf_token }} 13 | 14 | 17 |
18 |
19 |
20 | 21 | {% endblock body %} 22 | -------------------------------------------------------------------------------- /subscribie/blueprints/admin/templates/admin/index.html: -------------------------------------------------------------------------------- 1 | Yolo 2 | -------------------------------------------------------------------------------- /subscribie/blueprints/admin/templates/admin/logout.html: -------------------------------------------------------------------------------- 1 | {% extends "admin/layout.html" %} 2 | {% block title %} Login {% endblock %} 3 | 4 | {% block body %} 5 | 6 |

You have logged out

7 | 8 |
9 | {% if g.user %} 10 |

Click here to log back in.

11 | {% else %} 12 |

Click here to log back in.

13 | {% endif %} 14 |
15 | 16 | {% endblock body %} 17 | -------------------------------------------------------------------------------- /subscribie/blueprints/admin/templates/admin/option/add_option.html: -------------------------------------------------------------------------------- 1 | {% extends "admin/layout.html" %} 2 | {% block title %} Add Shop Admin{% endblock %} 3 | 4 | {% block body %} 5 | 6 |

Add Option

7 | 8 |
9 | 15 |
16 | 17 |
18 |
19 |
20 | 21 |

Add Option

22 |

Options are part of choice groups.

23 | 24 |
25 | 26 |
27 | {{ form.csrf_token }} 28 |
29 | 30 |
31 | 32 |
33 |
34 | 35 |
36 | 37 |
38 |
39 |
40 | 41 | 42 | 43 | {% endblock %} 44 | -------------------------------------------------------------------------------- /subscribie/blueprints/admin/templates/admin/reset_password.html: -------------------------------------------------------------------------------- 1 | {% extends "admin/layout.html" %} 2 | {% block title %} Login {% endblock %} 3 | 4 | {% block body %} 5 | 6 |

Set a new password

7 | 8 |
9 |
10 |
11 | {{ form.csrf_token }} 12 |

Please choose a new password:

13 | 14 | 15 | 18 |
19 |
20 |
21 | 22 | {% endblock body %} 23 | -------------------------------------------------------------------------------- /subscribie/blueprints/admin/templates/admin/uploads/upload_files.html: -------------------------------------------------------------------------------- 1 | {% extends "admin/layout.html" %} 2 | {% block title %} Add Shop Admin{% endblock %} 3 | 4 | {% block body %} 5 | 6 |

Upload files to your shop

7 | 8 |
9 | 14 |
15 | 16 |
17 |
18 |
19 | 20 |
21 |
22 |

Upload files to your shop

23 |

Support upload files:
24 | png, gif, jpg, jpeg, webp, mpeg, ogg, pdf, ms-powerpoint, ms-excel, msword

25 |
26 | {{ form.csrf_token }} 27 | 28 | 29 | 30 |
31 |
32 | 33 |
34 | 35 |
36 |
37 |
38 | 39 | 40 | 41 | {% endblock %} 42 | -------------------------------------------------------------------------------- /subscribie/blueprints/document/__init__.py: -------------------------------------------------------------------------------- 1 | import logging 2 | from flask import Blueprint, render_template, current_app 3 | from subscribie.models import Document 4 | import jinja2 5 | 6 | log = logging.getLogger(__name__) 7 | document_blueprint = Blueprint("document", __name__, template_folder="templates") 8 | 9 | 10 | @document_blueprint.route("/document/", methods=["GET"]) 11 | def show_document(document_uuid): 12 | """Show raw document""" 13 | document = Document.query.where(Document.uuid == document_uuid).first() 14 | if document is not None: 15 | if document.body is None: 16 | return f"The document '{document.name}' is empty" 17 | environment = jinja2.Environment( 18 | loader=jinja2.FileSystemLoader(str(current_app.config["THEME_PATH"])) 19 | ).from_string(document.body) 20 | 21 | return environment.render() 22 | else: 23 | return "Document not found", 404 24 | 25 | 26 | @document_blueprint.route("/documents", methods=["GET"]) 27 | def list_documents(): 28 | """List all documents""" 29 | documents = Document.query.all() 30 | 31 | if len(documents) != 0: 32 | return render_template("list_documents.html", documents=documents) 33 | else: 34 | return "There are no documents", 404 35 | -------------------------------------------------------------------------------- /subscribie/blueprints/document/templates/list_documents.html: -------------------------------------------------------------------------------- 1 | {% extends "admin/layout.html" %} 2 | 3 | 4 | {% block title %} 5 | {{ title }} 6 | {% endblock title %} 7 | 8 | {% block body %} 9 | 10 | 11 | 12 | 13 | 14 |

Documents

15 | 16 |
17 | Documents related to {{ company.name }} 18 |
19 | 20 |
21 |
22 |
23 | 28 |
29 |
30 |
31 | 32 | 33 | {% endblock body %} 34 | -------------------------------------------------------------------------------- /subscribie/blueprints/iframe/__init__.py: -------------------------------------------------------------------------------- 1 | import logging 2 | from flask import Blueprint, render_template, abort, request 3 | from jinja2 import TemplateNotFound 4 | from subscribie.auth import login_required 5 | 6 | log = logging.getLogger(__name__) 7 | module_iframe_embed = Blueprint("iframe", __name__, template_folder="templates") 8 | 9 | 10 | @module_iframe_embed.route("/show-iframe-embed") 11 | @login_required 12 | def get_iframe_embed(): 13 | """Set optimised title tags for your pages.""" 14 | log.info("Generating iframe") 15 | iframe = ( 16 | f'" 21 | ) 22 | 23 | try: 24 | return render_template("show-iframe-embed.html", iframe=iframe) 25 | except TemplateNotFound: 26 | abort(404) 27 | -------------------------------------------------------------------------------- /subscribie/blueprints/pages/templates/delete_page.html: -------------------------------------------------------------------------------- 1 | {% extends "admin/layout.html" %} 2 | {% block title %} {{ title }} {% endblock %} 3 | 4 | {% block body %} 5 | 6 |

Delete Page

7 | 8 |
9 | 14 |
15 | 16 |
17 |
18 |
19 | 20 |
21 |

Delete page

22 |

Delete the page below.

23 | 24 |
25 | 26 |
27 | 28 |
29 |
30 |
31 | {% endblock body %} 32 | -------------------------------------------------------------------------------- /subscribie/blueprints/pages/templates/edit_pages_list.html: -------------------------------------------------------------------------------- 1 | {% extends "admin/layout.html" %} 2 | {% block title %} {{ title }} {% endblock %} 3 | 4 | {% block body %} 5 | 6 |

Edit Pages

7 | 8 |
9 | 15 |
16 | 17 |
18 |
19 |
20 | 21 |
22 |

Edit Pages

23 |

Select a page to edit.

24 | 25 |
26 | {% for page in pages %} 27 | 28 | {{ page.page_name }} 29 | 30 | {% endfor %} 31 |
32 |
33 | 34 |
35 |
36 |
37 | 38 | {% endblock body %} 39 | -------------------------------------------------------------------------------- /subscribie/blueprints/pages/templates/module_pages_index.html: -------------------------------------------------------------------------------- 1 | {% extends "admin/layout.html" %} 2 | {% block title %} {{ title }} {% endblock %} 3 | 4 | {% block body %} 5 | 6 |

Pages

7 | 8 |
9 | 14 |
15 | 16 | 17 |
18 |
19 |
20 |
21 |

Add, Edit & Delete Pages

22 |
23 | Add page 24 | Edit page 25 | Delete page 26 | Set private pages 27 |
28 |
29 |
30 |
31 |
32 | {% endblock body %} 33 | -------------------------------------------------------------------------------- /subscribie/blueprints/seo/templates/set-page-title.html: -------------------------------------------------------------------------------- 1 | {% extends "admin/layout.html" %} 2 | {% block title %} {{ title }} {% endblock %} 3 | 4 | {% block body %} 5 | 6 |

Set page title

7 | 8 |
9 | 14 |
15 | 16 |
17 |
18 |
19 | 20 | {% with messages = get_flashed_messages() %} 21 | {% if messages %} 22 |
    23 | {% for message in messages %} 24 |
  • {{ message }}
  • 25 | {% endfor %} 26 |
27 | {% endif %} 28 | {% endwith %} 29 | 30 | 31 |
32 |
33 |
34 | 35 | 36 | 37 |
38 |
39 |
40 |
41 | 42 | {% endblock body %} 43 | -------------------------------------------------------------------------------- /subscribie/blueprints/subscriber/templates/subscriber/forgot_password.html: -------------------------------------------------------------------------------- 1 | {% extends "subscriber/layout.html" %} 2 | {% block title %} {{ _('Login') }} {% endblock %} 3 | 4 | {% block body %} 5 | 6 |

{{ _('Reset your password') }}

7 | 8 |
9 |
10 |

{{ _('We will send you an email to reset your password') }}.

11 |
12 | {{ form.csrf_token }} 13 | 14 | 17 |
18 |
19 |
20 | 21 | {% endblock body %} 22 | -------------------------------------------------------------------------------- /subscribie/blueprints/subscriber/templates/subscriber/list_files.html: -------------------------------------------------------------------------------- 1 | {% extends "subscriber/layout.html" %} 2 | {% block title %} {{ _('Account') }} - {{ company.name }} {% endblock %} 3 | 4 | {% block body %} 5 | 6 |

{{ _('Uploaded files') }}

7 | 8 |
9 | 12 |
13 | 14 |
15 |
16 |
17 | 18 |

{{ _('Uploaded Files') }}

19 |

{{ _('Files listed here will be available to your subscribers when they login') }}.

20 | 25 | 26 | 27 | 28 | 29 | 30 | {% for file in files %} 31 | 32 | 33 | 34 | 35 | {% endfor %} 36 | 37 |
{{ _('File name') }}{{ _('Created at') }}
{{ file.file_name }}{{ file.created_at.strftime('%d/%m/%Y %H:%M') }}
38 | 39 |
40 |
41 |
42 | 43 | 44 | 45 | {% endblock %} 46 | -------------------------------------------------------------------------------- /subscribie/blueprints/subscriber/templates/subscriber/login.html: -------------------------------------------------------------------------------- 1 | {% extends "subscriber/layout.html" %} 2 | {% block title %} {{ _('Login') }} {% endblock %} 3 | 4 | {% block body %} 5 | 6 |

{{ _('Customer Login') }}

7 | 8 |
9 |
10 |
11 | {{ form.csrf_token }} 12 | 13 | 14 | 15 | 18 | {{ _('Forgot your password') }}?
19 |
20 | {{ _('Or, are you a shop admin needing help logging into your shop?') }} 21 |
22 |
23 |
24 | 25 | {% endblock body %} 26 | -------------------------------------------------------------------------------- /subscribie/blueprints/subscriber/templates/subscriber/reset_password.html: -------------------------------------------------------------------------------- 1 | {% extends "subscriber/layout.html" %} 2 | {% block title %} {{ _('Change password') }} {% endblock %} 3 | 4 | {% block body %} 5 | 6 |

{{ _('Set a new password') }}

7 | 8 |
9 |
10 |
11 | {{ form.csrf_token }} 12 |

{{ _('Please choose a new password') }}:

13 | 14 | 15 | 18 |
19 |
20 |
21 | 22 | {% endblock body %} 23 | -------------------------------------------------------------------------------- /subscribie/blueprints/subscriber/templates/subscriber/update_choices.html: -------------------------------------------------------------------------------- 1 | {% extends "subscriber/layout.html" %} 2 | {% block title %} {{ _('Update Choices') }} - {{ company.name }} {% endblock %} 3 | 4 | {% block body %} 5 | 6 |
7 |
8 | 9 |

{{ _('Choose your options') }}

10 | 11 |

{{ _('Your') }} {{ plan.title }} {{ _('plan has the following options') }}

12 | 13 |
14 | 15 | {% for choice_group in plan.choice_groups %} 16 |
17 | {{ choice_group.title }} ({{ choice_group.options|count }} {{ _('options') }}) {{ _('choose one') }}: 18 |
    19 | {% for option in choice_group.options %} 20 |
  • 21 | 22 | 23 |
  • 24 | {% endfor %} 25 |
26 |
27 | {% endfor %} 28 | 29 | 30 |
31 | 32 |
33 |
34 | 35 | {% endblock %} 36 | -------------------------------------------------------------------------------- /subscribie/custom_pages/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Subscribie/subscribie/4ba736e39a1e867186fee4e4ec28ae8b4b1d3a3e/subscribie/custom_pages/.gitkeep -------------------------------------------------------------------------------- /subscribie/database.py: -------------------------------------------------------------------------------- 1 | from flask_sqlalchemy import SQLAlchemy 2 | 3 | database = SQLAlchemy() 4 | -------------------------------------------------------------------------------- /subscribie/emails/donation.jinja2.html: -------------------------------------------------------------------------------- 1 |

Hello {{ first_name or ''}},

2 | 3 |

Thanks for your Donations to {{ company_name or '' }}.

4 | 5 |

With your support we will be able to help others

6 | 7 |

Sincerly,{{ company_name or '' }}.

8 | -------------------------------------------------------------------------------- /subscribie/emails/subscriber-payment-failed-notification.jinja2.html: -------------------------------------------------------------------------------- 1 | Hi {{ subscriber_first_name or '' }},
2 | 3 |

This is a message from {{ company.name }}.

4 | 5 |

The system says a payment collection failed.

6 | 7 |

The system gave the following reason: "{{ failure_message }} / {{ failure_code }}."

8 | 9 |

Please could you log into your account where you can retry payments (under 'Failed Invoices').

10 | 11 |

If you need to, you can also change your payment details (under 'Payment Settings').

12 | 13 |

Thank you!

14 | -------------------------------------------------------------------------------- /subscribie/emails/subscriber-reset-password.jinja2.html: -------------------------------------------------------------------------------- 1 |

Reset your password - {{ company.name }}

2 | 3 |

Please use the following link to reset your password:

4 | 5 | Reset my password -------------------------------------------------------------------------------- /subscribie/emails/update-choices.jinja2.html: -------------------------------------------------------------------------------- 1 |

{{ company.name }} - Update Choices

2 | 3 |

Your subscription has options which you can choose from.

4 | 5 |

Please use the following link to set your options:

6 | 7 | Login & update my options -------------------------------------------------------------------------------- /subscribie/emails/user-new-subscriber-notification.jinja2.html: -------------------------------------------------------------------------------- 1 | You have a new subscriber!
2 | 3 | {% if subscriber_email %} 4 | Email: {{ subscriber_email }}
5 | {% endif %} 6 | 7 | {% if subscription %} 8 | Name: {{ subscription.person.given_name }} {{ subscription.person.family_name }}
9 | {% endif %} -------------------------------------------------------------------------------- /subscribie/emails/user-reset-password.jinja2.html: -------------------------------------------------------------------------------- 1 |

Reset your password - {{ company.name }}

2 | 3 |

Please use the following link to reset your password:

4 | 5 | Reset my password -------------------------------------------------------------------------------- /subscribie/emails/welcome.jinja2.html: -------------------------------------------------------------------------------- 1 |

Hello {{ first_name or ''}},

2 | 3 |

Welcome to {{ company_name or '' }}.

4 | 5 |

Plan name: {{ plan.title }}

6 | 7 | 8 | {% if plan.requirements.instant_payment %} 9 |

Upfront payment: {{ plan.showSellPrice() }}

10 | {% endif %} 11 | 12 | {% if plan.requirements.subscription %} 13 |

Interval: {{ plan.interval_unit }}

14 |

Amount: {{ plan.showIntervalAmount() }} 15 | {% if first_charge_date %} 16 |

Your first payment will be taken on: {{ first_charge_date }}

17 | {% endif %} 18 |

Each payment will be on the same day {{ plan.interval_unit }}

19 | {% endif %} 20 | 21 | 22 |

You can login to manage your account at: 23 | My account 24 |

25 | 26 |

Once again welcome to {{ company_name }}.

27 | -------------------------------------------------------------------------------- /subscribie/schemas/__init__.py: -------------------------------------------------------------------------------- 1 | from .schemas import Plan, PlanCreate, PlanRequirementsCreate, PlanUpdate, Shop, Company 2 | -------------------------------------------------------------------------------- /subscribie/static/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Subscribie/subscribie/4ba736e39a1e867186fee4e4ec28ae8b4b1d3a3e/subscribie/static/.gitkeep -------------------------------------------------------------------------------- /subscribie/tasks.py: -------------------------------------------------------------------------------- 1 | import logging 2 | import queue 3 | import threading 4 | from flask import current_app 5 | 6 | log = logging.getLogger(__name__) 7 | 8 | task_queue = queue.Queue() 9 | 10 | 11 | # Usage: 12 | """ 13 | task_queue.put(lambda: print("long running task")) 14 | """ 15 | 16 | 17 | def fifo_queue(): 18 | def worker(): 19 | while True: 20 | item = task_queue.get() 21 | log.info("Working on task from task_queue") 22 | try: 23 | item() # Execute task 24 | task_queue.task_done() 25 | log.info("Finished working on task from task_queue") 26 | except Exception as e: 27 | log.error(f"Error running task: {e}") 28 | 29 | # turn-on the worker thread 30 | threading.Thread(target=worker, daemon=True).start() 31 | 32 | # block until all tasks are done 33 | task_queue.join() 34 | 35 | 36 | thread = threading.Thread(target=fifo_queue) 37 | thread.start() 38 | 39 | 40 | def background_task(f): 41 | def bg_f(*a, **kw): 42 | app = current_app._get_current_object() 43 | kw["app"] = app # inject flask app for app context 44 | 45 | threading.Thread(target=f, args=a, kwargs=kw).start() 46 | 47 | return bg_f 48 | -------------------------------------------------------------------------------- /subscribie/themes/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Subscribie/subscribie/4ba736e39a1e867186fee4e4ec28ae8b4b1d3a3e/subscribie/themes/.gitkeep -------------------------------------------------------------------------------- /subscribie/themes/theme-builder/builder/_formhelpers.html: -------------------------------------------------------------------------------- 1 | {% macro render_field(field) %} 2 |
{{ field.label }} 3 |
{{ field(**kwargs)|safe }} 4 | {% if field.errors %} 5 |
    6 | {% for error in field.errors %} 7 |
  • {{ error }}
  • 8 | {% endfor %} 9 |
10 | {% endif %} 11 |
12 | {% endmacro %} 13 | -------------------------------------------------------------------------------- /subscribie/themes/theme-builder/builder/changed.html: -------------------------------------------------------------------------------- 1 | dfsok 2 | -------------------------------------------------------------------------------- /subscribie/themes/theme-builder/builder/changes.html: -------------------------------------------------------------------------------- 1 | Testing 2 | -------------------------------------------------------------------------------- /subscribie/themes/theme-builder/builder/refund-policy.html: -------------------------------------------------------------------------------- 1 | {% extends "layout.html" %} 2 | {% block title %} Refund Policy Subscribie {% endblock %} 3 | 4 | {% block body %} 5 | 6 |
7 | 8 |
9 |

Cancellation and Termination

10 | Refund Policy 11 |
12 | 13 |
    14 |
  1. You may close your Account at any time by emailing hello@subscriptionwebsitebuilder.co.uk and following the instructions given in our response.
  2. 15 |
  3. Once Closed: 16 |
      17 |
    1. We will cease providing you the Services and they will no longer be accessible
    2. 18 |
    3. You will not be entitled to any refunds of any Fees, pro rata or otherwise.
    4. 19 |
    5. Your online store will be taken offline
    6. 20 |
    21 |
  4. 22 |
  5. 23 | We reserve the right to modify or terminate the Service or your Account without notice at any time. For example, upgrades, security , these examples are non-exhaustive 24 |
  6. 25 |
26 | 27 | Start now 29 | 31 | or be inspired 32 | 33 | 34 |
35 | 36 | {% endblock %} 37 | -------------------------------------------------------------------------------- /subscribie/themes/theme-builder/builder/shops.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | {% for shop in shops %} 4 | {% if 'prodtest' not in shop['site_url'] %} 5 | 6 | 7 | 8 | 9 | {% endif %} 10 | {% endfor %} 11 | 12 |
{{ shop['email'] }}{{ shop['site_url'] }}
13 | -------------------------------------------------------------------------------- /subscribie/themes/theme-builder/builder/total.html: -------------------------------------------------------------------------------- 1 | beter 2 | 3 | -------------------------------------------------------------------------------- /subscribie/themes/theme-builder/static/credit.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Subscribie/subscribie/4ba736e39a1e867186fee4e4ec28ae8b4b1d3a3e/subscribie/themes/theme-builder/static/credit.png -------------------------------------------------------------------------------- /subscribie/themes/theme-builder/static/feature1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Subscribie/subscribie/4ba736e39a1e867186fee4e4ec28ae8b4b1d3a3e/subscribie/themes/theme-builder/static/feature1.png -------------------------------------------------------------------------------- /subscribie/themes/theme-builder/static/feature2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Subscribie/subscribie/4ba736e39a1e867186fee4e4ec28ae8b4b1d3a3e/subscribie/themes/theme-builder/static/feature2.png -------------------------------------------------------------------------------- /subscribie/themes/theme-builder/static/feature3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Subscribie/subscribie/4ba736e39a1e867186fee4e4ec28ae8b4b1d3a3e/subscribie/themes/theme-builder/static/feature3.png -------------------------------------------------------------------------------- /subscribie/themes/theme-builder/static/google-signin-component.js: -------------------------------------------------------------------------------- 1 | // Define cusom element 2 | // See https://developer.mozilla.org/en-US/docs/Web/Web_Components/Using_templates_and_slots 3 | customElements.define('google-signin', 4 | class extends HTMLElement { 5 | constructor() { 6 | super(); 7 | let template = document.getElementById('google-signin-template'); 8 | let templateContent = template.content; 9 | 10 | const shadowRoot = this.attachShadow({mode: 'open'}) 11 | .appendChild(templateContent.cloneNode(true)); 12 | } 13 | } 14 | ); 15 | -------------------------------------------------------------------------------- /subscribie/themes/theme-builder/static/google-signin-template.css: -------------------------------------------------------------------------------- 1 | .btn-google { 2 | padding: 0.5rem 2.5rem; 3 | width: 100%; 4 | text-decoration: none; 5 | display: block; 6 | border-radius: 0.25rem; 7 | color: #555; 8 | text-align: center; 9 | box-sizing:border-box; 10 | background-position: left center; 11 | background-repeat: no-repeat; 12 | background-color: white; 13 | background-image: url(./google-icon.svg); 14 | 15 | } 16 | 17 | .btn-google:hover { 18 | background-color: #dfdfdf; 19 | } 20 | 21 | .btn-google--lg { 22 | font-size: 1.5rem; 23 | background-size: 4rem 4rem; 24 | } 25 | 26 | .btn-google--border { 27 | border: 1px solid #ccc; 28 | } 29 | 30 | -------------------------------------------------------------------------------- /subscribie/themes/theme-builder/static/google_tag_manager.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Subscribie/subscribie/4ba736e39a1e867186fee4e4ec28ae8b4b1d3a3e/subscribie/themes/theme-builder/static/google_tag_manager.jpg -------------------------------------------------------------------------------- /subscribie/themes/theme-builder/static/iconfinder_Circled_Facebook_svg_5279111.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Subscribie/subscribie/4ba736e39a1e867186fee4e4ec28ae8b4b1d3a3e/subscribie/themes/theme-builder/static/iconfinder_Circled_Facebook_svg_5279111.png -------------------------------------------------------------------------------- /subscribie/themes/theme-builder/static/iconfinder_Circled_Instagram_svg_5279112.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Subscribie/subscribie/4ba736e39a1e867186fee4e4ec28ae8b4b1d3a3e/subscribie/themes/theme-builder/static/iconfinder_Circled_Instagram_svg_5279112.png -------------------------------------------------------------------------------- /subscribie/themes/theme-builder/static/iconfinder_Circled_Twitter_svg_5279123.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Subscribie/subscribie/4ba736e39a1e867186fee4e4ec28ae8b4b1d3a3e/subscribie/themes/theme-builder/static/iconfinder_Circled_Twitter_svg_5279123.png -------------------------------------------------------------------------------- /subscribie/themes/theme-builder/static/meta-thumbnail.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Subscribie/subscribie/4ba736e39a1e867186fee4e4ec28ae8b4b1d3a3e/subscribie/themes/theme-builder/static/meta-thumbnail.png -------------------------------------------------------------------------------- /subscribie/themes/theme-builder/static/no-credit.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Subscribie/subscribie/4ba736e39a1e867186fee4e4ec28ae8b4b1d3a3e/subscribie/themes/theme-builder/static/no-credit.png -------------------------------------------------------------------------------- /subscribie/themes/theme-builder/static/photos/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Subscribie/subscribie/4ba736e39a1e867186fee4e4ec28ae8b4b1d3a3e/subscribie/themes/theme-builder/static/photos/.gitkeep -------------------------------------------------------------------------------- /subscribie/themes/theme-builder/static/right_top.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Subscribie/subscribie/4ba736e39a1e867186fee4e4ec28ae8b4b1d3a3e/subscribie/themes/theme-builder/static/right_top.png -------------------------------------------------------------------------------- /subscribie/themes/theme-builder/static/snackbar.min.css: -------------------------------------------------------------------------------- 1 | .snackbar-container{transition:all .5s ease;transition-property:top,right,bottom,left,opacity;font-family:Roboto,sans-serif;font-size:14px;min-height:14px;background-color:#070b0e;position:fixed;display:flex;justify-content:space-between;align-items:center;color:#fff;line-height:22px;padding:18px 24px;bottom:-100px;top:-100px;opacity:0;z-index:9999}.snackbar-container .action{background:inherit;display:inline-block;border:none;font-size:inherit;text-transform:uppercase;color:#4caf50;margin:0 0 0 24px;padding:0;min-width:min-content;cursor:pointer}@media (min-width:640px){.snackbar-container{min-width:288px;max-width:568px;display:inline-flex;border-radius:2px;margin:24px}}@media (max-width:640px){.snackbar-container{left:0;right:0;width:100%}}.snackbar-pos.bottom-center{top:auto!important;bottom:0;left:50%;transform:translate(-50%,0)}.snackbar-pos.bottom-left{top:auto!important;bottom:0;left:0}.snackbar-pos.bottom-right{top:auto!important;bottom:0;right:0}.snackbar-pos.top-left{bottom:auto!important;top:0;left:0}.snackbar-pos.top-center{bottom:auto!important;top:0;left:50%;transform:translate(-50%,0)}.snackbar-pos.top-right{bottom:auto!important;top:0;right:0}@media (max-width:640px){.snackbar-pos.bottom-center,.snackbar-pos.top-center{left:0;transform:none}} -------------------------------------------------------------------------------- /subscribie/themes/theme-builder/static/start-a-subscription-website-example.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Subscribie/subscribie/4ba736e39a1e867186fee4e4ec28ae8b4b1d3a3e/subscribie/themes/theme-builder/static/start-a-subscription-website-example.png -------------------------------------------------------------------------------- /subscribie/themes/theme-builder/static/subscription-embed-widgetpng.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Subscribie/subscribie/4ba736e39a1e867186fee4e4ec28ae8b4b1d3a3e/subscribie/themes/theme-builder/static/subscription-embed-widgetpng.png -------------------------------------------------------------------------------- /subscribie/themes/theme-builder/static/tick.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Subscription Builder - Success 5 | Created with Sketch. 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /subscribie/themes/theme-jesmond/jesmond/errors/ui-error.html: -------------------------------------------------------------------------------- 1 | {% extends "layout.html" %} 2 | 3 | {% block body %} 4 | 9 | 10 | {% endblock %} -------------------------------------------------------------------------------- /subscribie/themes/theme-jesmond/static/box.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /subscribie/themes/theme-jesmond/static/fb.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /subscribie/themes/theme-jesmond/static/google_tag_manager.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Subscribie/subscribie/4ba736e39a1e867186fee4e4ec28ae8b4b1d3a3e/subscribie/themes/theme-jesmond/static/google_tag_manager.jpg -------------------------------------------------------------------------------- /subscribie/themes/theme-jesmond/static/insta.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /subscribie/themes/theme-jesmond/static/packing_peanuts.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Subscribie/subscribie/4ba736e39a1e867186fee4e4ec28ae8b4b1d3a3e/subscribie/themes/theme-jesmond/static/packing_peanuts.png -------------------------------------------------------------------------------- /subscribie/themes/theme-jesmond/static/tawk_logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Subscribie/subscribie/4ba736e39a1e867186fee4e4ec28ae8b4b1d3a3e/subscribie/themes/theme-jesmond/static/tawk_logo.png -------------------------------------------------------------------------------- /subscribie/themes/theme-jesmond/static/tawk_property_id.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Subscribie/subscribie/4ba736e39a1e867186fee4e4ec28ae8b4b1d3a3e/subscribie/themes/theme-jesmond/static/tawk_property_id.png -------------------------------------------------------------------------------- /subscribie/themes/theme-jesmond/static/tick.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Subscription Builder - Success 5 | Created with Sketch. 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /subscribie/themes/theme-jesmond/static/twitter.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /subscribie/translations/de/LC_MESSAGES/messages.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Subscribie/subscribie/4ba736e39a1e867186fee4e4ec28ae8b4b1d3a3e/subscribie/translations/de/LC_MESSAGES/messages.mo -------------------------------------------------------------------------------- /subscribie/translations/es/LC_MESSAGES/messages.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Subscribie/subscribie/4ba736e39a1e867186fee4e4ec28ae8b4b1d3a3e/subscribie/translations/es/LC_MESSAGES/messages.mo -------------------------------------------------------------------------------- /subscribie/translations/fr/LC_MESSAGES/messages.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Subscribie/subscribie/4ba736e39a1e867186fee4e4ec28ae8b4b1d3a3e/subscribie/translations/fr/LC_MESSAGES/messages.mo -------------------------------------------------------------------------------- /subscribie/translations/hr/LC_MESSAGES/messages.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Subscribie/subscribie/4ba736e39a1e867186fee4e4ec28ae8b4b1d3a3e/subscribie/translations/hr/LC_MESSAGES/messages.mo -------------------------------------------------------------------------------- /subscribie/uploads/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Subscribie/subscribie/4ba736e39a1e867186fee4e4ec28ae8b4b1d3a3e/subscribie/uploads/.gitkeep -------------------------------------------------------------------------------- /test.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -exou 4 | 5 | . .venv/bin/activate 6 | python -m pytest 7 | -------------------------------------------------------------------------------- /tests/amber.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | file_format_version: 1 3 | public_key: 8476e2922afdc8945e2f44397b55eb174561b60e73066a0c913fc932c5e83342 4 | secrets: 5 | - name: KEEP_SHOPS_LIST 6 | sha256: 296a9b19f60ee6fdb6e18b5cecbbf0ba42ce5a17b27d72f1424739133bdec79c 7 | cipher: ae434df42ed4fd10c631136de57d6b3f8bff71d9a0717073fd75c3f6857f856d825031322486e64a18f7da022080e377ea42d3d777f35cf7bf16cdca37fde5fcca0f923d9a251085b441e596841a7edb5e5b7c9fdff0895d5e5eea157783adb37dedf0c4fb65b20b838aa8376621ffa0ae516c2e7870f1fc7feb95 8 | - name: PYTHONUNBUFFERED 9 | sha256: 6b86b273ff34fce19d6b804eff5a3f5747ada4eaa22f1d49c01e52ddb7875b4b 10 | cipher: 2e710eda7dee482e2456cd256153d65b10eee45e9046317a406587fe517a114fe92892583c6e3f6980474c345458971db7 11 | -------------------------------------------------------------------------------- /tests/browser-automated-tests-playwright/.env.example: -------------------------------------------------------------------------------- 1 | PLAYWRIGHT_HEADLESS=false 2 | PLAYWRIGHT_HOST=http://127.0.0.1:5000/ 3 | PLAYWRIGHT_SLOWMO=500 4 | 5 | PLAWRIGHT_MAX_RETRIES=1 6 | # GLOBAL EMAIL SETTINGS # 7 | IMAP_SEARCH_UNSEEN="1" 8 | IMAP_SEARCH_SINCE_DATE="21-Aug-2022" 9 | EMAIL_SEARCH_API_HOST="email-search-api.example.com" 10 | 11 | # SHOP OWNER EMAIL SETTINGS # 12 | SHOP_OWNER_EMAIL_HOST="email.example.co.uk" 13 | SHOP_OWNER_EMAIL_USER="alice@example.co.uk" 14 | SHOP_OWNER_MAGIC_LOGIN_IMAP_SEARCH_SUBJECT="Subscribie Magic Login" 15 | SHOP_OWNER_EMAIL_PASSWORD="secret" 16 | 17 | # SUBSCRIBER EMAIL SEttingS # 18 | SUBSCRIBER_EMAIL_HOST="email.example.co.uk" 19 | SUBSCRIBER_EMAIL_USER="test@example.co.uk" 20 | SUBSCRIBER_EMAIL_PASSWORD="secret" 21 | RESET_PASSWORD_IMAP_SEARCH_SUBJECT="Password Reset" 22 | -------------------------------------------------------------------------------- /tests/browser-automated-tests-playwright/delete-connect-account-id.js: -------------------------------------------------------------------------------- 1 | // global-setup.js 2 | const { test, expect, chromium } = require('@playwright/test'); 3 | 4 | module.exports = async config => { 5 | const { baseURL, storageState } = config.projects[0].use; 6 | const browser = await chromium.launch(); 7 | const page = await browser.newPage(); 8 | await page.goto(baseURL + '/auth/login'); 9 | await page.fill('#email', 'admin@example.com'); 10 | await page.fill('#password', 'password'); 11 | await page.click('#login'); 12 | 13 | const content = await page.textContent('.card-title') 14 | expect(content === 'Checklist'); // If we see "Checklist", we're logged in to admin 15 | 16 | await new Promise(x => setTimeout(x, 5000)); 17 | await page.goto(baseURL + '/admin/delete-connect-account'); 18 | console.log('deleting-connect-account-id'); 19 | await new Promise(x => setTimeout(x, 2000)); //2 secconds 20 | await page.goto(baseURL + 'admin/dashboard') 21 | const connect_to_stripe = await page.textContent('text="Review Stripe"'); 22 | expect (connect_to_stripe == 'Review Stripe'); 23 | console.log('stripe is not connected'); 24 | 25 | await page.context().storageState({ path: storageState }); 26 | await browser.close(); 27 | }; 28 | -------------------------------------------------------------------------------- /tests/browser-automated-tests-playwright/e2e/1005_subscriber_terms_and_condition_check_test.spec.js: -------------------------------------------------------------------------------- 1 | const { test, expect } = require('@playwright/test'); 2 | const { set_test_name_cookie } = require('./features/set_test_name_cookie'); 3 | const TEST_SUBSCRIBER_EMAIL_USER = process.env.TEST_SUBSCRIBER_EMAIL_USER; 4 | 5 | 6 | test('@1005@subscriber @1005_subscriber_terms_and_condition_check_test', async ({ page }) => { 7 | 8 | await set_test_name_cookie(page, "@1005_subscriber_terms_and_condition_check_test"); 9 | await page.goto("/auth/logout"); 10 | await page.goto("/account/logout"); 11 | //login in as subscriber 12 | await page.goto("/account/login"); 13 | await page.fill('#email', TEST_SUBSCRIBER_EMAIL_USER); 14 | await page.fill('#password', 'password'); 15 | await page.click('text=Sign In'); 16 | await page.textContent('.card-title') === "Your subscriptions"; 17 | console.log("Logged in as a subscriber"); 18 | //check Terms and Conditions is attached 19 | await page.goto('/account/subscriptions'); 20 | await page.textContent('.card-title') === "Your subscriptions"; 21 | await page.locator('text=Terms and Conditions'); 22 | await new Promise(x => setTimeout(x, 1000)); 23 | // check the terms and conditions page 24 | await page.click("text=Terms and Conditions"); 25 | await page.locator("testing"); 26 | console.log("terms and condition are shown in the subscriber side"); 27 | }); 28 | -------------------------------------------------------------------------------- /tests/browser-automated-tests-playwright/e2e/1065_shop_owner_enabling_donations.spec.js: -------------------------------------------------------------------------------- 1 | const { admin_login } = require('./features/admin_login'); 2 | const { set_test_name_cookie } = require('./features/set_test_name_cookie'); 3 | 4 | const { test, expect } = require('@playwright/test'); 5 | //Subscribie enable donation test 6 | test("@1065 @1065_shop_owner_enabling_donations", async ({ page }) => { 7 | console.log("enabling Donations..."); 8 | await admin_login(page); 9 | await set_test_name_cookie(page, "@1065_shop_owner_enabling_donations"); 10 | // Go to enable donations 11 | await page.goto('/admin/donate-enabled-settings'); 12 | const donations_settings = await page.content("text=Donations Settings"); 13 | expect(donations_settings === "Donations Settings"); 14 | 15 | await page.click('text="Enable"'); 16 | await page.click('text="Save"'); 17 | await page.textContent('.alert-heading') === "Notification"; 18 | 19 | //Check the admin dashboard if donors settings are enabled in the dashboard 20 | await page.goto('/admin/dashboard'); 21 | const donations_in_dashboard = await page.content("text=Donations to your shop"); 22 | expect(donations_in_dashboard === "Donations to your shop"); 23 | 24 | await page.goto('/'); 25 | const donation_heading = await page.content("text=Donate"); 26 | expect(donation_heading === "Donate"); 27 | }); 28 | -------------------------------------------------------------------------------- /tests/browser-automated-tests-playwright/e2e/1333_shop_owner_add_free_text_question.spec.js: -------------------------------------------------------------------------------- 1 | import { test, expect } from '@playwright/test'; 2 | const { admin_login } = require('./features/admin_login'); 3 | const { set_test_name_cookie } = require('./features/set_test_name_cookie'); 4 | 5 | const testName = "@1333_shop_owner_add_free_text_question"; 6 | 7 | test(testName, async ({ page }) => { 8 | await admin_login(page); 9 | await set_test_name_cookie(page, testName); 10 | await page.goto("/admin/dashboard"); 11 | await page.getByRole('button', { name: 'Questions (Simple Forms)' }).click(); 12 | await page.getByRole('link', { name: 'Add / Edit / Delete Questions' }).click(); 13 | await page.getByRole('link', { name: 'Add Question' }).click(); 14 | await page.getByRole('textbox').click(); 15 | await page.getByRole('textbox').fill('Where did you hear about us?'); 16 | await page.getByRole('button', { name: 'Save' }).click(); 17 | await page.getByRole('cell', { name: 'Where did you hear about us?' }).first().click(); 18 | }); -------------------------------------------------------------------------------- /tests/browser-automated-tests-playwright/e2e/212_shop_owner_slogan_creation.spec.js: -------------------------------------------------------------------------------- 1 | const { test, expect } = require('@playwright/test'); 2 | const { admin_login } = require('./features/admin_login'); 3 | const { set_test_name_cookie } = require('./features/set_test_name_cookie'); 4 | 5 | //Subscribie tests 6 | test("@212@shop-owner@slogan creation @212_shop_owner_slogan_creation", async ({ page }) => { 7 | await admin_login(page); 8 | await set_test_name_cookie(page, "@212_shop_owner_slogan_creation"); 9 | console.log("checking if slogan is already created..."); 10 | await page.goto('/'); 11 | let slogan_exists = await page.evaluate(() => document.body.textContent); 12 | if (slogan_exists === 'this is a slogan') { 13 | console.log("slogan already created, exiting test"); 14 | test.skip(); 15 | } 16 | // Go to edit plan page 17 | await page.goto('/admin/edit'); 18 | 19 | //edit slogan 20 | await page.fill("input[name='slogan']", 'this is a slogan'); 21 | await page.click("text=Hair Gel"); 22 | await page.click('text="Save"'); 23 | 24 | //verify home page plan creation 25 | await page.goto("/"); 26 | await page.reload(); 27 | const slogan_created = await page.textContent('text=this is a slogan'); 28 | expect(slogan_created === 'this is a slogan'); 29 | }); -------------------------------------------------------------------------------- /tests/browser-automated-tests-playwright/e2e/387_shop_owner_change_shop_colour.spec.js: -------------------------------------------------------------------------------- 1 | 2 | const { test, expect } = require('@playwright/test'); 3 | const { admin_login } = require('./features/admin_login'); 4 | const { set_test_name_cookie } = require('./features/set_test_name_cookie'); 5 | 6 | test("@387@shop-owner@change_shop_colour @387_shop_owner_change_shop_colour", async ({ page }) => { 7 | await admin_login(page); 8 | await set_test_name_cookie(page, "@387_shop_owner_change_shop_colour"); 9 | 10 | console.log("changing shop colour..."); 11 | // Go to style your shop 12 | await page.goto('/style/style-shop'); 13 | const style_shop = await page.content("text=Style Your Shop"); 14 | expect(style_shop === "Style Your Shop"); 15 | 16 | await page.fill('input[name="primary"]', "0b5394"); 17 | await new Promise(x => setTimeout(x, 3000)); 18 | await page.fill('input[name="font"]', "000000"); 19 | await page.click('text="Save"'); 20 | 21 | // check if its changed 22 | console.log("checking if shop style has changed"); 23 | await page.goto('/style/style-shop'); 24 | await page.content('input[style="background-color: rgb(11, 83, 148); color: white;"]'); 25 | 26 | //screenshot of the changed style shop; 27 | await page.goto('/'); 28 | }); 29 | -------------------------------------------------------------------------------- /tests/browser-automated-tests-playwright/e2e/463_shop_owner_adding_vat.spec.js: -------------------------------------------------------------------------------- 1 | 2 | const { test, expect } = require('@playwright/test'); 3 | const { admin_login } = require('./features/admin_login'); 4 | const { set_test_name_cookie } = require('./features/set_test_name_cookie'); 5 | 6 | 7 | test("@463@shop-owner@adding VAT @463_shop_owner_adding_vat", async ({ page }) => { 8 | await admin_login(page); 9 | await set_test_name_cookie(page, "@463_shop_owner_adding_vat"); 10 | console.log("enabling VAT..."); 11 | // Go to style your shop 12 | await page.goto('/admin/vat-settings'); 13 | const VAT_settings = await page.content("text=VAT Settings"); 14 | expect(VAT_settings === "VAT Settings"); 15 | 16 | await page.click('text="Yes. Charge VAT at 20%"'); 17 | await new Promise(x => setTimeout(x, 1000)); 18 | await page.click('text="Save"'); 19 | await page.textContent('.alert-heading') === "Notification"; 20 | 21 | }); 22 | -------------------------------------------------------------------------------- /tests/browser-automated-tests-playwright/e2e/704_shop_owner_magic_login_receives_email.js: -------------------------------------------------------------------------------- 1 | const { test, expect } = require('@playwright/test'); 2 | const checkShopOwnerLogin = require('./checkShopOwnerLogin.js'); 3 | 4 | const SHOP_OWNER_LOGIN_URL = process.env.SHOP_OWNER_LOGIN_URL 5 | const SHOP_OWNER_EMAIL = process.env.SHOP_OWNER_EMAIL_USER 6 | 7 | test('@704@shop_owner@magic login receives email', async ({ page }) => { 8 | await page.goto(SHOP_OWNER_LOGIN_URL); 9 | await page.fill('#email', SHOP_OWNER_EMAIL); 10 | await page.click('#login'); 11 | await new Promise(r => setTimeout(r, 5000)); 12 | checkShopOwnerLogin.checkShopOwnerLogin(); 13 | console.log(checkShopOwnerLogin.magic_login_url); 14 | await new Promise(r => setTimeout(r, 5000)); 15 | await page.goto(checkShopOwnerLogin.magic_login_url); 16 | await new Promise(r => setTimeout(r, 5000)); 17 | }); 18 | -------------------------------------------------------------------------------- /tests/browser-automated-tests-playwright/e2e/features/admin_login.js: -------------------------------------------------------------------------------- 1 | var admin_login = async function (page) { 2 | await page.goto(process.env['PLAYWRIGHT_HOST'] + '/auth/login'); 3 | await page.fill('#email', 'admin@example.com'); 4 | await page.fill('#password', 'password'); 5 | await page.click('#login'); 6 | await page.goto(process.env['PLAYWRIGHT_HOST'] + '/admin/dashboard'); 7 | } 8 | 9 | 10 | module.exports.admin_login = admin_login -------------------------------------------------------------------------------- /tests/browser-automated-tests-playwright/e2e/features/clear_db.js: -------------------------------------------------------------------------------- 1 | const { admin_login } = require('./admin_login'); 2 | const { expect } = require('@playwright/test'); 3 | const URL = process.env['PLAYWRIGHT_HOST']; 4 | var clear_db = async function (page) { 5 | await page.goto(URL + '/admin/remove-subscriptions'); 6 | const contentSubscriptions = await page.evaluate(() => document.body.textContent.indexOf("all subscriptions deleted")); 7 | expect(contentSubscriptions > -1); 8 | 9 | await page.goto(URL + '/admin/remove-people'); 10 | const contentPeople = await page.evaluate(() => document.body.textContent.indexOf("all people deleted")); 11 | expect(contentPeople > -1); 12 | 13 | await page.goto(URL + '/admin/remove-transactions'); 14 | const contentTransactions = await page.evaluate(() => document.body.textContent.indexOf("all transactions deleted")); 15 | expect(contentTransactions > -1); 16 | 17 | await page.goto(URL + '/admin/remove-documents'); 18 | const contentDocuments = await page.evaluate(() => document.body.textContent.indexOf("all documents deleted")); 19 | expect(contentDocuments > -1); 20 | // End Clear DB 21 | } 22 | 23 | module.exports.clear_db = clear_db 24 | -------------------------------------------------------------------------------- /tests/browser-automated-tests-playwright/e2e/features/fetch_upcomming_invoices.js: -------------------------------------------------------------------------------- 1 | var fetch_upcomming_invoices = async function (page) { 2 | // Go to upcoming payments and ensure plan is attached to upcoming invoice 3 | await page.goto('/admin/upcoming-invoices'); 4 | await new Promise(x => setTimeout(x, 35000)); 5 | await page.click('#fetch_upcoming_invoices'); 6 | await new Promise(x => setTimeout(x, 30000)); 7 | await page.goto('/admin/upcoming-invoices'); 8 | } 9 | 10 | module.exports.fetch_upcomming_invoices = fetch_upcomming_invoices; -------------------------------------------------------------------------------- /tests/browser-automated-tests-playwright/e2e/features/set_test_name_cookie.js: -------------------------------------------------------------------------------- 1 | var set_test_name_cookie = async function (page, testName) { 2 | /* Drop a cookie to cause Subscribie to display a visual 3 | feedback overlay showing the test name/number running at the time. 4 | */ 5 | await page.goto(`/admin/set-test-name/${testName}`); 6 | 7 | //await new Promise(x => setTimeout(x, 19000)); 8 | } 9 | 10 | module.exports.set_test_name_cookie = set_test_name_cookie; -------------------------------------------------------------------------------- /tests/browser-automated-tests-playwright/github.spec.js: -------------------------------------------------------------------------------- 1 | const { test, expect } = require('@playwright/test'); 2 | 3 | test.describe("Github actions test:", () => { 4 | const magic_login_receives_email = require('./tests/704_shop_owner_magic_login_receives_email'); 5 | 6 | }); 7 | -------------------------------------------------------------------------------- /tests/browser-automated-tests-playwright/logo-subscribie.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Subscribie/subscribie/4ba736e39a1e867186fee4e4ec28ae8b4b1d3a3e/tests/browser-automated-tests-playwright/logo-subscribie.png -------------------------------------------------------------------------------- /tests/browser-automated-tests-playwright/requirements.txt: -------------------------------------------------------------------------------- 1 | graphviz 2 | -------------------------------------------------------------------------------- /tests/browser-automated-tests-playwright/test-videos/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Subscribie/subscribie/4ba736e39a1e867186fee4e4ec28ae8b4b1d3a3e/tests/browser-automated-tests-playwright/test-videos/.gitkeep -------------------------------------------------------------------------------- /tests/browser-automated-tests-playwright/worker2.spec.js: -------------------------------------------------------------------------------- 1 | /* 2 | const { test, expect } = require('@playwright/test'); 3 | 4 | test.beforeEach(async ({ page }) => { 5 | //Login 6 | await page.goto('/auth/login'); 7 | await page.fill('#email', 'admin@example.com'); 8 | await page.fill('#password', 'password'); 9 | await page.click('#login'); 10 | 11 | const content = await page.textContent('.card-title') 12 | expect(content === 'Checklist'); // If we see "Checklist", we're logged in to admin 13 | 14 | await new Promise(x => setTimeout(x, 5000)); 15 | }); 16 | 17 | const plan_creation = require('./tests/shop_owner_plan_creation'); 18 | 19 | const custom_url = require('./tests/1219_shop_owner_enable_custom_url'); 20 | 21 | const changing_plans_order = require('./tests/275_shop_owner_changing_plans_order'); 22 | 23 | const share_private_plan_url = require('./tests/491_shop_owner_share_private_plan_url'); 24 | 25 | const order_plan_with_choice_options_and_required_note = require('./tests/264_subscriber_order_plan_with_choice_options_and_required_note'); 26 | 27 | const order_plan_with_cancel_at = require('./tests/516_subscriber_order_plan_with_cancel_at'); 28 | 29 | const order_plan_cooling_off = require('./tests/133_subscriber_order_plan_with_cooling_off'); 30 | 31 | const enabling_donations = require('./tests/1065_shop_owner_enabling_donations'); 32 | 33 | const checkout_donations = require('./tests/1065_subscriber_checkout_donation'); 34 | */ 35 | --------------------------------------------------------------------------------