try it out.
modified: make_post_sell/models/product.py modified: make_post_sell/models/shop.py modified: make_post_sell/models/user.py new file: make_post_sell/scripts/alembic/versions/c263b4fba9e7_new_ux_columns.py deleted: make_post_sell/static/css/alerts.css modified: make_post_sell/static/css/common.css deleted: make_post_sell/static/css/lib.css deleted: make_post_sell/static/css/mps.css modified: make_post_sell/templates/base.j2 modified: make_post_sell/templates/cart.j2 modified: make_post_sell/templates/product_edit.j2 modified: make_post_sell/templates/shop_settings.j2 modified: make_post_sell/templates/snippets/search.j2 modified: make_post_sell/templates/user_settings.j2 modified: make_post_sell/views/shop.py modified: requirements.txt
This commit is contained in:
parent
759501ad25
commit
4142476f7e
16 changed files with 343 additions and 167 deletions
|
|
@ -470,6 +470,7 @@ def get_products_by_keywords(dbsession, keywords, shop=None):
|
|||
for keyword in keywords:
|
||||
|
||||
keyword_filter = Product.title.ilike("%{}%".format(keyword))
|
||||
# the product _must_ be public (1).
|
||||
products = (
|
||||
product_query.filter(keyword_filter).filter(Product.visibility == 1).all()
|
||||
)
|
||||
|
|
|
|||
|
|
@ -67,6 +67,9 @@ class Shop(RBase, Base):
|
|||
|
||||
disabled = Column(Boolean, default=False)
|
||||
|
||||
maint_mode = Column(Boolean, default=False)
|
||||
favicon = Column(Boolean, default=False)
|
||||
|
||||
# many to many uses association_proxy.
|
||||
users = association_proxy("shop_users", "user", creator=lambda u: UserShop(user=u))
|
||||
|
||||
|
|
|
|||
|
|
@ -56,6 +56,9 @@ class User(RBase, Base):
|
|||
active_cart_count = Column(Integer, default=0, nullable=False)
|
||||
active_cart_total_in_cents = Column(BigInteger, default=0, nullable=False)
|
||||
|
||||
# 0 is dark, 1 is light, could have more themes when h@ckz0rs unite.
|
||||
theme_id = Column(BigInteger, nullable=False, default=1)
|
||||
|
||||
# many to many uses association_proxy.
|
||||
shops = association_proxy("user_shops", "shop", creator=lambda s: UserShop(shop=s))
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,30 @@
|
|||
"""new ux columns
|
||||
|
||||
Revision ID: c263b4fba9e7
|
||||
Revises: cdad5c220c39
|
||||
Create Date: 2022-01-31 15:45:34.314442
|
||||
|
||||
"""
|
||||
from alembic import op
|
||||
import sqlalchemy as sa
|
||||
|
||||
|
||||
# revision identifiers, used by Alembic.
|
||||
revision = 'c263b4fba9e7'
|
||||
down_revision = 'cdad5c220c39'
|
||||
branch_labels = None
|
||||
depends_on = None
|
||||
|
||||
from make_post_sell.models.meta import UUIDType
|
||||
|
||||
|
||||
def upgrade():
|
||||
op.add_column('mps_shop', sa.Column('maint_mode', sa.Boolean(), nullable=True, server_default="0"))
|
||||
op.add_column('mps_shop', sa.Column('favicon', sa.Boolean(), nullable=True, server_default="0"))
|
||||
op.add_column('mps_user', sa.Column('theme_id', sa.BigInteger(), nullable=False, server_default="1"))
|
||||
|
||||
|
||||
def downgrade():
|
||||
op.drop_column('mps_shop', 'maint_mode')
|
||||
op.drop_column('mps_shop', 'favicon')
|
||||
op.drop_column('mps_user', 'theme_id')
|
||||
|
|
@ -1,66 +0,0 @@
|
|||
div.message-ribbon {
|
||||
color: #ffffff;
|
||||
background-color: #5871ad;
|
||||
background: linear-gradient(to right, #5871ad, #82A8FF);
|
||||
}
|
||||
|
||||
#alerts {
|
||||
animation: fadein 2s;
|
||||
}
|
||||
|
||||
@keyframes fadein {
|
||||
from { opacity: 0; }
|
||||
to { opacity: 1; }
|
||||
}
|
||||
|
||||
|
||||
/* ALERT START */
|
||||
#alerts {
|
||||
z-index: 98;
|
||||
}
|
||||
|
||||
.alert {
|
||||
opacity: .85;
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 50px;
|
||||
grid-gap: 10px;
|
||||
}
|
||||
|
||||
.alert-message {
|
||||
text-align: center;
|
||||
margin-top: 10px;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.alert .close {
|
||||
text-align: right;
|
||||
margin-top: 10px;
|
||||
margin-bottom: 10px;
|
||||
margin-right: 15px;
|
||||
}
|
||||
|
||||
.alert-danger, .alert-error {
|
||||
color: #721c24;
|
||||
background-color: #f8d7da;
|
||||
border-color: #f5c6cb;
|
||||
}
|
||||
|
||||
.alert-warning {
|
||||
color: #856404;
|
||||
background-color: #fff3cd;
|
||||
border-color: #ffeeba;
|
||||
}
|
||||
|
||||
.alert-info, .alert-notice {
|
||||
color: #0c5460;
|
||||
background-color: #98b6fa;
|
||||
border-color: #bee5eb;
|
||||
}
|
||||
|
||||
.alert-success {
|
||||
color: #155724;
|
||||
background-color: #a3c765;
|
||||
border-color: #c3e6cb;
|
||||
}
|
||||
|
||||
/* ALERT END */
|
||||
|
|
@ -7,6 +7,7 @@
|
|||
*
|
||||
* * * * * */
|
||||
|
||||
|
||||
body {
|
||||
margin: 0px;
|
||||
font-family: helvetica;
|
||||
|
|
@ -32,6 +33,10 @@ input {
|
|||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
section {
|
||||
margin-bottom: 0px;
|
||||
}
|
||||
|
||||
input[type="text"],
|
||||
input[type="tel"],
|
||||
input[type="password"],
|
||||
|
|
@ -177,6 +182,7 @@ div.message-ribbon {
|
|||
section.log-in {
|
||||
text-align: center;
|
||||
align-self: center;
|
||||
font-size: .75em;
|
||||
}
|
||||
|
||||
section.search {
|
||||
|
|
@ -199,7 +205,9 @@ section.content {
|
|||
}
|
||||
|
||||
section.logo{
|
||||
align-self: center;
|
||||
text-align: center;
|
||||
vertical-align: middle;
|
||||
|
||||
}
|
||||
|
||||
img.logo {
|
||||
|
|
@ -736,3 +744,107 @@ textarea.markup-editor-textarea {
|
|||
padding: 20px;
|
||||
}
|
||||
}
|
||||
div.message-ribbon {
|
||||
color: #ffffff;
|
||||
background-color: #5871ad;
|
||||
background: linear-gradient(to right, #5871ad, #82A8FF);
|
||||
}
|
||||
|
||||
.highlight {
|
||||
text-shadow:
|
||||
-6px 0px 6px rgba(255, 231, 13, 0.6),
|
||||
6px 0px 6px rgba(255, 231, 13, 0.6),
|
||||
12px 0px 12px rgba(255, 231, 13, 0.6),
|
||||
-12px 0px 12px rgba(255, 231, 13, 0.6);
|
||||
}
|
||||
.avoid-wrap {
|
||||
display:inline-block;
|
||||
}
|
||||
|
||||
.vertical-text {
|
||||
display: inline-block;
|
||||
-webkit-transform: rotate(-90deg);
|
||||
-moz-transform: rotate(-90deg);
|
||||
-ms-transform: rotate(-90deg);
|
||||
-o-transform: rotate(-90deg);
|
||||
transform: rotate(-90deg);
|
||||
}
|
||||
|
||||
.shown-on-desktop {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.not-shown-on-desktop {
|
||||
display: block;
|
||||
}
|
||||
|
||||
@media screen and (min-width:800px) {
|
||||
.shown-on-desktop {display: block}
|
||||
.not-shown-on-desktop {display: none}
|
||||
}
|
||||
div.message-ribbon {
|
||||
color: #ffffff;
|
||||
background-color: #5871ad;
|
||||
background: linear-gradient(to right, #5871ad, #82A8FF);
|
||||
}
|
||||
|
||||
#alerts {
|
||||
animation: fadein 2s;
|
||||
}
|
||||
|
||||
@keyframes fadein {
|
||||
from { opacity: 0; }
|
||||
to { opacity: 1; }
|
||||
}
|
||||
|
||||
|
||||
/* ALERT START */
|
||||
#alerts {
|
||||
z-index: 98;
|
||||
}
|
||||
|
||||
.alert {
|
||||
opacity: .85;
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 50px;
|
||||
grid-gap: 10px;
|
||||
}
|
||||
|
||||
.alert-message {
|
||||
text-align: center;
|
||||
margin-top: 10px;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.alert .close {
|
||||
text-align: right;
|
||||
margin-top: 10px;
|
||||
margin-bottom: 10px;
|
||||
margin-right: 15px;
|
||||
}
|
||||
|
||||
.alert-danger, .alert-error {
|
||||
color: #721c24;
|
||||
background-color: #f8d7da;
|
||||
border-color: #f5c6cb;
|
||||
}
|
||||
|
||||
.alert-warning {
|
||||
color: #856404;
|
||||
background-color: #fff3cd;
|
||||
border-color: #ffeeba;
|
||||
}
|
||||
|
||||
.alert-info, .alert-notice {
|
||||
color: #0c5460;
|
||||
background-color: #98b6fa;
|
||||
border-color: #bee5eb;
|
||||
}
|
||||
|
||||
.alert-success {
|
||||
color: #155724;
|
||||
background-color: #a3c765;
|
||||
border-color: #c3e6cb;
|
||||
}
|
||||
|
||||
/* ALERT END */
|
||||
|
|
|
|||
|
|
@ -1,25 +0,0 @@
|
|||
.avoid-wrap {
|
||||
display:inline-block;
|
||||
}
|
||||
|
||||
.vertical-text {
|
||||
display: inline-block;
|
||||
-webkit-transform: rotate(-90deg);
|
||||
-moz-transform: rotate(-90deg);
|
||||
-ms-transform: rotate(-90deg);
|
||||
-o-transform: rotate(-90deg);
|
||||
transform: rotate(-90deg);
|
||||
}
|
||||
|
||||
.shown-on-desktop {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.not-shown-on-desktop {
|
||||
display: block;
|
||||
}
|
||||
|
||||
@media screen and (min-width:800px) {
|
||||
.shown-on-desktop {display: block}
|
||||
.not-shown-on-desktop {display: none}
|
||||
}
|
||||
|
|
@ -1,13 +0,0 @@
|
|||
div.message-ribbon {
|
||||
color: #ffffff;
|
||||
background-color: #5871ad;
|
||||
background: linear-gradient(to right, #5871ad, #82A8FF);
|
||||
}
|
||||
|
||||
.highlight {
|
||||
text-shadow:
|
||||
-6px 0px 6px rgba(255, 231, 13, 0.6),
|
||||
6px 0px 6px rgba(255, 231, 13, 0.6),
|
||||
12px 0px 12px rgba(255, 231, 13, 0.6),
|
||||
-12px 0px 12px rgba(255, 231, 13, 0.6);
|
||||
}
|
||||
|
|
@ -5,18 +5,11 @@
|
|||
{% if request.product -%}
|
||||
<!--product_id={{ request.product.id }}-->
|
||||
{%- endif %}
|
||||
<html lang="en">
|
||||
<html lang="en" data-theme="{{ request.html_data_theme or 'dark' }}">
|
||||
<head>
|
||||
|
||||
<!--
|
||||
TODO: merge all these CSS files into a single file during builds.
|
||||
In prod single concatenated ("streamlined") all.css file.
|
||||
In dev each CSS file busted out like so:
|
||||
-->
|
||||
<!-- stylesheet to-end-all stylesheets, pico.fluid.classless.css ! woot -->
|
||||
<link rel="stylesheet" href="/static/css/common.css">
|
||||
<link rel="stylesheet" href="/static/css/mps.css">
|
||||
<link rel="stylesheet" href="/static/css/alerts.css">
|
||||
<link rel="stylesheet" href="/static/css/lib.css">
|
||||
|
||||
{% include 'snippets/analytics.j2' %}
|
||||
|
||||
|
|
@ -26,6 +19,10 @@
|
|||
<meta name="theme-color" content="{{ theme_color }}">
|
||||
<meta charset="utf-8">
|
||||
|
||||
{% if request.shop and request.shop.favicon %}
|
||||
<link rel="icon" href="{{ request.app['bucket.secure_uploads.get_endpoint'] }}/{{ request.shop.uuid_str }}/meta/shop-favicon" />
|
||||
{% endif %}
|
||||
|
||||
{%- block append_to_head_tag_section %}
|
||||
<title>{{ request.app_domain }}</title>
|
||||
{% endblock %}
|
||||
|
|
|
|||
|
|
@ -114,7 +114,7 @@
|
|||
<form action="/cart/{{ cart.id }}/quantity" method="POST" onsubmit="submit.disabled = true; return true;" style="display: inline;">
|
||||
<input type="hidden" name="product_id" value="{{ product.id }}">
|
||||
quantity: <input type="text" name="quantity" class="mps-quantity" value="{{ product_quantity }}">
|
||||
<input type="submit" id="submit" class="quantity button-small" value="update" />
|
||||
<input type="submit" id="submit" value="update" role="button" style="width: 80px;"/>
|
||||
</form>
|
||||
<br/>
|
||||
|
||||
|
|
|
|||
|
|
@ -30,7 +30,8 @@
|
|||
<li>
|
||||
<form method="post" action="/p/{{ product.id }}/bundle/remove/{{ p.id }}" onsubmit="submit.disabled = true; return true;">
|
||||
{{p.title}}
|
||||
<input type="submit" name="submit" class="mps-submit" value="remove" />
|
||||
<input type="submit" name="submit" class="mps-submit" value="remove" style
|
||||
="width: 80px;"/>
|
||||
</form>
|
||||
</li>
|
||||
<br>
|
||||
|
|
@ -43,9 +44,12 @@
|
|||
<h3>Upload or Replace Product File</h3>
|
||||
|
||||
People may download this file after making a purchase.
|
||||
|
||||
<br>
|
||||
<br>
|
||||
|
||||
{% if "product" in product.originals %}<p style="font-weight: bold">Current File: {{ product.originals["product"] }}</p>{% endif %}
|
||||
|
||||
{% set signed_post = signed_posts["product"] %}
|
||||
<form method="post" action="{{ signed_post["url"] }}" enctype="multipart/form-data" onsubmit="submit.disabled = true; return true;">
|
||||
{% for field_name, field_value in signed_post["fields"].items() %}
|
||||
|
|
@ -55,19 +59,22 @@
|
|||
<input type="submit" name="submit" class="mps-upload" value="Upload Product" />
|
||||
</form>
|
||||
|
||||
{% if "product" in product.originals %}<p style="font-weight: bold">Current File: {{ product.originals["product"] }}</p>{% endif %}
|
||||
|
||||
{% endif %}
|
||||
|
||||
{% if product.is_sellable %}
|
||||
<br/>
|
||||
<br/>
|
||||
|
||||
<hr/>
|
||||
|
||||
<h3>Upload or Replace Preview File</h3>
|
||||
|
||||
People may download this file before making a purchase.
|
||||
<br>
|
||||
<br>
|
||||
|
||||
<br />
|
||||
<br />
|
||||
|
||||
{% if "preview" in product.originals %}<p style="font-weight: bold">Current File: {{ product.originals["preview"] }}</p>{% endif %}
|
||||
|
||||
{% set signed_post = signed_posts["preview"] %}
|
||||
<form method="post" action="{{ signed_post["url"] }}" enctype="multipart/form-data" onsubmit="submit.disabled = true; return true;">
|
||||
{% for field_name, field_value in signed_post["fields"].items() %}
|
||||
|
|
@ -77,7 +84,7 @@
|
|||
<input type="file" name="file" class="file-input" /> <br />
|
||||
<input type="submit" name="submit" class="mps-upload" value="Upload Preview" />
|
||||
</form>
|
||||
{% if "preview" in product.originals %}<p style="font-weight: bold">Current File: {{ product.originals["preview"] }}</p>{% endif %}
|
||||
|
||||
|
||||
{% endif %}
|
||||
|
||||
|
|
@ -97,9 +104,13 @@ Your product cover (<code>thumbnail1</code>) will show up on search pages.
|
|||
{% set s3_key_thumbnails = product.s3_key_thumbnails %}
|
||||
|
||||
{% for thumbnail_key in product.file_thumbnail_keys %}
|
||||
|
||||
<div class="upload-thumbnail-item">
|
||||
<b>{{ thumbnail_key }}</b>
|
||||
<br />
|
||||
|
||||
{% if thumbnail_key in s3_key_thumbnails %}
|
||||
{% set get_endpoint = request.app["bucket.secure_uploads.get_endpoint"] + "/" + s3_key_thumbnails[thumbnail_key] %}
|
||||
<a href="{{ get_endpoint }}?ts={{ product.updated_timestamp }}"><img src="{{ get_endpoint }}?ts={{ product.updated_timestamp }}" width="120px" /></a>
|
||||
{% endif %}
|
||||
|
||||
{% set signed_post = signed_posts[thumbnail_key] %}
|
||||
<form method="post" action="{{ signed_post["url"] }}" enctype="multipart/form-data" onsubmit="submit.disabled = true; return true;">
|
||||
|
|
@ -109,14 +120,14 @@ Your product cover (<code>thumbnail1</code>) will show up on search pages.
|
|||
<input type="file" name="file" class="file-input" /> <br />
|
||||
<input type="submit" name="submit" class="mps-upload" value="Upload {{ thumbnail_key }}" />
|
||||
</form>
|
||||
|
||||
<hr/>
|
||||
|
||||
<br />
|
||||
|
||||
{% if thumbnail_key in s3_key_thumbnails %}
|
||||
{% set get_endpoint = request.app["bucket.secure_uploads.get_endpoint"] + "/" + s3_key_thumbnails[thumbnail_key] %}
|
||||
<a href="{{ get_endpoint }}?ts={{ product.updated_timestamp }}"><img src="{{ get_endpoint }}?ts={{ product.updated_timestamp }}" width="120px" /></a>
|
||||
{% endif %}
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
{% endfor %}
|
||||
</section>
|
||||
|
||||
|
|
|
|||
|
|
@ -3,9 +3,10 @@
|
|||
{% block content -%}
|
||||
|
||||
<section class="one-column">
|
||||
|
||||
<section class="shop-settings well">
|
||||
|
||||
<h3>Shop Settings</h3>
|
||||
|
||||
<form method="post" action="/s/{{ request.shop.id }}/settings" onsubmit="submit.disabled = true; return true;">
|
||||
|
||||
<label for="name_input">Shop Name</label>
|
||||
|
|
@ -57,7 +58,26 @@
|
|||
|
||||
<br />
|
||||
<br />
|
||||
|
||||
<input type="submit" name="submit" class="mps-submit" value="Save Settings" />
|
||||
<br />
|
||||
<br />
|
||||
|
||||
</form>
|
||||
|
||||
</section>
|
||||
</section>
|
||||
|
||||
<br />
|
||||
<br />
|
||||
|
||||
<section class="one-column">
|
||||
<section class="shop-settings well">
|
||||
|
||||
<h3>Integration Settings</h3>
|
||||
|
||||
<form method="post" action="/s/{{ request.shop.id }}/settings" onsubmit="submit.disabled = true; return true;">
|
||||
|
||||
<label for="domain_name_input">Custom Shop Domain Name</label>
|
||||
<input
|
||||
name = "domain_name"
|
||||
|
|
@ -80,10 +100,10 @@
|
|||
value = "{% if stripe_public_api_key %}{{ stripe_public_api_key }}{% endif %}"
|
||||
placeholder = "Stripe Public API Key (pk)"
|
||||
/>
|
||||
|
||||
|
||||
<br />
|
||||
<br />
|
||||
|
||||
|
||||
<label for="stripe_secret_api_key_input">Stripe Secret API Key</label>
|
||||
<input
|
||||
name = "stripe_secret_api_key"
|
||||
|
|
@ -93,7 +113,7 @@
|
|||
value = "{% if stripe_secret_api_key %}{{ stripe_secret_api_key }}{% endif %}"
|
||||
placeholder = "Stripe Secret API Key (sk)"
|
||||
/>
|
||||
|
||||
|
||||
<br />
|
||||
<br />
|
||||
|
||||
|
|
@ -129,15 +149,60 @@
|
|||
|
||||
<input type="submit" name="submit" class="mps-submit" value="Save Settings" />
|
||||
|
||||
<br />
|
||||
<br />
|
||||
<br />
|
||||
|
||||
<hr />
|
||||
</form>
|
||||
|
||||
</section>
|
||||
</section>
|
||||
|
||||
<br />
|
||||
|
||||
<h4>Announcement Ribbon Settings</h4>
|
||||
<br />
|
||||
<br />
|
||||
|
||||
<section class="one-column">
|
||||
<section class="shop-settings well">
|
||||
|
||||
<h3>Branding Settings</h3>
|
||||
|
||||
<label for="logo-banner">Banner Logo</label>
|
||||
<a href="{{ get_endpoints["shop-logo-banner"] }}"><img src="{{ get_endpoints["shop-logo-banner"] }}" width="420px" /></a>
|
||||
{% set signed_post = signed_posts["shop-logo-banner"] %}
|
||||
<form method="post" action="{{ signed_post["url"] }}" enctype="multipart/form-data" onsubmit="submit.disabled = true; return true;">
|
||||
{% for field_name, field_value in signed_post["fields"].items() %}
|
||||
<input type="hidden" name="{{ field_name }}" value="{{ field_value }}" />
|
||||
{% endfor %}
|
||||
<input type="file" name="file" class="file-input" /> <br />
|
||||
<input type="submit" name="submit" class="mps-upload" value="Upload Shop Banner" />
|
||||
</form>
|
||||
|
||||
<hr />
|
||||
|
||||
<br />
|
||||
|
||||
<label for="logo-banner">favicon.ico</label>
|
||||
<a href="{{ get_endpoints["shop-favicon"] }}"><img src="{{ get_endpoints["shop-favicon"] }}" width="32px" /></a>
|
||||
{% set signed_post = signed_posts["shop-favicon"] %}
|
||||
<form method="post" action="{{ signed_post["url"] }}" enctype="multipart/form-data" onsubmit="submit.disabled = true; return true;">
|
||||
{% for field_name, field_value in signed_post["fields"].items() %}
|
||||
<input type="hidden" name="{{ field_name }}" value="{{ field_value }}" />
|
||||
{% endfor %}
|
||||
<input type="file" name="file" class="file-input" /> <br />
|
||||
<input type="submit" name="submit" class="mps-upload" value="Upload favicon.ico" />
|
||||
</form>
|
||||
|
||||
</section>
|
||||
</section>
|
||||
|
||||
<br />
|
||||
<br />
|
||||
|
||||
<section class="one-column">
|
||||
<section class="shop-settings well">
|
||||
|
||||
<form method="post" action="/s/{{ request.shop.id }}/settings" onsubmit="submit.disabled = true; return true;">
|
||||
|
||||
<h3>Announcement Ribbon Settings 🎀</h3>
|
||||
|
||||
<label for="ribbon_text_input">Ribbon Text</label>
|
||||
<textarea
|
||||
|
|
@ -194,35 +259,44 @@
|
|||
<br />
|
||||
<br />
|
||||
|
||||
<hr>
|
||||
|
||||
<br />
|
||||
<br />
|
||||
|
||||
|
||||
</form>
|
||||
|
||||
|
||||
<h4>Branding</h4>
|
||||
</section>
|
||||
</section>
|
||||
|
||||
<br />
|
||||
<br />
|
||||
|
||||
<section class="one-column">
|
||||
<section class="shop-settings well">
|
||||
|
||||
<form method="post" action="/s/{{ request.shop.id }}/settings" onsubmit="submit.disabled = true; return true;">
|
||||
|
||||
<h3>Maintenance Mode 🏗️</h3>
|
||||
|
||||
<input type="checkbox" name="maint-mode-checkbox" id="maint-mode-checkbox" {% if maint_mode %}checked{% endif %}></input>
|
||||
<b>If checked, enabled maintenance mode.</b>
|
||||
|
||||
<br />
|
||||
<br />
|
||||
|
||||
Temporarily prevent new searches or sales on this shop.
|
||||
Existing sales honored for download buy purchasers.
|
||||
|
||||
<label for="logo-banner">Banner Logo</label>
|
||||
{% set signed_post = signed_posts["shop-logo-banner"] %}
|
||||
<form method="post" action="{{ signed_post["url"] }}" enctype="multipart/form-data" onsubmit="submit.disabled = true; return true;">
|
||||
{% for field_name, field_value in signed_post["fields"].items() %}
|
||||
<input type="hidden" name="{{ field_name }}" value="{{ field_value }}" />
|
||||
{% endfor %}
|
||||
<input type="file" name="file" class="file-input" /> <br />
|
||||
<input type="submit" name="submit" class="mps-upload" value="Upload Shop Banner" />
|
||||
</form>
|
||||
|
||||
<br />
|
||||
<br />
|
||||
|
||||
<a href="{{ get_endpoints["shop-logo-banner"] }}"><img src="{{ get_endpoints["shop-logo-banner"] }}" width="420px" /></a>
|
||||
<input type="submit" name="submit" class="mps-submit" value="Save Settings" />
|
||||
|
||||
<br />
|
||||
<br />
|
||||
|
||||
</form>
|
||||
|
||||
</section>
|
||||
|
||||
</section>
|
||||
|
||||
|
||||
{%- endblock -%}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
{% if request.shop and not search_disabled %}
|
||||
<form action="/search" id="search" name="search">
|
||||
<form action="/search" id="search" name="search" style="margin-bottom: 0px;">
|
||||
|
||||
{% include 'csrf.j2' %}
|
||||
{%- if request.shop -%}
|
||||
|
|
@ -12,6 +12,7 @@
|
|||
class="mps-keywords"
|
||||
placeholder="Keyword search on {{ request.shop.name }}"
|
||||
{% if keywords %}value="{{ keywords }}"{% endif %}
|
||||
style="margin-bottom: 0px;"
|
||||
required/>
|
||||
|
||||
</form>
|
||||
|
|
|
|||
|
|
@ -6,9 +6,9 @@
|
|||
|
||||
{% block content -%}
|
||||
|
||||
<section class="two-column">
|
||||
|
||||
<section class="one-column">
|
||||
<section class="user-settings well">
|
||||
|
||||
<h3>User Settings</h3>
|
||||
<form method="post" action="/u/settings" onsubmit="submit.disabled = true; return true;">
|
||||
|
||||
|
|
@ -37,15 +37,36 @@
|
|||
|
||||
<br />
|
||||
<br />
|
||||
|
||||
|
||||
<fieldset>
|
||||
|
||||
<legend>User Theme</legend>
|
||||
|
||||
<input type="radio" name="user_theme" id="light_mode" value="1" {% if user_theme == 1 %}checked{% endif %} />
|
||||
<label for="user_theme" style="display: inline">Light mode</label>
|
||||
|
||||
<input type="radio" name="user_theme" id="visibility_unlisted" value="0" {% if user_theme == 0 %}checked{% endif %} />
|
||||
<label for="user_theme" style="display: inline;">Dark mode</label>
|
||||
|
||||
</fieldset>
|
||||
|
||||
|
||||
<br />
|
||||
|
||||
<input type="submit" name="submit" class="mps-submit" value="Save Settings" />
|
||||
|
||||
<br />
|
||||
<br />
|
||||
|
||||
</form>
|
||||
</section>
|
||||
|
||||
<section class="button-panel">
|
||||
</section>
|
||||
|
||||
<br />
|
||||
<br />
|
||||
|
||||
<section class="one-column">
|
||||
<section class="well">
|
||||
|
||||
{% if request.is_saas_domain %}
|
||||
<a href="/u/shops" class="product-edit-button mps-button">My Shops</a>
|
||||
|
|
|
|||
|
|
@ -26,6 +26,13 @@ from pyramid.httpexceptions import HTTPFound
|
|||
from miscutils.phone_numbers import is_phone_number_valid
|
||||
|
||||
|
||||
def checkbox_to_bool(checkbox):
|
||||
return True if checkbox == "on" else False
|
||||
|
||||
def bool_to_checkbox(boolean):
|
||||
return "on" if boolean == True else "off"
|
||||
|
||||
|
||||
def get_shop_from_matchdict(request, prefetched_shop=None):
|
||||
"""
|
||||
This function uses the shop_id from the url path
|
||||
|
|
@ -308,6 +315,9 @@ def shop_settings(request):
|
|||
stripe_public_api_key = request.params.get("stripe_public_api_key", shop.stripe_public_api_key)
|
||||
stripe_secret_api_key = request.params.get("stripe_secret_api_key", shop.stripe_secret_api_key)
|
||||
|
||||
maint_mode_checkbox = request.params.get("maint-mode-checkbox", bool_to_checkbox(shop.maint_mode))
|
||||
maint_mode = checkbox_to_bool(maint_mode_checkbox)
|
||||
|
||||
s3_webhook_key = request.params.get("key")
|
||||
s3_webhook_bucket = request.params.get("bucket")
|
||||
s3_webhook_etag = request.params.get("etag")
|
||||
|
|
@ -396,6 +406,18 @@ def shop_settings(request):
|
|||
msg = ("The shop's stripe_secret_api_key must start with 'sk_'.", "error")
|
||||
request.session.flash(msg)
|
||||
|
||||
print("{} {}".format(shop.maint_mode, maint_mode))
|
||||
if shop.maint_mode != maint_mode:
|
||||
shop.maint_mode = maint_mode
|
||||
request.session.flash(
|
||||
(
|
||||
"You turned {} maint_mode".format(
|
||||
maint_mode_checkbox
|
||||
),
|
||||
"success",
|
||||
)
|
||||
)
|
||||
|
||||
# TODO: Dry out this block, it's a copy pasta from views/product.py
|
||||
if s3_webhook_key and s3_webhook_bucket and s3_webhook_etag:
|
||||
|
||||
|
|
@ -409,9 +431,9 @@ def shop_settings(request):
|
|||
|
||||
# determine content type from extension.
|
||||
file_ext = s3_webhook_key.split(".")[-1]
|
||||
print(file_ext)
|
||||
#print(file_ext)
|
||||
content_type = mimetypes.types_map.get("." + file_ext)
|
||||
print(content_type)
|
||||
#print(content_type)
|
||||
|
||||
# copy upload to our system defined s3 location.
|
||||
# https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/s3.html#S3.Client.copy_object
|
||||
|
|
@ -435,6 +457,9 @@ def shop_settings(request):
|
|||
Key=s3_webhook_key,
|
||||
)
|
||||
|
||||
if file_key == "shop-favicon":
|
||||
shop.favicon = True
|
||||
|
||||
# redirect back to this page to clear
|
||||
# the params posted by the s3 webhooks.
|
||||
return HTTPFound("/s/{}/{}/settings?uploaded={}".format(shop.id, shop.slug, file_key))
|
||||
|
|
@ -444,7 +469,7 @@ def shop_settings(request):
|
|||
signed_posts = {}
|
||||
get_endpoints = {}
|
||||
|
||||
for file_key in ["shop-logo-banner", "shop-logo-avatar"]:
|
||||
for file_key in ["shop-logo-banner", "shop-logo-avatar", "shop-favicon"]:
|
||||
# conditionally sign the ability to POST to the object path when the
|
||||
# object path start's with the shop's s3 namespace (uuid) and only for
|
||||
# particular file keys. This prevents a user from writing files into
|
||||
|
|
@ -493,9 +518,10 @@ def shop_settings(request):
|
|||
"ribbon_color_1": ribbon_color_1,
|
||||
"ribbon_color_2": ribbon_color_2,
|
||||
"google_analytics_id": google_analytics_id,
|
||||
"plausble_domain_name": plausible_domain_name,
|
||||
"plausible_domain_name": plausible_domain_name,
|
||||
"stripe_public_api_key": stripe_public_api_key,
|
||||
"stripe_secret_api_key": stripe_secret_api_key,
|
||||
"maint_mode": maint_mode,
|
||||
"signed_posts": signed_posts,
|
||||
"get_endpoints": get_endpoints,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
# python 2 -> 3 compat.
|
||||
six
|
||||
#future
|
||||
|
||||
# Pyramid with SQLAlchemy.
|
||||
plaster_pastedeploy
|
||||
|
|
@ -52,7 +53,7 @@ miniuri
|
|||
# my miscutils package can sanitize and make HTML safe.
|
||||
# that said, it requires the following:
|
||||
# Bleach sanitizes MarkDown (removes HTML/Javascript) to prevent XSS.
|
||||
bleach>=2.1.4
|
||||
bleach
|
||||
#bleach-whitelist
|
||||
bleach-allowlist
|
||||
beautifulsoup4
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue