mirror of
https://github.com/hubHarmony/servii-backend.git
synced 2024-11-17 21:40:31 +00:00
[+] Added payments.
Created a subscription system, and added different permission levels to the users depending on their subscription
This commit is contained in:
parent
04a62f41f8
commit
15059a7063
22
app.py
22
app.py
@ -13,6 +13,7 @@ from werkzeug.datastructures import ImmutableMultiDict, FileStorage
|
||||
from werkzeug.utils import secure_filename
|
||||
|
||||
import file_manager
|
||||
import finances
|
||||
import firebase_manager
|
||||
import generic_executor
|
||||
import modpacks_manager
|
||||
@ -20,7 +21,7 @@ import modpacks_manager
|
||||
app = Flask(__name__)
|
||||
app.config['MAX_CONTENT_LENGTH'] = 16 * 1000 * 1000 * 1000 #15.28MB~
|
||||
cors = CORS(app, origins="*")
|
||||
apiBP = Blueprint('apiBP', 'BPapi')
|
||||
mc_api = Blueprint('mc_api_bp', 'bp_mc_api')
|
||||
|
||||
|
||||
def generic_response_maker(status_code: http.HTTPStatus, _message: str = None) -> tuple[Response, int]:
|
||||
@ -50,12 +51,6 @@ def generic_response_maker(status_code: http.HTTPStatus, _message: str = None) -
|
||||
return message, status_code.value
|
||||
|
||||
|
||||
'''
|
||||
valid, user_id = firebase_manager.verify_jwt_token(data['token'])
|
||||
TODO : replace 53 by the given statement.
|
||||
'''
|
||||
|
||||
|
||||
def authenticate_request(token: str):
|
||||
valid, user_id = firebase_manager.verify_jwt_token(token)
|
||||
if not valid:
|
||||
@ -102,7 +97,7 @@ route_handlers = {
|
||||
}
|
||||
|
||||
|
||||
@apiBP.route('/<path:path>', methods=['POST'])
|
||||
@mc_api.route('/<path:path>', methods=['POST'])
|
||||
def dynamic_route_handler(path):
|
||||
if path not in route_handlers:
|
||||
return generic_response_maker(http.HTTPStatus.METHOD_NOT_ALLOWED)
|
||||
@ -128,7 +123,7 @@ def dynamic_route_handler(path):
|
||||
|
||||
|
||||
# [!] This route is specific and has to remain out of the dynamic route handler.
|
||||
@apiBP.route('/Upload', methods=['POST'])
|
||||
@mc_api.route('/Upload', methods=['POST'])
|
||||
def upload():
|
||||
form = request.form
|
||||
token: str or None = request.headers.get('SST')
|
||||
@ -180,12 +175,12 @@ def upload():
|
||||
|
||||
|
||||
|
||||
@app.route('/modpacks', methods=['GET'])
|
||||
@mc_api.route('/modpacks', methods=['GET'])
|
||||
def get_modpacks():
|
||||
return modpacks_manager.get_modpacks()
|
||||
|
||||
|
||||
@app.route('/modpacks/image/<path:filename>', methods=['GET'])
|
||||
@mc_api.route('/modpacks/image/<path:filename>', methods=['GET'])
|
||||
def get_modpack_image(filename):
|
||||
return modpacks_manager.get_modpack_image(filename)
|
||||
|
||||
@ -195,7 +190,8 @@ def api_cleanup() -> None:
|
||||
return
|
||||
|
||||
|
||||
app.register_blueprint(apiBP)
|
||||
app.register_blueprint(mc_api)
|
||||
app.register_blueprint(finances.payment_api)
|
||||
|
||||
if __name__ == '__main__':
|
||||
parser = argparse.ArgumentParser(description="Background Scheduler")
|
||||
@ -211,4 +207,4 @@ if __name__ == '__main__':
|
||||
scheduler.start()
|
||||
|
||||
run_simple('0.0.0.0', 3000, app, use_debugger=False, use_reloader=False)
|
||||
api_cleanup()
|
||||
#api_cleanup()
|
148
finances.py
148
finances.py
@ -1,13 +1,74 @@
|
||||
import stripe
|
||||
from flask import Flask, request, jsonify
|
||||
from flask import request, jsonify, Blueprint
|
||||
from stripe import StripeClient
|
||||
|
||||
app = Flask(__name__)
|
||||
import firebase_manager
|
||||
from firebase_manager import log_exception_to_firestore
|
||||
|
||||
payment_api = Blueprint('payment_api_bp', 'bp_payment_api')
|
||||
|
||||
|
||||
#stripe.api_key = os.getenv("STRIPE_SECRET_KEY")
|
||||
endpoint_secret = "whsec_2a1cadb771f7acfdeaac6720fdd56d3353cca5d38bdc2ed88336932968531457"
|
||||
stripe_api_key: str = ("sk_live_51PyIYTP3VLLeb9GlKRfsTMh4olzrJxkT1PwXGlW2G"
|
||||
"HPUeFZmTFHe5ITI0L2tZPBnJd2lHarQifIV5TMh505KFuL300mkItQuBo")
|
||||
endpoint_secret: str = "whsec_2a1cadb771f7acfdeaac6720fdd56d3353cca5d38bdc2ed88336932968531457"
|
||||
|
||||
@app.route('/finances', methods=['POST'])
|
||||
|
||||
stripe.api_key = stripe_api_key
|
||||
client: StripeClient = StripeClient(api_key=stripe_api_key)
|
||||
|
||||
|
||||
products: [str] = ["",
|
||||
"price_1Q3Ji5P3VLLeb9GlMOZuafV9", "price_1Q3Ji3P3VLLeb9GlqNStquBo", "price_1Q3Ji1P3VLLeb9Gl5uqH23js"]
|
||||
|
||||
|
||||
@payment_api.route('/get-checkout-session', methods=['GET'])
|
||||
def create_checkout_session():
|
||||
try:
|
||||
permission: int = int(request.headers.get('permission'))
|
||||
email: str = request.headers.get('email')
|
||||
except ValueError as err:
|
||||
print(err)
|
||||
permission: None = None
|
||||
email: None = None
|
||||
|
||||
if not permission:
|
||||
return jsonify(message="No product query provided."), 404
|
||||
if not email:
|
||||
return jsonify(message="No customer email provided."), 404
|
||||
|
||||
try:
|
||||
session = stripe.checkout.Session.create(
|
||||
ui_mode = 'embedded',
|
||||
line_items=[
|
||||
{
|
||||
'price': products[permission],
|
||||
'quantity': 1,
|
||||
},
|
||||
],
|
||||
allow_promotion_codes=True,
|
||||
mode='subscription',
|
||||
customer_email= email,
|
||||
return_url= "https://app.servii.fr" + '/return?session_id={CHECKOUT_SESSION_ID}',
|
||||
automatic_tax={'enabled': True},
|
||||
)
|
||||
except Exception as err:
|
||||
firebase_manager.log_exception_to_firestore(exception=err, user_id="Stripe")
|
||||
return jsonify(message="Unable to get associated product."), 500
|
||||
|
||||
return jsonify(clientSecret=session.client_secret), 200
|
||||
|
||||
|
||||
@payment_api.route('/get-session-status', methods=['GET'])
|
||||
def session_status():
|
||||
try:
|
||||
session = stripe.checkout.Session.retrieve(request.args.get('session_id'))
|
||||
return jsonify(status=session.status, customer_email=session.customer_details.email), 200
|
||||
except Exception as err:
|
||||
firebase_manager.log_exception_to_firestore(exception=err, user_id="Stripe")
|
||||
return jsonify(message="Unable to retrieve payment session status."), 500
|
||||
|
||||
|
||||
@payment_api.route('/finances', methods=['POST'])
|
||||
def webhook():
|
||||
payload = request.get_data(as_text=True)
|
||||
sig_header = request.headers.get('Stripe-Signature')
|
||||
@ -16,30 +77,61 @@ def webhook():
|
||||
event = stripe.Webhook.construct_event(
|
||||
payload, sig_header, endpoint_secret
|
||||
)
|
||||
except ValueError as e:
|
||||
print(f"Invalid payload: {e}")
|
||||
return jsonify({'error': 'Invalid payload'}), 400
|
||||
except stripe.error.SignatureVerificationError as e:
|
||||
print(f"Invalid signature: {e}")
|
||||
return jsonify({'error': 'Invalid signature'}), 400
|
||||
except ValueError as err:
|
||||
print(f"Invalid payload: {err}")
|
||||
return jsonify({'message': 'Invalid payload'}), 400
|
||||
except stripe.error.SignatureVerificationError as err:
|
||||
print(f"Invalid signature: {err}")
|
||||
return jsonify({'message': 'Invalid signature'}), 400
|
||||
try:
|
||||
match event['type']:
|
||||
case 'customer.subscription.created' | 'customer.subscription.updated':
|
||||
firestore_metadata: int = extract_firestore_data(event)
|
||||
user_id: str = extract_user_id(event)
|
||||
firebase_manager.update_firestore(user_id=user_id, data={"subscription": firestore_metadata})
|
||||
|
||||
case 'customer.subscription.deleted':
|
||||
user_id: str = extract_user_id(event)
|
||||
firebase_manager.update_firestore(user_id=user_id, data={"subscription": 0})
|
||||
|
||||
return jsonify({'status': 'success'}), 200
|
||||
|
||||
except Exception as err:
|
||||
log_exception_to_firestore(exception=err, user_id="Stripe")
|
||||
return jsonify({'status': 'error'}), 500
|
||||
|
||||
|
||||
# Handle the event based on its type
|
||||
match event['type']:
|
||||
case 'customer.subscription.deleted':
|
||||
customer = event['data']['object']
|
||||
print(event)
|
||||
print(f"Customer stopped subscription: {customer['id']}")
|
||||
case 'customer.subscription.created':
|
||||
print(event)
|
||||
customer = event['data']['object']
|
||||
print(f"Customer started subscription: {customer['id']}")
|
||||
case 'customer.subscription.updated':
|
||||
print(event)
|
||||
customer = event['data']['object']
|
||||
print(f"Customer started subscription: {customer['id']}")
|
||||
def extract_firestore_data(event):
|
||||
try:
|
||||
firestore_metadata = (
|
||||
event.get('data', {})
|
||||
.get('object', {})
|
||||
.get('items', {})
|
||||
.get('data', [{}])[0]
|
||||
.get('price', {})
|
||||
.get('metadata', {})
|
||||
.get('firestore', 0)
|
||||
)
|
||||
return int(firestore_metadata)
|
||||
|
||||
return jsonify({'status': 'success'}), 200
|
||||
except (IndexError, KeyError, ValueError) as e:
|
||||
return None
|
||||
|
||||
if __name__ == '__main__':
|
||||
app.run(port=3400)
|
||||
|
||||
def extract_user_id(event):
|
||||
try:
|
||||
customer_id = event.get('data', {}).get('object', {}).get('customer', None)
|
||||
customer = client.customers.retrieve(customer_id)
|
||||
mail: str = customer.get("email", None)
|
||||
user_id: str = firebase_manager.get_user_from_mail(mail)
|
||||
return user_id
|
||||
|
||||
except (IndexError, KeyError) as e:
|
||||
return None
|
||||
except Exception as err:
|
||||
log_exception_to_firestore(exception=err, user_id="Stripe")
|
||||
return None
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
pass
|
||||
|
@ -5,7 +5,8 @@ from typing import Union
|
||||
import firebase_admin
|
||||
import jwt
|
||||
from firebase_admin import auth, credentials, firestore
|
||||
from google.api_core.exceptions import Aborted, DataLoss, NotFound, OutOfRange, PermissionDenied, ResourceExhausted
|
||||
from google.api_core.exceptions import Aborted, DataLoss, NotFound, OutOfRange, PermissionDenied, ResourceExhausted, \
|
||||
GoogleAPICallError
|
||||
from google.cloud.firestore_v1 import FieldFilter, DocumentReference
|
||||
|
||||
import file_manager
|
||||
@ -16,10 +17,35 @@ app = firebase_admin.initialize_app(cred)
|
||||
firestore_database = firestore.client()
|
||||
|
||||
|
||||
def get_user_from_id(user_id):
|
||||
def get_user_from_id(user_id: str):
|
||||
return auth.get_user(user_id)
|
||||
|
||||
|
||||
def get_user_from_mail(mail: str) -> str or None:
|
||||
try:
|
||||
users_ref = firestore_database.collection('users')
|
||||
query = users_ref.where(filter=FieldFilter(field_path='mail', op_string='==', value=mail)).limit(1).stream()
|
||||
|
||||
user_id = None
|
||||
for doc in query:
|
||||
user_id = doc.id
|
||||
break
|
||||
|
||||
return user_id
|
||||
|
||||
except NotFound:
|
||||
print("No such document!")
|
||||
return None
|
||||
|
||||
except GoogleAPICallError as e:
|
||||
print(f"API call error: {e}")
|
||||
return None
|
||||
|
||||
except Exception as e:
|
||||
print(f"An error occurred: {e}")
|
||||
return None
|
||||
|
||||
|
||||
def verify_jwt_token(token):
|
||||
try:
|
||||
decoded_token = auth.verify_id_token(token, app=app, check_revoked=True)
|
||||
|
@ -188,6 +188,8 @@ def server_create(user: UserRecord, name: str, version: str, framework: str = "p
|
||||
if framework not in allowed_frameworks:
|
||||
return HTTPStatus.METHOD_NOT_ALLOWED, f"Framework {framework} not recognized."
|
||||
user_id = user.uid
|
||||
if not firebase_manager.get_user_field(user_id, "subscription"):
|
||||
return HTTPStatus.FORBIDDEN, "You haven't yet subscribed to Servii."
|
||||
server_path: str = f"users/{user_id}/{name}"
|
||||
server_template_path: str = f"servers/{framework}/{version}"
|
||||
try:
|
||||
@ -234,6 +236,8 @@ def server_delete(name: str, user: UserRecord) -> tuple[HTTPStatus, Union[str, N
|
||||
|
||||
def server_run(user: UserRecord, name: str) -> tuple[HTTPStatus, Union[str, None]]:
|
||||
user_id = user.uid
|
||||
if not firebase_manager.get_user_field(user_id, "subscription"):
|
||||
return HTTPStatus.FORBIDDEN, "You haven't yet subscribed to Servii."
|
||||
mc_manager.set_cooldown(user_id=user_id)
|
||||
try:
|
||||
port: int = firebase_manager.get_server_port(user_id)
|
||||
|
13
unit_test.py
13
unit_test.py
@ -2,6 +2,7 @@ import os
|
||||
import shutil
|
||||
|
||||
import firebase_manager
|
||||
from firebase_manager import firestore_database
|
||||
|
||||
|
||||
def ban_user(user_id: str):
|
||||
@ -38,14 +39,6 @@ if __name__ == '__main__':
|
||||
listdir("/home/hapso/Desktop/Personal/servii-backend/servers/paper"),
|
||||
"/home/hapso/Desktop/Personal/servii-backend/servers/paper")
|
||||
'''
|
||||
users_ref = firebase_manager.firestore_database.collection('users')
|
||||
|
||||
# Stream all documents in the users collection
|
||||
users = users_ref.stream()
|
||||
|
||||
# Iterate over each user document
|
||||
for user in users:
|
||||
# Update each document to add the 'subscription' field
|
||||
user_ref = users_ref.document(user.id)
|
||||
user_ref.update({'subscription': 0})
|
||||
print(firebase_manager.get_user_from_mail("technoprod25458565@gmail.com"))
|
||||
print(firebase_manager.get_user_field("MpkbDMOO8PQddQgB5VgBQdTMWF53", "test"))
|
||||
pass
|
||||
|
Loading…
Reference in New Issue
Block a user