Make Post Sell
==============

The `Make Post Sell <https://www.makepostsell.com>`_ monolith platform service.

You can use the SaaS or self-host! Accepts credit cards (Stripe), PayPal, Monero (XMR), and Dogecoin (DOGE) payments.

Our `blog acts as our user guide <https://blog.makepostsell.com/>`_ & also uses ``make_post_sell``!

| `Source Code <https://git.unturf.com/engineering/make-post-sell/make_post_sell>`_ | `PyPI <https://pypi.org/project/make-post-sell/>`_ | `SaaS <https://my.makepostsell.com>`_ |

Features
--------

* **Multi-tenant SaaS** — each shop gets its own subdomain or custom domain
* **Payments** — Stripe, PayPal, Adyen, Monero (XMR), Dogecoin (DOGE)
* **Watch Mode** — continuous media playback with DJ crossfade transitions, discovery ring, queue management, and autoplay
* **Pop-out Player** — draggable media window with keyboard shortcuts, ``/random`` and ``/tv`` endpoints
* **Email Subscriptions** — digest emails (immediately, daily, weekly) with @mention notifications
* **Feeds** — RSS, Atom, and sitemap generation per shop
* **AJAX Comments** — real-time comment posting without page reload, preserves media playback
* **Related Content** — Jaccard similarity ranking with thumbnails
* **Lazy Carts** — in-memory until a product is added, no empty rows from bots
* **CSS Grid Lanes** — optional masonry layout per shop
* **Vanilla JS** — no jQuery, no framework dependencies
* **Public Domain** — all contributed code is placed in the public domain

See ``CHANGELOG.rst`` for detailed release history.


Quick Start: Operating a Server with PyPI or Source Code
==========================================================

Before you start, navigate to the directory where you want to install ``make_post_sell`` database & files.

This Makefile-based workflow lets you choose between installing ``make_post_sell`` from PyPI packages or directly from the source code (editable mode). Both flows create a virtual environment in ``./env`` and store configuration and SQLite data in the persistent ``./data`` directory.

1. **Install make_post_sell**

   - **PyPI Installation:**  
     Download the Makefile and run::
     
         wget "https://git.unturf.com/engineering/make-post-sell/make_post_sell/-/raw/master/Makefile"
         make install-from-pypi

   - **Source Installation (Editable Mode):**  
     Clone the repository and run::
     
         git clone ssh://git@git.unturf.com:2222/engineering/make-post-sell/make_post_sell.git
         make install-from-source

   - **Production Installation (Non‑Editable):**  
     For production use (non‑editable even from source), run::
     
         git clone ssh://git@git.unturf.com:2222/engineering/make-post-sell/make_post_sell.git
         make install-from-source-prod

2. **Activate the Virtual Environment**

   Before running any commands, activate the virtual environment::
   
         source env/bin/activate

3. **Start the Development Server**

   You'll want to configure the system in ``data/development.ini``.

   Typically I control most stuff with environment vars, for example ``vars.sh``::

         # boto3 style credentials for s3/digital-ocean spaces.
         # this is for storing content & physical products.
         export MPS_APP_MAIN_BUCKET="removed"
         export MPS_APP_SECURE_UPLOADS_ACCESS_KEY="removed"
         export MPS_APP_SECURE_UPLOADS_SECRET_KEY="removed"

         # stripe keys for collecting credit cards & crypto.
         # NOTE: These are used by tests, shops configure their own keys in the UI
         export MPS_TEST_STRIPE_PUBLIC_API_KEY="pk_test_removed"
         export MPS_TEST_STRIPE_SECRET_API_KEY="sk_test_removed"

         # the root domain acts as a SaaS for many shop domains!
         export MAKE_POST_SELL_ROOT_DOMAIN="example.com"
         export MAKE_POST_SELL_ROOT_URL="http://example.com:6501"
         
         # optional: email for the root domain owner
         export MAKE_POST_SELL_DOMAIN_OWNER_EMAIL="admin@example.com"

         # optional: DKIM email signing (commented out by default)
         # export MPS_APP_DKIM_PRIVATE_KEY_PATH="/path/to/dkim/private.key"
         # export MPS_APP_DKIM_SELECTOR="selector"

   With the virtual environment active, start the server::

         source vars.sh
         make serve

   Then browse to `http://127.0.0.1:6501/ <http://127.0.0.1:6501/>`_ to view the app.



Running Tests
-------------

We currently use `pytest`:

.. code-block:: bash

 make test


SQL Migrations
===============

If your deployment is brand new, you don't need to run any migrations.

Otherwise, it should be safe to run this at anytime to catch your database up:

.. code-block:: bash

 alembic -c development.ini upgrade head

To look at the current revision and the history run these:

.. code-block:: bash

 alembic -c development.ini history
 alembic -c development.ini current

If you ever want to cut a new migration script, you can run this:

.. code-block:: bash

 alembic -c development.ini revision -m "Added email_id column to User table."

Then you can edit / modify the generated ``.py`` file with your changes.

You can also autogenerate a new migration script using `--autogenerate`.
Alembic will prepare a migration script by comparing the state of the
database with the state of the model:

.. code-block:: bash

  alembic -c development.ini revision --autogenerate -m "autogenerated indicies."

You should review the recommended migration script before `upgrade`.

misc
====

You may source the new Python virtual environment during development:

.. code-block:: bash

 # source env/bin/activate.fish
 . env/bin/activate


Python Pyramid Shell
==========================

If you want to use an interactive Python interpreter to interact with Make Post Sell app/models & DB:

.. code-block:: bash

 pshell development.ini

For example, we needed to migrate production data using this script:

.. code-block:: python

 # begin the database transaction.
 request.tm.begin()

 suses = models.stripe_user_shop.get_all_stripe_user_shop_objects(request.dbsession)
 for sus in suses:
     try:
         sus.active_card_id = sus.stripe_customer_default_source.id
         request.dbsession.add(sus)
     except AttributeError:
         pass

 # flush / commit all changes stored the the sqlachemy session.
 request.dbsession.flush()

 # commit/close the database transaction to really make changes.
 request.tm.commit()


Contributing
===================

* Establish communication with Russell or another admin to bless your git.unturf.com gitlab account & put you into the proper roles.
* Russell should see your account request but due to spam you have to ask him directly for approval via email or some other means of comms.
* Clone repo & make commits
* Create merge requests, we automatically run the unit & headless functional tests on each commit
* On merge we release to the production site & see the change across users.

Optionally, format your code.

This is not set in stone, but if you want to use a formatter this is the path for now!

**Python**
  black (manual)

**Jinja2**
  None (not needed, neither is an HTML formatter)

**JavaScript**
  Prettier or biome (manual)

**CSS**
  Prettier or biome (manual)


Licence
==============================================

All contributed code is placed in the public domain.

source code: `https://git.unturf.com/engineering/make-post-sell/make_post_sell <https://git.unturf.com/engineering/make-post-sell/make_post_sell>`_

MakePostSell & make-post-sell are trademarked, do not misrepresent the brand.

Feel free to white label any code or themes into your own brand.

**Original Developer:**  
`Russell Ballestrini <https://russell.ballestrini.net>`_
