Skip to content

Commit a4bfb8c

Browse files
gloriajwmister-teddyTuyetGiangjenkins-fans
authored
Kingfisher 21 (#906)
* Update devapp1.yml New Release * mansory grid (#915) * allow super admin to log in and remove unreachable codes (#911) * email notification on requesting permission and approve/reject (#909) * Issue 871 Guest should not have access to Studio (#908) * hide studio from guest menu * server side blocking * update script (#907) * Display status and visibility on stages list (#922) * display status and visibility to dashboard * mutation update status, visibility * Issue 807 Keep backdrop animation while changing opacity (#917) * fix creating media in studio * keep animation while changing opacity * Issue 912 Scaffolding script enhancement (#916) * demo stage visibility and cover image * media size detection * all user should be able to use demo stage * downsize * Issue 918 Deleting player (#924) * fix performance foreign key and typo * cascade totp * How did this old domain name get back in here??? * Add filter images and fix error create image curtain type (#928) * create image type curtain and add filter image * update style * format code * change style image grid (#929) * change style image grid * Display center image * troubleshooting (#930) * Issue 925 Clear archived events on stage delete (#933) * troubleshooting * clear archived events of abandoned stage * options to send as BCC * Revert "Issue 925 Clear archived events on stage delete (#933)" This reverts commit c29c211. * Issue 925 Clear archived events on stage delete (#933) * troubleshooting * clear archived events of abandoned stage * Revert "options to send as BCC" This reverts commit 00ae6a6. * options to send as BCC (#936) * Issue 931 Making our software i18n - Dashboard (#935) * integrating vue-in18n * convert hard coded string to i18n component * npm script and language selector * vietnames translation * persist locale to local storage Co-authored-by: gloriajw <gloriajw@users.noreply.github.com> * fix bcc recipients not receing email * fix bcc not updating * Issue 819 No required to field (#937) * allow email to be sent with bcc only * translate text * Issue 931 I18n - Studio (#939) * setup i18n in studio * convert string in html to translatable component * translatable column and dragzone * Issue 932 stripe intergration (#938) * add payment schema * Integrate donate to upstage * validate input card * Fix format exp * Fix format custom amount * Validate input * remove key * optional hover effect in prop link (#941) Co-authored-by: Hồng Phát <hongphat.js@gmail.com> Co-authored-by: TuyetGiang <30744004+TuyetGiang@users.noreply.github.com> Co-authored-by: gloriajw <aagg@comcast.net>
1 parent 1b63ca5 commit a4bfb8c

File tree

115 files changed

+2155
-611
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

115 files changed

+2155
-611
lines changed

.github/workflows/devapp1.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ name: DEVAPP1 CI
66
on:
77
# Triggers the workflow on push or approved pull request on R1-2021 branch
88
push:
9-
branches: [ Schildbrau-20 ]
9+
branches: [ Kingfisher-21 ]
1010

1111
# Allows you to run this workflow manually from the Actions tab
1212
workflow_dispatch:
@@ -32,7 +32,7 @@ jobs:
3232
script: |
3333
cd /home/upstage/upstage/ui/dashboard/
3434
git fetch
35-
git checkout Schildbrau-20
35+
git checkout Kingfisher-21
3636
git pull
3737
yarn
3838
yarn build:dev

README.md

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -248,5 +248,52 @@ Finally, pass the incoming request to `UpStage Service`
248248
        }
249249
}
250250
```
251+
252+
## Troubleshooting
253+
254+
### Stages offline when entering with firefox
255+
256+
If you are using firefox and doesn't have the red `LIVE` status on the top right when entering a stage although the stage is live using other browsers, it's because the version of Mosquitto (MQTT Broker) you are using doesn't use `libwebsockets` or it's using a version of `libwebsockets` that having an issue in protocol handling of HTTP2. Whilst Chromium does not attempt a HTTP2 connection in this case, Firefox tries it first and gets a denied reply from the server. More explanation can be found [here](https://www.bluhm-de.com/content/os-tools/en/applications/mqtt/websocket-connections-fail-with-javascript-paho-client.html).
257+
258+
The solution is to build `libwebsockets` and `mosquitto` from source and use it instead of the one provided by your distro.
259+
260+
Instruction on how to do this:
261+
262+
```bash
263+
apt install libssl-dev xsltproc docbook-xsl
264+
git clone https://github.com/warmcat/libwebsockets.git
265+
cd libwebsockets
266+
mkdir build
267+
cd build
268+
cmake .. -DLWS_WITH_HTTP2=OFF
269+
make
270+
make install
271+
ldconfig
272+
cd ../..
273+
git clone https://github.com/eclipse/mosquitto.git
274+
cd mosquitto
275+
make install WITH_WEBSOCKETS=yes WITH_CJSON=no
276+
sudo systemctl edit mosquitto.service
277+
```
278+
279+
Put this into the override file of the service:
280+
281+
```ini
282+
[Unit]
283+
ConditionPathExists=/etc/mosquitto/mosquitto.conf
284+
Requires=network.target
285+
286+
[Service]
287+
Type=
288+
Type=simple
289+
ExecStart=
290+
ExecStart=/usr/local/sbin/mosquitto -c /etc/mosquitto/mosquitto.conf
291+
```
292+
Finally restart the service
293+
294+
```bash
295+
sudo systemctl restart mosquitto.service
296+
```
297+
251298
## License
252299
[GPL-3.0 License](https://github.com/upstage-org/upstage/blob/main/LICENSE)

auth/auth_api.py

Lines changed: 5 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -254,8 +254,11 @@ def call_login_logout(app_entry=True,num_value=None):
254254
).filter(User.active==True).first()
255255

256256
if user:
257-
if not decrypt(user.password) == password:
258-
return make_response(jsonify({"error": "Bad email or password (16)"}), 403)
257+
try:
258+
if not decrypt(user.password) == password:
259+
return make_response(jsonify({"error": "Incorrect username or password (16)"}), 403)
260+
except:
261+
return make_response(jsonify({"error": "Signature did not match digest. Please contact admin to make sure that cipher key is correctly set up (18)"}), 403)
259262
else:
260263
if '@' in username:
261264
user = DBSession.query(User).filter(User.email==username
@@ -274,34 +277,6 @@ def call_login_logout(app_entry=True,num_value=None):
274277
else:
275278
return make_response(jsonify({"error": "Your account has been successfully created but not approved yet.<br/>Please wait for approval or contact UpStage Admin for support!", "level": "warning"}), 403)
276279

277-
# Re-send their signup code.
278-
existing_code = get_security_code(user.id,SIGNUP_VALIDATION)
279-
if not existing_code:
280-
existing_code = new_security_code(user.id,SIGNUP_VALIDATION_MISSING_1ST_CODE)
281-
'''
282-
raise LostCodeError(
283-
"Something weird happened in the system, and this person's code got lost: user id {}".format(user.id)
284-
)
285-
'''
286-
287-
if not send_acct_verification_code(user.phone,existing_code): # always sms
288-
app.logger.warning(f"Tried to send this user a verification code but their phone number is invalid: user_id {user.id} phone {user.phone} ")
289-
290-
email_verification_code(user.email,existing_code)
291-
return make_response(jsonify({"user_id":user.id,
292-
"message": "User needs to verify account"}), 409)
293-
294-
# Admin Logins from the portal will pass a TOTP value that must be verified.
295-
# Service providers will have an SMS code they have entered.
296-
297-
# Kludge: uncomment the below line. remove the line after.
298-
if user.role in (SUPER_ADMIN,):
299-
if not verify_user_totp(user,num_value):
300-
return make_response(jsonify({"error": "Invalid code."}), 403)
301-
302-
elif user.role in (PLAYER,GUEST,ADMIN) and not app_entry:
303-
pass # password checked-out, that's all we need.
304-
305280
# We may also have a fb/g login, if this is the first time a user is logging
306281
# in via fb/g.
307282
# If it's not the first time, we only have the fb/g login, and it's already mapped

config/schema.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -151,15 +151,17 @@ class Arguments:
151151
required=True, description="The body of the email. HTML is allowed.")
152152
recipients = graphene.String(
153153
required=True, description="The recipients of the email. Comma separated.")
154+
bcc = graphene.String(
155+
required=False, description="The bcc recipients of the email. Comma separated.")
154156

155157
@jwt_required()
156-
def mutate(self, info, subject, body, recipients):
158+
def mutate(self, info, subject, body, recipients, bcc):
157159
code, error, user, timezone = current_user()
158160
if not user.role in (ADMIN, SUPER_ADMIN):
159161
raise Exception(
160162
"Only Admin can send notification emails!")
161163

162-
send(recipients, subject, body)
164+
send(recipients, subject, body, bcc)
163165
return SendEmail(success=True)
164166

165167

config/settings/your_hostname.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,3 +118,5 @@
118118
CIPHER_KEY='' # Paste the result from fernet_crypto.py
119119
SECRET_KEY='' # Paste the result from running __init__.py
120120
STREAM_KEY='' # Paste the secret key from node media server config
121+
STRIPE_KEY = ''
122+
STRIPE_PRODUCT_ID = ''

mail/mail_utils.py

Lines changed: 15 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -6,30 +6,37 @@
66
import os
77
import re
88
from config.models import Config
9-
from config.project_globals import DBSession
9+
from config.project_globals import ScopedSession
1010

1111
from config.settings import (EMAIL_HOST, EMAIL_PORT,
1212
EMAIL_HOST_USER, EMAIL_HOST_PASSWORD, EMAIL_HOST_DISPLAY_NAME,
1313
ADMIN_EMAIL, ENV_TYPE)
1414

15-
def send_sync(to, subject, content):
16-
subject_prefix = DBSession.query(Config).filter(Config.name == 'EMAIL_SUBJECT_PREFIX').first().value
15+
def send_sync(to, subject, content, bcc=None):
16+
with ScopedSession() as local_db_session:
17+
subject_prefix = local_db_session.query(Config).filter(Config.name == 'EMAIL_SUBJECT_PREFIX').first().value
1718
msg = MIMEText(content, "html")
18-
msg["Subject"] = f'{subject_prefix}: {subject}'
19+
if subject_prefix:
20+
msg["Subject"] = f'{subject_prefix}: {subject}'
21+
else:
22+
msg["Subject"] = subject
1923
# some SMTP servers will do this automatically, not all
2024
msg["From"] = f'{EMAIL_HOST_DISPLAY_NAME} <{EMAIL_HOST_USER}>'
2125
msg["To"] = to
22-
msg["Bcc"] = ADMIN_EMAIL
26+
if bcc:
27+
msg["Bcc"] = ADMIN_EMAIL + ',' + bcc
28+
else:
29+
msg["Bcc"] = ADMIN_EMAIL
2330

2431
# Always use TLS.
2532
conn = SMTP(EMAIL_HOST, EMAIL_PORT)
2633
conn.set_debuglevel(False)
2734
conn.login(EMAIL_HOST_USER, EMAIL_HOST_PASSWORD)
2835
try:
29-
recipients = re.split(r'[,;]\s*', '{},{}'.format(to, ADMIN_EMAIL))
36+
recipients = re.split(r'[,;]\s*', '{},{}'.format(msg["To"], msg["Bcc"]))
3037
conn.sendmail(EMAIL_HOST_USER, recipients, msg.as_string())
3138
finally:
3239
conn.quit()
3340

34-
def send(to, subject, content):
35-
Process(target=send_sync, args=(to, subject, content)).start()
41+
def send(to, subject, content, bcc=None):
42+
Process(target=send_sync, args=(to, subject, content, bcc)).start()

mail/templates.py

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,4 +82,31 @@ def admin_registration_notification(user, approval_url):
8282
<br>
8383
<b>Email:</b> {user.email}
8484
{footer}
85+
"""
86+
87+
def request_permission_for_media(user, media, note, studio_url):
88+
return f"""
89+
<p>
90+
Hi <b>{display_user(media.owner)}</b>,
91+
<br>
92+
<br>
93+
{display_user(user)} has requested permission to use your media <b>{media.name}</b>. Please go to the <a href="{studio_url}">Studio</a> and click on the Notification icon to approve or deny the request.
94+
<br>
95+
Purpose: {note}
96+
<br>
97+
<br>
98+
{footer}
99+
"""
100+
101+
def permission_response_for_media(user, media, note, approved, studio_url):
102+
return f"""
103+
<p>
104+
Hi <b>{display_user(user)}</b>,
105+
<br>
106+
<br>
107+
Your permission request for <b>{media.name}</b> with purpose \"{note}\" has been {'approved' if approved else 'denied'} by the owner.
108+
{f'<br><br>You can now use the media in the <a href="{studio_url}">Studio</a>.' if approved else ''}
109+
<br>
110+
<br>
111+
{footer}
85112
"""

payment/payment.py

Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
# -*- coding: iso8859-15 -*-
2+
import os
3+
import sys
4+
5+
appdir = os.path.abspath(os.path.dirname(__file__))
6+
projdir = os.path.abspath(os.path.join(appdir, '..'))
7+
if projdir not in sys.path:
8+
sys.path.append(appdir)
9+
sys.path.append(projdir)
10+
11+
import stripe
12+
from config.settings import STRIPE_KEY, STRIPE_PRODUCT_ID
13+
14+
15+
stripe.api_key = STRIPE_KEY
16+
17+
ACCEPT_TYPE = ['card']
18+
ACCEPT_CURRENCIES = ['usd']
19+
20+
21+
def generate_card_token(card_number, exp_month, exp_year, cvc):
22+
''' Generate card token '''
23+
data = stripe.Token.create(
24+
card={
25+
"number": str(card_number),
26+
"exp_month": int(exp_month),
27+
"exp_year": int(exp_year),
28+
"cvc": str(cvc),
29+
})
30+
card_token = data['id']
31+
32+
return card_token
33+
34+
35+
def create_payment_charge(token_id, amount):
36+
''' Create payment charge '''
37+
payment = stripe.Charge.create(
38+
amount=int(amount)*100, # convert amount to cents
39+
currency='usd',
40+
description='Example charge',
41+
source=token_id,
42+
)
43+
44+
payment_check = payment['paid'] # return True for payment
45+
46+
return payment_check
47+
48+
49+
def create_subscription(payment_method_id, customer_id, price_id):
50+
''' Create a subcription '''
51+
stripe.PaymentMethod.attach(payment_method_id, customer=customer_id)
52+
# Set the default payment method on the customer
53+
stripe.Customer.modify(customer_id,
54+
invoice_settings={
55+
'default_payment_method': payment_method_id,
56+
},
57+
)
58+
# Create the subscription
59+
# Subscribe the user to the subscription created
60+
subscription = stripe.Subscription.create(
61+
customer=customer_id,
62+
items=[{"price": price_id, }],
63+
expand=["latest_invoice.payment_intent"]
64+
)
65+
return subscription
66+
67+
68+
def get_subscription(subscription_id):
69+
''' Get subcription by id'''
70+
subscription = stripe.Subscription.retrieve(subscription_id)
71+
return subscription
72+
73+
74+
def cancel_subscription(subscription_id):
75+
''' Cancel a subcription '''
76+
deletedSubscription = stripe.Subscription.delete(subscription_id)
77+
return deletedSubscription
78+
79+
80+
def create_customer(email):
81+
''' Create new customer '''
82+
customer = stripe.Customer.create(email=email)
83+
return customer
84+
85+
86+
def update_email_customer(customer_id, email):
87+
''' Update customer email '''
88+
customer = stripe.Customer.modify(customer_id, email=email)
89+
return customer
90+
91+
92+
def create_payment_card(card_number, exp_month, exp_year, cvc):
93+
''' Create payment by card '''
94+
payment_method = stripe.PaymentMethod.create(
95+
type="card",
96+
card={
97+
"number": str(card_number),
98+
"exp_month": int(exp_month),
99+
"exp_year": int(exp_year),
100+
"cvc": str(cvc),
101+
})
102+
return payment_method
103+
104+
105+
def create_price(unit_amount, currency):
106+
''' Create new price '''
107+
price = stripe.Price.create(
108+
unit_amount=int(unit_amount)*100,
109+
currency=str(currency),
110+
recurring={"interval": "year"},
111+
product=STRIPE_PRODUCT_ID
112+
)
113+
return price
114+
115+
116+
if __name__ == "__main__":
117+
print(stripe.Product.create(name="Upstage").id)

0 commit comments

Comments
 (0)