CaesarCloudSync commited on
Commit
211843b
·
0 Parent(s):

CaesarAI Change Card Improve 1

Browse files
.gitignore ADDED
@@ -0,0 +1,13 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ *.json
2
+ revisionbankenv
3
+ exampleimage.json
4
+ Procfile
5
+ yes
6
+ yes.pub
7
+ test.js
8
+ test.py
9
+ test3.py
10
+ test4.py
11
+ mydata.json
12
+ .space
13
+ revisionbankscheduler
Aptfile ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ tesseract-ocr
2
+ tesseract-ocr-eng
3
+ libtesseract-dev
Dockerfile ADDED
@@ -0,0 +1,29 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Use the official Python 3.9 image
2
+ FROM python:3.10
3
+ RUN export PYTHONPATH=$PWD
4
+ RUN apt-get update && apt-get install curl ffmpeg libsm6 libxext6 uvicorn libopencv-dev python3-opencv tesseract-ocr -y
5
+ RUN pip install uvicorn
6
+ # Set the working directory to /code
7
+ WORKDIR /code
8
+ #VOLUME /home/amari/Desktop/CaesarAI/CaesarFastAPI /code
9
+ # Copy the current directory contents into the container at /code
10
+ COPY ./requirements.txt /code/requirements.txt
11
+
12
+ # Install requirements.txt
13
+ RUN pip install --no-cache-dir --upgrade -r /code/requirements.txt
14
+
15
+ # Set up a new user named "user" with user ID 1000
16
+ RUN useradd -m -u 1000 user
17
+ # Switch to the "user" user
18
+ USER user
19
+ # Set home to the user's home directory
20
+ ENV HOME=/home/user \
21
+ PATH=/home/user/.local/bin:$PATH
22
+
23
+ # Set the working directory to the user's home directory
24
+ WORKDIR $HOME/app
25
+
26
+ # Copy the current directory contents into the container at $HOME/app setting the owner to the user
27
+ COPY --chown=user . $HOME/app
28
+
29
+ CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "7860","--reload"]
README.md ADDED
@@ -0,0 +1,9 @@
 
 
 
 
 
 
 
 
 
 
1
+ ---
2
+ title: RevisionBank
3
+ emoji: 📖
4
+ colorFrom: indigo
5
+ colorTo: gray
6
+ sdk: docker
7
+ pinned: false
8
+ license: apache-2.0
9
+ ---
RevisionBankModels.py ADDED
@@ -0,0 +1,13 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from typing import Generic, TypeVar,Dict,List,AnyStr,Any,Union
2
+ from pydantic import BaseModel
3
+ from pydantic.generics import GenericModel
4
+
5
+ M = TypeVar("M", bound=BaseModel)
6
+
7
+
8
+ class GenericSingleObject(GenericModel, Generic[M]):
9
+ object: M
10
+ class RevisionBankAuth(BaseModel):
11
+ email:str
12
+ password:str
13
+
Subjects.md ADDED
@@ -0,0 +1,23 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ## Subjects
2
+ # Done = $, Pending = % , Not Done = /
3
+ # A level Exam Boards = Edexcel,AQA,CIE,OCR, WJEC
4
+ # GCSE
5
+ # 1. Further Maths $
6
+ # 2. Physics OCR ans $
7
+ # 3. Computer science OCR ans $
8
+ # 4. Chemistry OCR ans $
9
+ # 5. Biology OCR ans $
10
+ # 6. History
11
+ # 7. Extended Project Qualification
12
+ # 8. Economics
13
+ # 9. Business
14
+
15
+ # 10. Geography
16
+ # 11. Art
17
+ # 12. Geology
18
+ # 13. Modern Languages
19
+ # 14. Music
20
+ # 15. RS
21
+ # 16. Psycology
22
+ # 17. Drama
23
+ # 18. Geology
__pycache__/RevisionBankModels.cpython-310.pyc ADDED
Binary file (799 Bytes). View file
 
__pycache__/config.cpython-310.pyc ADDED
Binary file (723 Bytes). View file
 
__pycache__/csv_to_db.cpython-310.pyc ADDED
Binary file (1.45 kB). View file
 
__pycache__/forgotpassemail.cpython-310.pyc ADDED
Binary file (815 Bytes). View file
 
__pycache__/main.cpython-310.pyc ADDED
Binary file (42.1 kB). View file
 
__pycache__/models.cpython-310.pyc ADDED
Binary file (1.68 kB). View file
 
__pycache__/physicsaqa.cpython-310.pyc ADDED
Binary file (1.43 kB). View file
 
__pycache__/raspsendemail.cpython-310.pyc ADDED
Binary file (2.31 kB). View file
 
__pycache__/revisionbankscheduler.cpython-310.pyc ADDED
Binary file (3.49 kB). View file
 
app.py ADDED
@@ -0,0 +1,1457 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import base64
2
+ import concurrent
3
+ import os
4
+ from concurrent.futures import thread
5
+ from datetime import datetime
6
+ import datetime as dt
7
+ import requests
8
+ from bs4 import BeautifulSoup
9
+ from flask import Flask, app, jsonify, request
10
+ from flask_cors import CORS, cross_origin
11
+ from flask_mail import Mail, Message
12
+ from physicsaqa import PhysicsAQA
13
+ from config import Config
14
+ from flask_jwt_extended import JWTManager, jwt_required, create_access_token, get_jwt_identity
15
+ from csv_to_db import ImportCSV
16
+ from models import Users
17
+ from bson.objectid import ObjectId #
18
+ import hashlib
19
+ import random
20
+ from datetime import datetime
21
+ from PIL import Image, ImageOps
22
+ from io import BytesIO
23
+ import base64
24
+ import json
25
+ import stripe
26
+ #import cv2
27
+ import re
28
+ import pytesseract
29
+ from forgotpassemail import forgotpasswordemail
30
+ app = Flask(__name__)
31
+ app.config.from_object(Config)
32
+ mail = Mail(app)
33
+ jwt = JWTManager(app)
34
+ importcsv = ImportCSV("RevisionBankDB",maindb=0)
35
+ importcsvqp = ImportCSV("RevisionBankDB",maindb= 1)
36
+ importcsvqp1 = ImportCSV("RevisionBankQPs1",maindb=2)
37
+ app.config['JWT_SECRET_KEY'] = "Peter Piper picked a peck of pickled peppers, A peck of pickled peppers Peter Piper picked, If Peter Piper picked a peck of pickled peppers,Where's the peck of pickled peppers Peter Piper picked" #'super-secret'
38
+
39
+ app.config["JWT_ACCESS_TOKEN_EXPIRES"] = dt.timedelta(days=1)
40
+
41
+ def getendsubscription(current_user):
42
+ user_from_db = list(importcsv.db.users.find({"email": current_user}))[0]
43
+ end_date = user_from_db["end_date_subscription"]
44
+ return end_date
45
+ # Sending Emails from Heroku: https://blairconrad.com/2020/03/05/libraryhippo-2020-sending-email-from-heroku/
46
+ # Send Email API: https://app.sendgrid.com/
47
+ # Signin and Signup page: https://shayff.medium.com/building-your-first-flask-rest-api-with-mongodb-and-jwt-e03f2d317f04
48
+ # SetUp Tesseract: https://towardsdatascience.com/deploy-python-tesseract-ocr-on-heroku-bbcc39391a8d
49
+ def check_user_from_db(current_user): #test
50
+ email_exists = importcsv.db.users.find_one({"email":current_user})
51
+ student_email_exists = importcsv.db.studentsubscriptions.find_one({"email":current_user})
52
+ if email_exists:
53
+ user_from_db = list(importcsv.db.users.find({"email": current_user}))[0] # Gets wanted data for user
54
+ return user_from_db
55
+ elif student_email_exists:
56
+ user_from_db = list(importcsv.db.studentsubscriptions.find({"email": current_user}))[0]
57
+ return user_from_db
58
+
59
+
60
+ @app.route('/',methods=['GET'])
61
+ @cross_origin() # allow all origins all methods.
62
+ def index():
63
+ return "Hello World"
64
+ @app.route('/test',methods=['POST'])
65
+ @cross_origin() # allow all origins all methods.
66
+ def test():
67
+ data = request.get_json()
68
+ databack = data['data'] + ' from backend'
69
+ return {"result":databack }
70
+
71
+ @app.route("/sendmail",methods=["POST"])
72
+ @cross_origin()
73
+ def sendmail():
74
+ data = request.get_json()
75
+ now = datetime.now().strftime("%c")
76
+ msg = Message("Mail from LibraryHippo", recipients=["[email protected]"])
77
+ msg.body = f"test mail from LibraryHippo at {now}"
78
+ msg.html = f"<h1>Test mail from LibraryHippo</h1><p>It's now {now}."
79
+ mail.send(msg)
80
+ return f"Sent mail at {now}"
81
+ @app.route("/revisionbankstripepayment",methods=["POST"])
82
+ @cross_origin() # allow all origins all methods.
83
+ @jwt_required()
84
+ def revisionbankstripepayment():
85
+ current_user = get_jwt_identity() # outputs the email of the user [email protected]
86
+ if current_user:
87
+ try:
88
+ data = request.get_json()
89
+ price = data["price"]
90
+ stripe.api_key = "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"
91
+ #"sk_test_51La4WnLpfbhhIhYRjP1w036wUwBoatAgqNRYEoj9u6jMd7GvSmBioKgmwJsabjgAY8V5W8i2r3QdelOPe5VNOueB00zDxeXtDQ"
92
+
93
+ striperesponse = stripe.PaymentIntent.create(
94
+ amount=round(price*100),
95
+ currency="gbp",
96
+ payment_method_types=["card"],
97
+ )
98
+ clientsecret= striperesponse["client_secret"]
99
+ #print(clientsecret)
100
+ return {"clientsecret":clientsecret}
101
+ except Exception as ex:
102
+ return {"error":f"{type(ex)}-{ex}"}
103
+
104
+ @app.route('/revisionbanktranslate',methods=['POST'])
105
+ @cross_origin() # allow all origins all methods.
106
+ def revisionbanktranslate():
107
+ def read_img(img):
108
+ pytesseract.pytesseract.tesseract_cmd = "/app/.apt/usr/bin/tesseract"
109
+ text = pytesseract.image_to_string(img,
110
+ lang="eng",
111
+ config='--dpi 300 --psm 6 --oem 2 -c tessedit_char_blacklist=][|~_}{=!#%&«§><:;—?¢°*@,')
112
+
113
+ return(text)
114
+ try:
115
+ # TODO Use Tesseract OCR to get the text from the image hello
116
+ data = request.get_json()
117
+ img = data["revisioncardscreenshot"].replace("data:image/png;base64,","").replace("data:image/jpeg;base64,","")
118
+ # TODO Next Remove Blurriness and Noise from the image with cv2
119
+ #https://pyimagesearch.com/2017/07/10/using-tesseract-ocr-python/
120
+ img_obj =ImageOps.grayscale(Image.open(BytesIO(base64.b64decode(img))))
121
+ text = read_img(img_obj)
122
+
123
+ return {"revisioncardscreenshotext":text }
124
+ #return {"result":data}
125
+ except Exception as e:
126
+ return {f"error":f"{type(e)},{str(e)}"}
127
+
128
+
129
+ @app.route('/getedexcelqp',methods=['POST'])
130
+ @cross_origin() # allow all origins all methods.
131
+ @jwt_required()
132
+ def getedexcelqp():
133
+ current_user = get_jwt_identity() # outputs the email of the user [email protected]
134
+ if current_user:
135
+ try:
136
+ data = request.get_json()
137
+ edexcelpapers = list(importcsvqp.db.edexcelpapers.find({data["edexcelpaper"]:{"$exists":"true"}}))[0]
138
+ del edexcelpapers["_id"]
139
+ return {"edexcelpaper":edexcelpapers}
140
+ except Exception as e:
141
+ return {f"error":f"{type(e)},{str(e)}"}
142
+ @app.route('/getcomputerscienceqp',methods=['POST'])
143
+ @cross_origin() # allow all origins all methods.
144
+ @jwt_required()
145
+ def getcomputerscienceqp():
146
+ current_user = get_jwt_identity() # outputs the email of the user [email protected]
147
+ if current_user:
148
+ try:
149
+ data = request.get_json()
150
+ edexcelpapers = list(importcsvqp1.db.computerscienceqp.find({data["aqacomputerscience"]:{"$exists":"true"}}))[0]
151
+ del edexcelpapers["_id"]
152
+ return edexcelpapers # {"aqacomputerscience":edexcelpapers}
153
+ except Exception as e:
154
+ return {f"error":f"{type(e)},{str(e)}"}
155
+ @app.route('/getcomputersciencems',methods=['POST'])
156
+ @cross_origin() # allow all origins all methods.
157
+ @jwt_required()
158
+ def getcomputersciencems():
159
+ current_user = get_jwt_identity() # outputs the email of the user [email protected]
160
+ if current_user:
161
+ try:
162
+ data = request.get_json()
163
+ edexcelpapers = list(importcsvqp1.db.computersciencems.find({data["aqacomputerscience"]:{"$exists":"true"}}))[0]
164
+ del edexcelpapers["_id"]
165
+ return edexcelpapers # {"aqacomputerscience":edexcelpapers}
166
+ except Exception as e:
167
+ return {f"error":f"{type(e)},{str(e)}"}
168
+ @app.route('/getphysicsocrqp',methods=['POST'])
169
+ @cross_origin() # allow all origins all methods.
170
+ @jwt_required()
171
+ def getphysicsocrqp():
172
+ current_user = get_jwt_identity() # outputs the email of the user [email protected]
173
+ if current_user:
174
+ try:
175
+ data = request.get_json()
176
+ if data["subject"] == "physics":
177
+ edexcelpapers = list(importcsvqp1.db.physicsocrqp.find({data["questionpapersubject"]:{"$exists":"true"}}))[0]
178
+ elif data["subject"] == "chemistry":
179
+ edexcelpapers = list(importcsvqp.db.chemistryaqaqp.find({data["questionpapersubject"]:{"$exists":"true"}}))[0]
180
+ elif data["subject"] == "biology":
181
+ edexcelpapers = list(importcsvqp.db.biologyaqaqp.find({data["questionpapersubject"]:{"$exists":"true"}}))[0]
182
+
183
+ del edexcelpapers["_id"]
184
+ #print(edexcelpapers)
185
+ if data["scheme"] == "qp":
186
+ return {"questionpapersubject":edexcelpapers[data["questionpapersubject"]]["questionpaper"]}
187
+ elif data["scheme"] == "ms":
188
+ return {"questionpapersubject":edexcelpapers[data["questionpapersubject"]]["markscheme"]}
189
+ except Exception as e:
190
+ return {f"error":f"{type(e)},{str(e)}"}
191
+
192
+
193
+ @app.route('/storeocrrevisioncards',methods=['POST'])
194
+ @jwt_required()
195
+ @cross_origin() # allow all origins all methods.
196
+ def storeocrrevisioncards():
197
+ current_user = get_jwt_identity() # outputs the email of the user [email protected]
198
+ if current_user:
199
+ try:
200
+ data_json = request.get_json()
201
+ data = data_json["revisioncardscheduler"]
202
+ email_exists = importcsv.db.accountrevisioncards.find_one({"email":current_user})
203
+ if email_exists: # Checks if email exists
204
+ cards_not_exist = []
205
+ user_revision_cards = list(importcsv.db.accountrevisioncards.find({"email": current_user}))[0] # Gets the email.
206
+
207
+ #print(user_revision_cards)
208
+ for card in data["revisioncards"]: # Checks if the revision card exists in the database.
209
+ if card not in user_revision_cards["revisioncards"]:
210
+ cards_not_exist.append(card) # If not, add it to the list.
211
+ #cards_that_exist.append(card)
212
+ if cards_not_exist != []:
213
+ new_cards = cards_not_exist + user_revision_cards["revisioncards"] # adds new cards to the list.
214
+ user_revision_cards["revisioncards"] = new_cards # Updates the list.
215
+ del user_revision_cards["_id"]
216
+ user_revision_cards["email"] = current_user # Sets the email to the current user.
217
+ importcsv.db.accountrevisioncards.delete_many({"email":current_user}) # Allows data to be updated.
218
+ importcsv.db.accountrevisioncards.insert_one(user_revision_cards) # Inserts the new data.
219
+ return {"message":"revision cards updated"}
220
+ elif cards_not_exist == []: # If the cards are already in the database, return a message.
221
+ return {"message":"No new cards"}
222
+
223
+ elif not email_exists:
224
+ return {"message": "account doesn't exist"}
225
+ except Exception as ex:
226
+ print(type(ex),ex)
227
+ @app.route('/storerevisioncards',methods=['POST'])
228
+ @cross_origin() # allow all origins all methods.
229
+ @jwt_required()
230
+ def storerevisioncards():
231
+ try:
232
+ current_user = get_jwt_identity()
233
+ if current_user:
234
+ data_json = request.get_json() # test
235
+ data = data_json["revisioncardscheduler"]
236
+ email_exists = importcsv.db.accountrevisioncards.find_one({"email":current_user})
237
+ if email_exists: # Checks if email exists
238
+ cards_not_exist = []
239
+ user_revision_cards = list(importcsv.db.accountrevisioncards.find({"email": current_user}))[0] # Gets the email.
240
+
241
+ #print(user_revision_cards)
242
+ for card in data["revisioncards"]: # Checks if the revision card exists in the database.
243
+ if card not in user_revision_cards["revisioncards"]:
244
+ cards_not_exist.append(card) # If not, add it to the list.
245
+ #cards_that_exist.append(card)
246
+ if cards_not_exist != []:
247
+ new_cards = cards_not_exist + user_revision_cards["revisioncards"] # adds new cards to the list.
248
+ user_revision_cards["revisioncards"] = new_cards # Updates the list.
249
+ del user_revision_cards["_id"]
250
+ user_revision_cards["email"] = current_user # Sets the email to the current user.
251
+ importcsv.db.accountrevisioncards.delete_many({"email":current_user}) # Allows data to be updated.
252
+ importcsv.db.accountrevisioncards.insert_one(user_revision_cards) # Inserts the new data.
253
+ return {"message":"revision cards updated"}
254
+ elif cards_not_exist == []: # If the cards are already in the database, return a message.
255
+ return {"message":"No new cards"}
256
+
257
+ elif not email_exists:
258
+ data["email"] = current_user
259
+ importcsv.db.accountrevisioncards.insert_one(data)
260
+
261
+ return {"message": "revision card stored"}
262
+ except Exception as ex:
263
+ print(type(ex),ex)
264
+ @app.route('/changesendtoemail',methods=['PUT'])
265
+ @cross_origin() # allow all origins all methods.
266
+ @jwt_required()
267
+ def changesendtoemail(): # TODO
268
+ current_user = get_jwt_identity()
269
+ if current_user:
270
+ try:
271
+ data = request.get_json()
272
+ email_exists = importcsv.db.accountrevisioncards.find_one({"email":current_user})
273
+ if email_exists:
274
+ scheduled_exists = importcsv.db.scheduledcards.find_one({"email":current_user})
275
+ if scheduled_exists:
276
+ user_scheduled_cards = list(importcsv.db.scheduledcards.find({"email": current_user}))[0]
277
+ importcsv.db.scheduledcards.delete_many(user_scheduled_cards)
278
+ del user_scheduled_cards["sendtoemail"]
279
+ sendtoemailscheduled = user_scheduled_cards["sendtoemail"]
280
+ user_scheduled_cards.update({"sendtoemail": sendtoemailscheduled})
281
+ importcsv.db.scheduledcards.insert_one(user_scheduled_cards)
282
+
283
+
284
+ user_revision_cards = list(importcsv.db.accountrevisioncards.find({"email": current_user}))[0]
285
+ importcsv.db.accountrevisioncards.delete_many(user_revision_cards)
286
+ del user_revision_cards["sendtoemail"]
287
+ sendtoemail = data["sendtoemail"]
288
+ user_revision_cards.update({"sendtoemail": sendtoemail})
289
+ importcsv.db.accountrevisioncards.insert_one(user_revision_cards)
290
+ return jsonify({"message": "Send to email changed."})
291
+ elif not email_exists:
292
+ return {"message":"email does not exist"}
293
+ except Exception as ex:
294
+ return {f"error":f"{type(ex)},{str(ex)}"}
295
+ @app.route('/changerevisioncard',methods=['POST'])
296
+ @cross_origin() # allow all origins all methods.
297
+ @jwt_required()
298
+ def changerevisioncard():
299
+ current_user = get_jwt_identity()
300
+ if current_user:
301
+ try:
302
+ data = request.get_json()
303
+ email_exists = importcsv.db.accountrevisioncards.find_one({"email":current_user})
304
+ if email_exists: # Checks if email exists
305
+ # TODO Slightly buggy here - removes old schedule from the database.
306
+ user_scheduled_cards = list(importcsv.db.scheduledcards.find({"email": current_user}))[0]
307
+ for card in user_scheduled_cards["revisioncards"]:
308
+ oldcard = {i:data[i] for i in data if i!='newrevisioncard'}
309
+ if card == oldcard:
310
+ user_scheduled_cards["revisioncards"].remove(card)
311
+ importcsv.db.scheduledcards.delete_many({"email":current_user})
312
+ importcsv.db.scheduledcards.insert_one(user_scheduled_cards)
313
+
314
+ user_revision_cards = list(importcsv.db.accountrevisioncards.find({"email": current_user}))[0]
315
+ for card in user_revision_cards["revisioncards"]:
316
+ oldcard = {i:data[i] for i in data if i!='newrevisioncard'}
317
+ if card == oldcard:
318
+ user_revision_cards["revisioncards"].remove(card)
319
+ del data["revisioncard"]
320
+ data["revisioncard"] = data["newrevisioncard"]
321
+ del data["newrevisioncard"]
322
+ user_revision_cards["revisioncards"].append(data)
323
+ importcsv.db.accountrevisioncards.delete_many({"email":current_user})
324
+ importcsv.db.accountrevisioncards.insert_one(user_revision_cards)
325
+ return {"message":"revision card changed."}
326
+ except Exception as ex:
327
+ return {f"error":f"{type(ex)},{str(ex)}"}
328
+
329
+
330
+
331
+ @app.route('/getrevisioncards',methods=['GET'])
332
+ @cross_origin() # allow all origins all methods.
333
+ @jwt_required()
334
+ def getrevisioncards():
335
+ current_user = get_jwt_identity()
336
+ if current_user:
337
+ try:
338
+ email_exists = importcsv.db.accountrevisioncards.find_one({"email":current_user})
339
+ if email_exists: # Checks if email exists
340
+ user_revision_cards = list(importcsv.db.accountrevisioncards.find({"email": current_user}))[0]
341
+ del user_revision_cards["_id"],user_revision_cards["email"]
342
+ return user_revision_cards
343
+ elif not email_exists:
344
+ return {"message":"No revision cards"} # Send in shape of data
345
+ except Exception as ex:
346
+ return {f"error":f"{type(ex)},{str(ex)}"}
347
+ @app.route('/uploadrevisioncardtxtfile',methods=['POST'])
348
+ @cross_origin() # allow all origins all methods.
349
+ @jwt_required()
350
+ def uploadrevisioncardtxtfile():
351
+ try:
352
+ current_user = get_jwt_identity()
353
+ if current_user:
354
+ file = request.files["file"]
355
+ if file:
356
+ return {"message":file}
357
+ elif not file:
358
+ {"message":"No file"}
359
+ except Exception as ex:
360
+ return {f"error":f"{type(ex)},{str(ex)}"}
361
+
362
+
363
+ @app.route('/removerevisioncard',methods=['POST'])
364
+ @cross_origin() # allow all origins all methods.
365
+ @jwt_required()
366
+ def removerevisioncard():
367
+ current_user = get_jwt_identity()
368
+ if current_user:
369
+ try:
370
+ data = request.get_json()
371
+ email_exists = importcsv.db.accountrevisioncards.find_one({"email":current_user})
372
+ if email_exists: # Checks if email exists
373
+ # Remove the revision card from the database.
374
+ user_revision_cards = list(importcsv.db.accountrevisioncards.find({"email": current_user}))[0]
375
+ for card in user_revision_cards["revisioncards"]:
376
+ if card == data:
377
+ user_revision_cards["revisioncards"].remove(card)
378
+ importcsv.db.accountrevisioncards.delete_many({"email":current_user})
379
+ importcsv.db.accountrevisioncards.insert_one(user_revision_cards)
380
+ # Remove the revision card from the scheduled cards
381
+ try:
382
+ user_scheduled_cards = list(importcsv.db.scheduledcards.find({"email": current_user}))[0]
383
+ for card in user_scheduled_cards["revisioncards"]:
384
+ if card == data:
385
+ user_scheduled_cards["revisioncards"].remove(card)
386
+ importcsv.db.scheduledcards.delete_many({"email":current_user})
387
+ importcsv.db.scheduledcards.insert_one(user_scheduled_cards)
388
+ return {"message":"revision card removed"}
389
+ except IndexError as iex:
390
+ return {"message":"revision card removed"}
391
+
392
+ except Exception as ex:
393
+ return {f"error":f"{type(ex)},{str(ex)}"}
394
+ @app.route('/schedulerevisioncard',methods=['POST'])
395
+ @cross_origin() # allow all origins all methods.
396
+ @jwt_required()
397
+ def schedulerevisioncard():
398
+ try:
399
+ current_user = get_jwt_identity()
400
+ if current_user:
401
+ data = request.get_json() # test
402
+ email_exists = importcsv.db.scheduledcards.find_one({"email":current_user})
403
+ if email_exists: # Checks if email exists
404
+ cards_not_exist = []
405
+ user_scheduled_cards = list(importcsv.db.scheduledcards.find({"email": current_user}))[0] # Gets the email.
406
+
407
+ #print(user_revision_cards)
408
+ for card in data["revisioncards"]: # Checks if the revision card exists in the database.
409
+ if card not in user_scheduled_cards["revisioncards"]:
410
+ cards_not_exist.append(card) # If not, add it to the list.
411
+ #cards_that_exist.append(card)
412
+ if cards_not_exist != []:
413
+ new_cards = cards_not_exist + user_scheduled_cards["revisioncards"] # adds new cards to the list.
414
+ user_scheduled_cards["revisioncards"] = new_cards # Updates the list.
415
+ del user_scheduled_cards["_id"]
416
+ user_scheduled_cards["email"] = current_user # Sets the email to the current user.
417
+ importcsv.db.scheduledcards.delete_many({"email":current_user}) # Allows data to be updated.
418
+ importcsv.db.scheduledcards.insert_one(user_scheduled_cards) # Inserts the new data.
419
+ return {"message":"revision cards scheduled"}
420
+ elif cards_not_exist == []: # If the cards are already in the database, return a message.
421
+ return {"message":"revision cards already scheduled"}
422
+
423
+ elif not email_exists:
424
+ data["email"] = current_user
425
+ importcsv.db.scheduledcards.insert_one(data)
426
+
427
+ return {"message": "revision card scheduled"}
428
+ except Exception as ex:
429
+ print(type(ex),ex)
430
+ @app.route('/unscheduleallrevisioncard',methods=['DELETE'])
431
+ @cross_origin() # allow all origins all methods.
432
+ @jwt_required()
433
+ def unscheduleallrevisioncard():
434
+ current_user = get_jwt_identity()
435
+ if current_user:
436
+ try:
437
+ email_exists = importcsv.db.scheduledcards.find_one({"email":current_user})
438
+ if email_exists: # Checks if email exists
439
+ user_revision_cards = list(importcsv.db.scheduledcards.find({"email": current_user}))[0]
440
+ user_revision_cards["revisioncards"] = []
441
+ importcsv.db.scheduledcards.delete_many({"email":current_user})
442
+ importcsv.db.scheduledcards.insert_one(user_revision_cards)
443
+ return {"message":"Allrevision card unscheduled"}
444
+ except Exception as ex:
445
+ return {f"error":f"{type(ex)},{str(ex)}"}
446
+ @app.route('/unschedulerevisioncard',methods=['POST'])
447
+ @cross_origin() # allow all origins all methods.
448
+ @jwt_required()
449
+ def unschedulerevisioncard():
450
+ current_user = get_jwt_identity()
451
+ if current_user:
452
+ try:
453
+ data = request.get_json()
454
+ email_exists = importcsv.db.scheduledcards.find_one({"email":current_user})
455
+ if email_exists: # Checks if email exists
456
+
457
+ user_revision_cards = list(importcsv.db.scheduledcards.find({"email": current_user}))[0]
458
+ for card in user_revision_cards["revisioncards"]:
459
+ if card == data:
460
+ user_revision_cards["revisioncards"].remove(card)
461
+ importcsv.db.scheduledcards.delete_many({"email":current_user})
462
+ importcsv.db.scheduledcards.insert_one(user_revision_cards)
463
+ return {"message":"revision card unscheduled"}
464
+ except Exception as ex:
465
+ return {f"error":f"{type(ex)},{str(ex)}"}
466
+ @app.route('/sendnowrevisioncard',methods=['POST'])
467
+ @cross_origin() # allow all origins all methods.
468
+ @jwt_required()
469
+ def sendnowrevisioncard():
470
+ try:
471
+ current_user = get_jwt_identity()
472
+ if current_user:
473
+ data = request.get_json()
474
+ now = datetime.now().strftime("%c")
475
+ message = f"""{data['revisioncards'][0]['revisioncardtitle']}{data["revisioncards"][0]["revisioncard"]}"""
476
+ response = requests.post("http://0.0.0.0:7860/raspsendemail",json={"raspsendemail":{"email":data["sendtoemail"],"message":message,"subject":f"{data['revisioncards'][0]['subject']} Send Now"}})
477
+ #print(response.text)
478
+ #msg = Message(f"{data['revisioncards'][0]['subject']} Send Now", recipients=[data["sendtoemail"]]) # "[email protected]"
479
+ #msg.body = f"Mail from RevisionCard Send Now at {now}"
480
+ #if "!DOCTYPE" not in data["revisioncards"][0]["revisioncard"] or "h1" not in data["revisioncards"][0]["revisioncard"]:
481
+ # msg.html = f"""<pre>{data['revisioncards'][0]['revisioncardtitle']}
482
+ # {data["revisioncards"][0]["revisioncard"]}</pre>"""
483
+ #elif "!DOCTYPE" in data["revisioncards"][0]["revisioncard"] or "h1" in data["revisioncards"][0]["revisioncard"]:
484
+ # msg.html = f"""
485
+ # {data['revisioncards'][0]['revisioncardtitle']}
486
+ # {data["revisioncards"][0]["revisioncard"]}
487
+ # """
488
+ #print(msg)
489
+ #mail.send(msg)
490
+ return {"message":"revision card sent"}
491
+ except Exception as ex:
492
+ return {f"error":f"{type(ex)},{str(ex)}"}
493
+ @app.route('/checkschedulerevisioncard',methods=['GET'])
494
+ @cross_origin() # allow all origins all methods.
495
+ @jwt_required()
496
+ def checkschedulerevisioncard():
497
+ current_user = get_jwt_identity()
498
+ if current_user:
499
+ try:
500
+ email_exists = importcsv.db.scheduledcards.find_one({"email":current_user})
501
+ if email_exists: # Checks if email exists
502
+ user_scheduled_cards = list(importcsv.db.scheduledcards.find({"email": current_user}))[0]
503
+ del user_scheduled_cards["_id"],user_scheduled_cards["email"],user_scheduled_cards["revisionscheduleinterval"],user_scheduled_cards["sendtoemail"]
504
+ return user_scheduled_cards
505
+ elif not email_exists:
506
+ return {"message":"revision cards not scheduled"} # Send in shape of data
507
+ except Exception as ex:
508
+ return {f"error":f"{type(ex)},{str(ex)}"}
509
+
510
+ @app.route('/fmathsqp',methods=['POST'])
511
+ @cross_origin() # allow all origins all methods.
512
+ @jwt_required()
513
+ def fmathsqp():
514
+ current_user = get_jwt_identity() # outputs the email of the user [email protected]
515
+ if current_user:
516
+ datajson = request.get_json()
517
+ try:
518
+ main_qp_url = "https://www.physicsandmathstutor.com/a-level-maths-papers/"
519
+ data = datajson["furthermaths"]
520
+ email = data["email"]
521
+ book_inp = data["furthermathsbook"]
522
+ topic_inp = data["furthermathstopic"]
523
+ platform = data["platform"]
524
+ qp_sections = {"Core":["c1",'c2','c3','c4'],"Mechanics":['m1','m2','m3','m4','m5'],"Statistics":['s1','s2','s3','s4'],'Further Pure':['fp1','fp2','fp3'],'Decision Maths':['d1','d2']}
525
+ if "c".lower() in book_inp.lower():
526
+ book_choice = "c"
527
+ elif "m".lower() in book_inp.lower():
528
+ book_choice = "m"
529
+ elif "s".lower() in book_inp.lower():
530
+ book_choice = "s"
531
+ elif "fp".lower() in book_inp.lower():
532
+ book_choice = "fp"
533
+ elif "d".lower() in book_inp.lower():
534
+ book_choice = "d"
535
+ elif "a".lower() in book_inp.lower():
536
+ book_choice = "a"
537
+ else:
538
+ return {"result": "doesn't exist"}
539
+ if book_choice != "a":
540
+ endpoints = [endpoint for val in qp_sections.values() for endpoint in val if book_choice in endpoint]
541
+ elif book_choice == "a":
542
+ endpoints = [endpoint for val in qp_sections.values() for endpoint in val]
543
+
544
+
545
+ pdf_result = []
546
+ pdf_titles = []
547
+ def qp_extraction(qp_url,end):
548
+ headers = {"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:66.0) Gecko/20100101 Firefox/66.0","Accept-Encoding": "gzip, deflate", "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8","DNT": "1", "Connection": "close", "Upgrade-Insecure-Requests": "1"}
549
+ response_topic = requests.get(f"{qp_url}/{end}-by-topic/",headers=headers).text
550
+ #if "This site is currently under going scheduled maintenance." in response_topic:
551
+ # return {"error":"Physics maths tutor is in maintenance mode."}
552
+ soup = BeautifulSoup(response_topic,features='lxml')
553
+ for child in soup.find_all(['a'],href=True):
554
+ if topic_inp.lower() in str(child.text).lower():
555
+ pdf_url = child['href']
556
+ #print(pdf_url)
557
+ #print(f'{str(child.text).capitalize()}.pdf')
558
+ pdf_titles.append(f'{str(child.text).capitalize()}.pdf')
559
+ pdf_result.append(pdf_url)
560
+ #response = requests.get(pdf_url)
561
+ #pdf_result.append(str(response.content).replace("b'","").replace("'",""))
562
+
563
+
564
+
565
+
566
+ #print(endpoints)
567
+ def topic_extraction(end):
568
+ qp_extraction(main_qp_url,end)
569
+
570
+ def threads_url():
571
+ #threads = 60 # 20 # TODO Number of threads may be blowing up the router.
572
+ threads = 4
573
+ with concurrent.futures.ThreadPoolExecutor(max_workers=threads) as executor: #max_workers=threads
574
+ executor.map(topic_extraction,endpoints)
575
+ threads_url()
576
+ message = """
577
+ The Further Maths question papers, email has been sent to you:
578
+ """
579
+ linkmessage = """
580
+ The Further Maths question papers links:
581
+ """
582
+
583
+ #random.shuffle(pdf_result)
584
+ #random.shuffle(pdf_titles)
585
+ if pdf_result != []:
586
+ if len(pdf_result) > 5:
587
+ pdf_slice = round(len(pdf_result) * (100/100))
588
+ else:
589
+ pdf_slice = round(len(pdf_result) * (100/100))
590
+ for link,title in zip(pdf_result[:pdf_slice],pdf_titles[:pdf_slice]):
591
+ linkmessage += "<br>"
592
+ linkmessage += f"{title}" + "<br>"
593
+ linkmessage += link.replace(" ",'%20') + "<br>"
594
+ for i in pdf_titles:
595
+ message += "\n"
596
+ message += i + "\n"
597
+
598
+
599
+
600
+ user_from_db = check_user_from_db(current_user)
601
+ student_email_exists = importcsv.db.studentsubscriptions.find_one({"email":current_user})
602
+ if "end_date_subscription" in user_from_db:
603
+ end_date = getendsubscription(current_user)
604
+ if user_from_db["emailsleft"] <= 0:
605
+ if platform == "app":
606
+ pdf_response = {"furthermathsresult":{"furthermathsmessage":message}} # "furthermathslinks":pdf_result,"furthermathstitles":pdf_titles,"furthermathslinkmessage":linkmessage
607
+ elif platform == "web":
608
+ pdf_response = {"furthermathsresult":{"furthermathsmessage":linkmessage,"emailcount":0,"end_date_subscription":end_date}}# "furthermathslinks":pdf_result,"furthermathstitles":pdf_titles,"furthermathslinkmessage":linkmessage
609
+ return pdf_response
610
+
611
+ elif user_from_db["emailsleft"] > 0:
612
+ now = datetime.now().strftime("%c")
613
+ message = f"""
614
+ <h1>The Further Maths question papers links:</h1>
615
+ <p>{linkmessage}</p>.
616
+ """
617
+ response = requests.post("http://0.0.0.0:7860/raspsendemail",json={"raspsendemail":{"email":email,"message":message,"subject":"FMathqp PDFs"}})
618
+
619
+ #msg = Message("FMathqp PDFs", recipients=[email]) # "[email protected]"
620
+ #msg.body = f"Mail from FMathqp at {now}"
621
+ #msg.html = f"""
622
+ #<h1>The Further Maths question papers links:</h1>
623
+ #<p>{linkmessage}</p>.
624
+ #"""
625
+
626
+ #mail.send(msg)
627
+ user_from_db.update({"emailsleft":int(user_from_db["emailsleft"])-1})
628
+ importcsv.db.users.update_one({"email": current_user}, {"$set": user_from_db},upsert=True)
629
+ if platform == "app":
630
+ pdf_response = {"furthermathsresult":{"furthermathsmessage":message}} # "furthermathslinks":pdf_result,"furthermathstitles":pdf_titles,"furthermathslinkmessage":linkmessage
631
+ elif platform == "web":
632
+ pdf_response = {"furthermathsresult":{"furthermathsmessage":linkmessage,"emailcount":int(user_from_db["emailsleft"])-1,"end_date_subscription":end_date}}
633
+
634
+ return pdf_response
635
+ elif "end_date_subscription" not in user_from_db and not student_email_exists:
636
+ if platform == "app":
637
+ pdf_response = {"furthermathsresult":{"furthermathsmessage":message}} # "furthermathslinks":pdf_result,"furthermathstitles":pdf_titles,"furthermathslinkmessage":linkmessage
638
+ elif platform == "web":
639
+ pdf_response = {"furthermathsresult":{"furthermathsmessage":linkmessage,"emailcount":0,"end_date_subscription":99999999}}# "furthermathslinks":pdf_result,"furthermathstitles":pdf_titles,"furthermathslinkmessage":linkmessage
640
+ return pdf_response
641
+ elif "end_date_subscription" not in user_from_db and student_email_exists:
642
+ if user_from_db["emailsleft"] <= 0:
643
+ if platform == "app":
644
+ pdf_response = {"furthermathsresult":{"furthermathsmessage":message}} # "furthermathslinks":pdf_result,"furthermathstitles":pdf_titles,"furthermathslinkmessage":linkmessage
645
+ elif platform == "web":
646
+ pdf_response = {"furthermathsresult":{"furthermathsmessage":linkmessage,"emailcount":0,"end_date_subscription":end_date}}# "furthermathslinks":pdf_result,"furthermathstitles":pdf_titles,"furthermathslinkmessage":linkmessage
647
+ return pdf_response
648
+
649
+ elif user_from_db["emailsleft"] > 0:
650
+ now = datetime.now().strftime("%c")
651
+ message = f"""
652
+ <h1>The Further Maths question papers links:</h1>
653
+ <p>{linkmessage}</p>.
654
+ """
655
+ response = requests.post("http://0.0.0.0:7860/raspsendemail",json={"raspsendemail":{"email":email,"message":message,"subject":"FMathqp PDFs"}})
656
+
657
+ user_from_db.update({"emailsleft":int(user_from_db["emailsleft"])-1})
658
+ importcsv.db.studentsubscriptions.update_one({"email": current_user}, {"$set": user_from_db},upsert=True)
659
+ if platform == "app":
660
+ pdf_response = {"furthermathsresult":{"furthermathsmessage":message}} # "furthermathslinks":pdf_result,"furthermathstitles":pdf_titles,"furthermathslinkmessage":linkmessage
661
+ elif platform == "web":
662
+ pdf_response = {"furthermathsresult":{"furthermathsmessage":linkmessage,"emailcount":int(user_from_db["emailsleft"])-1,"end_date_subscription":99999999}}# "furthermathslinks":pdf_result,"furthermathstitles":pdf_titles,"furthermathslinkmessage":linkmessage
663
+ return pdf_response
664
+ elif pdf_result == []:
665
+ return {"error":"No further maths question papers available"}
666
+ except Exception as e:
667
+ return {f"error":f"{type(e)},{str(e)}"}
668
+ else:
669
+ return jsonify({"message": "Login first please."})
670
+
671
+
672
+ @app.route('/fmathsb',methods=['POST'])
673
+ @cross_origin() # allow all origins all methods.
674
+ @jwt_required()
675
+ def fmathsb():
676
+ #pure maths: 0, statistics mechanics: 1, core pure maths: 2, further pure maths: 3, further statistics: 4, further mechanics: 5, decision maths: 6"
677
+ # year/book: 1, year/book: 2
678
+ # {"furthermathsb":{"email":"[email protected]","furthermathsbbook": 0,"furthermathsbyear":2}}
679
+ # Output PureMaths Book 2
680
+ current_user = get_jwt_identity() # outputs the email of the user [email protected]
681
+ if current_user:
682
+ try:
683
+ sb_books_list = {"0":"pure-maths","1":"statistics-mechanics","2":"core-pure-maths","3":"further-pure-maths","4":"further-statistics","5":"further-mechanics","6":"decision-maths"}
684
+ datajson = request.get_json()
685
+ data = datajson["furthermathsb"]
686
+ email = data["email"]
687
+ sb_book_inp = str(data["furthermathsbbook"])
688
+ sb_year_inp = str(data["furthermathsbyear"])
689
+ sb_exercise = str(data["furthermathsbexercise"])
690
+ platform = data["platform"]
691
+
692
+ sb_book = sb_books_list[str(sb_book_inp)]
693
+ sb_year = str(sb_year_inp)
694
+
695
+ if sb_book == "pure-maths" or sb_book == "statistics-mechanics":
696
+ sb_url = f"https://www.physicsandmathstutor.com/maths-revision/solutionbanks/edexcel-{sb_book}-year-{sb_year}/"
697
+ #print(sb_url)
698
+ else:
699
+ sb_url = f"https://www.physicsandmathstutor.com/maths-revision/solutionbanks/edexcel-{sb_book}-{sb_year}/"
700
+
701
+ book_dir_name = f"{sb_book}{str(sb_year)}".capitalize()
702
+
703
+ response = requests.get(sb_url).text
704
+ soup = BeautifulSoup(response,features='lxml')
705
+ soup_a_tags = soup.find_all(['a'],href=True)
706
+ sb_result = []
707
+ sb_titles = []
708
+ def sb_extraction(child):
709
+ if "Exercise" in child.text and sb_exercise.upper() in child.text:
710
+ print(child.text)
711
+ pdf_url = child['href']
712
+ #response = requests.get(pdf_url)
713
+ sb_titles.append(f'{book_dir_name}-{str(child.text).capitalize()}.pdf')
714
+ sb_result.append(pdf_url)
715
+ def threads_url():
716
+ #threads = 60 # 20 # TODO Number of threads may be blowing up the router.
717
+ threads = 4
718
+ with concurrent.futures.ThreadPoolExecutor(max_workers=threads) as executor: #max_workers=threads
719
+ executor.map(sb_extraction,soup_a_tags)
720
+ threads_url()
721
+ if sb_result != []:
722
+ message = """
723
+ The Further Maths solution bank, email has been sent to you:
724
+ """
725
+ linkmessage = """
726
+ The Further Maths question papers links:
727
+ """
728
+ for link,title in zip(sb_result,sb_titles):
729
+ linkmessage += "<br>"
730
+ linkmessage += f"{title}" + "<br>"
731
+ linkmessage += link.replace(" ",'%20') + "<br>"
732
+ for i in sb_titles:
733
+ message += "\n"
734
+ message += i + "\n"
735
+ user_from_db = check_user_from_db(current_user)
736
+ student_email_exists = importcsv.db.studentsubscriptions.find_one({"email":current_user})
737
+ if "end_date_subscription" in user_from_db:
738
+ end_date = getendsubscription(current_user)
739
+ if user_from_db["emailsleft"] <= 0:
740
+ if platform == "app":
741
+ pdf_response = {"furthermathsresult":{"furthermathsmessage":message}} # "furthermathslinks":pdf_result,"furthermathstitles":pdf_titles,"furthermathslinkmessage":linkmessage
742
+ elif platform == "web":
743
+ pdf_response = {"furthermathsresult":{"furthermathsmessage":linkmessage,"emailcount":0,"end_date_subscription":end_date}}# "furthermathslinks":pdf_result,"furthermathstitles":pdf_titles,"furthermathslinkmessage":linkmessage
744
+ return pdf_response
745
+
746
+ elif user_from_db["emailsleft"] > 0:
747
+ now = datetime.now().strftime("%c")
748
+ message = f"""
749
+ <h1>The Further Maths Solution Bank links:</h1>
750
+ <p>{linkmessage}</p>.
751
+ """
752
+ response = requests.post("http://0.0.0.0:7860/raspsendemail",json={"raspsendemail":{"email":email,"message":message,"subject":"FMathSB PDFs"}})
753
+
754
+ #msg = Message("FMathSB PDFs", recipients=[email]) # "[email protected]"
755
+ #msg.body = f"Mail from FMathsb at {now}"
756
+ #msg.html = f"""
757
+ #<h1>The Further Maths Solution Bank links:</h1>
758
+ #<p>{linkmessage}</p>.
759
+ #"""
760
+
761
+ #mail.send(msg)
762
+ emailcount = int(user_from_db["emailsleft"])-1
763
+ user_from_db.update({"emailsleft":emailcount})
764
+ importcsv.db.users.update_one({"email": current_user}, {"$set": user_from_db},upsert=True)
765
+
766
+ if platform == "app":
767
+ pdf_response = {"furthermathsresult":{"furthermathsmessage":message}} # "furthermathslinks":pdf_result,"furthermathstitles":pdf_titles,"furthermathslinkmessage":linkmessage
768
+ elif platform == "web":
769
+ pdf_response = {"furthermathsresult":{"furthermathsmessage":linkmessage,"emailcount":emailcount,"end_date_subscription":end_date}}# "furthermathslinks":pdf_result,"furthermathstitles":pdf_titles,"furthermathslinkmessage":linkmessage
770
+ return pdf_response
771
+ elif "end_date_subscription" not in user_from_db and not student_email_exists:
772
+ if platform == "app":
773
+ pdf_response = {"furthermathsresult":{"furthermathsmessage":message}} # "furthermathslinks":pdf_result,"furthermathstitles":pdf_titles,"furthermathslinkmessage":linkmessage
774
+ elif platform == "web":
775
+ pdf_response = {"furthermathsresult":{"furthermathsmessage":linkmessage,"emailcount":0,"end_date_subscription":9999999}}# "furthermathslinks":pdf_result,"furthermathstitles":pdf_titles,"furthermathslinkmessage":linkmessage
776
+ return pdf_response
777
+ elif "end_date_subscription" not in user_from_db and student_email_exists:
778
+ if user_from_db["emailsleft"] <= 0:
779
+ if platform == "app":
780
+ pdf_response = {"furthermathsresult":{"furthermathsmessage":message}} # "furthermathslinks":pdf_result,"furthermathstitles":pdf_titles,"furthermathslinkmessage":linkmessage
781
+ elif platform == "web":
782
+ pdf_response = {"furthermathsresult":{"furthermathsmessage":linkmessage,"emailcount":0,"end_date_subscription":end_date}}# "furthermathslinks":pdf_result,"furthermathstitles":pdf_titles,"furthermathslinkmessage":linkmessage
783
+ return pdf_response
784
+
785
+ elif user_from_db["emailsleft"] > 0:
786
+ now = datetime.now().strftime("%c")
787
+ message = f"""
788
+ <h1>The Further Maths Solution Bank links:</h1>
789
+ <p>{linkmessage}</p>.
790
+ """
791
+ response = requests.post("http://0.0.0.0:7860/raspsendemail",json={"raspsendemail":{"email":email,"message":message,"subject":"FMathSB PDFs"}})
792
+
793
+ user_from_db.update({"emailsleft":int(user_from_db["emailsleft"])-1})
794
+ importcsv.db.studentsubscriptions.update_one({"email": current_user}, {"$set": user_from_db},upsert=True)
795
+ if platform == "app":
796
+ pdf_response = {"furthermathsresult":{"furthermathsmessage":message}} # "furthermathslinks":pdf_result,"furthermathstitles":pdf_titles,"furthermathslinkmessage":linkmessage
797
+ elif platform == "web":
798
+ pdf_response = {"furthermathsresult":{"furthermathsmessage":linkmessage,"emailcount":int(user_from_db["emailsleft"])-1,"end_date_subscription":9999999}}# "furthermathslinks":pdf_result,"furthermathstitles":pdf_titles,"furthermathslinkmessage":linkmessage
799
+ return pdf_response
800
+
801
+ elif sb_result == []:
802
+ return {f"error":f"No further maths solution bank for {sb_book} {sb_year}"}
803
+ except Exception as e:
804
+ return {f"error":f"{type(e)},{str(e)}"}
805
+ else:
806
+ return jsonify({"message": "Login first please."})
807
+ @app.route('/ocrsciencebookanswers',methods=['POST'])
808
+ @cross_origin() # allow all origins all methods.
809
+ @jwt_required()
810
+ def scienceocranswers():
811
+ current_user = get_jwt_identity() # outputs the email of the user [email protected]
812
+ if current_user:
813
+ datajson = request.get_json()
814
+
815
+ def ocrscienceanswers(querydata):
816
+ examboards = "OCR"
817
+ url = "https://global.oup.com/education/content/secondary/series/ocr-a-level-sciences/a-level-sciences-for-ocr-student-book-answers/?region=uk"
818
+ physicsanswerspdf = {}
819
+
820
+ response= requests.get(url).text
821
+ soup = BeautifulSoup(response,features='lxml')
822
+ for divele in soup.find_all('div',{'class':'content_block half_width enclosed'}): # inner_block text_only_single ##
823
+ if querydata in divele.text:
824
+ for a in divele.find_all("a",href=True):
825
+ if a["href"] != "?region=uk":
826
+ physicsanswerspdf.update({a.text.replace("\xa0",' '): a["href"].replace("?region=uk",'')})
827
+
828
+ result = {querydata:{examboards:physicsanswerspdf}}
829
+ return result
830
+ try:
831
+ data = datajson["physicsocr"]
832
+ email = data["email"]
833
+ subject = data["subject"] # physics, chemistry, biology
834
+ physicsocralph = data["physicsocralph"] # A or B
835
+ chapter = data["chapter"] # Chapter 1
836
+ year = data["year"] # AS/Year 1, A Level
837
+ platform = data["platform"] # web or app
838
+
839
+ query = f"{subject.capitalize()} {physicsocralph} {year}"
840
+ papers = ocrscienceanswers(query)
841
+ answerlink = papers[query]["OCR"][f"{chapter.capitalize()} (PDF)"].replace(" ",'%20')
842
+
843
+ user_from_db = check_user_from_db(current_user)
844
+ student_email_exists = importcsv.db.studentsubscriptions.find_one({"email":current_user})
845
+ if "end_date_subscription" in user_from_db:
846
+ end_date = getendsubscription(current_user)
847
+ if user_from_db["emailsleft"] <= 0:
848
+ result = {"scienceocranswers": answerlink,"emailcount":0,"end_date_subscription":end_date}
849
+ return result
850
+ elif user_from_db["emailsleft"] > 0:
851
+ now = datetime.now().strftime("%c")
852
+ message = f"""
853
+ <h1>OCR Science {query} Answers:</h1>
854
+ <p>{answerlink}</p>.
855
+ """
856
+ response = requests.post("http://0.0.0.0:7860/raspsendemail",json={"raspsendemail":{"email":email,"message":message,"subject":f"OCR {query} Answers"}})
857
+
858
+ #msg = Message(f"OCR {query} Answers", recipients=[email]) # "[email protected]"
859
+ #msg.body = f"Mail from {query} at {now}"
860
+ #msg.html = f"""
861
+ #<h1>OCR Science {query} Answers:</h1>
862
+ #<p>{answerlink}</p>.
863
+ #"""
864
+
865
+ #mail.send(msg)
866
+ emailcount = int(user_from_db["emailsleft"])-1
867
+ user_from_db.update({"emailsleft":emailcount})
868
+ importcsv.db.users.update_one({"email": current_user}, {"$set": user_from_db},upsert=True)
869
+ result = {"scienceocranswers": answerlink,"emailcount":emailcount,"end_date_subscription":end_date}
870
+ return result
871
+ elif "end_date_subscription" not in user_from_db and not student_email_exists:
872
+ result = {"scienceocranswers": answerlink,"emailcount":0,"end_date_subscription":9999999}
873
+ return result
874
+ elif "end_date_subscription" not in user_from_db and student_email_exists:
875
+ if user_from_db["emailsleft"] <= 0:
876
+ result = {"scienceocranswers": answerlink,"emailcount":0,"end_date_subscription":end_date}
877
+ return result
878
+ elif user_from_db["emailsleft"] > 0:
879
+ now = datetime.now().strftime("%c")
880
+ message = f"""
881
+ <h1>OCR Science {query} Answers:</h1>
882
+ <p>{answerlink}</p>.
883
+ """
884
+ response = requests.post("http://0.0.0.0:7860/raspsendemail",json={"raspsendemail":{"email":email,"message":message,"subject":f"OCR {query} Answers"}})
885
+ user_from_db.update({"emailsleft":int(user_from_db["emailsleft"])-1})
886
+ importcsv.db.studentsubscriptions.update_one({"email": current_user}, {"$set": user_from_db},upsert=True)
887
+ result = {"scienceocranswers": answerlink,"emailcount":int(user_from_db["emailsleft"])-1,"end_date_subscription":9999999}
888
+ return result
889
+ except Exception as e:
890
+ return {f"error":f"{type(e)},{str(e)}"}
891
+ else:
892
+ return jsonify({"message": "Login first please."})
893
+ @app.route('/physicsaqa',methods=['POST'])
894
+ @cross_origin() # allow all origins all methods.
895
+ @jwt_required()
896
+ def physicsaqa():
897
+ current_user = get_jwt_identity() # outputs the email of the user [email protected]
898
+ if current_user:
899
+ try:
900
+ datajson = request.get_json()
901
+ topicquestions = PhysicsAQA().collectdata()
902
+ data = datajson["physicsaqa"]
903
+ email = data["email"]
904
+ chapter = data["chapter"] # Section 1: Measurement & Their Errors
905
+ topic = data["topic"] # Constituents of the Atom or The Law of the Atom
906
+ platform = data["platform"] # web or app
907
+ try:
908
+ questionpaper = topicquestions[chapter][topic]
909
+ except Exception as ex:
910
+ return {"error":"chapter or topic not found"}
911
+ try:
912
+ markscheme = topicquestions[chapter][f"{topic} MS"]
913
+ except Exception as ex:
914
+ return {"error":"chapter or topic mark scheme not found"}
915
+
916
+
917
+ user_from_db = check_user_from_db(current_user)
918
+ student_email_exists = importcsv.db.studentsubscriptions.find_one({"email":current_user})
919
+ if "end_date_subscription" in user_from_db:
920
+ end_date = getendsubscription(current_user)
921
+ if user_from_db["emailsleft"] <= 0:
922
+ return {"physicsaqa":{"chapter":chapter,"topic":topic,"question paper":questionpaper,"markscheme":markscheme,"emailcount":emailcount,"end_date_subscription":end_date}}
923
+ elif user_from_db["emailsleft"] > 0:
924
+ now = datetime.now().strftime("%c")
925
+ message = f"""
926
+ <h1>PhysicsAqa Question Papers:</h1>
927
+ <p>{questionpaper}</p>
928
+ <p>{markscheme}</p>.
929
+ """
930
+ response = requests.post("http://0.0.0.0:7860/raspsendemail",json={"raspsendemail":{"email":email,"message":message,"subject":f"PhysicsAqa Papers"}})
931
+ #msg = Message(f"PhysicsAqa Papers", recipients=[email]) # "[email protected]"
932
+ #msg.body = f"Mail from physicsaqaApi at {now}"
933
+ #msg.html = f"""
934
+ #<h1>PhysicsAqa Question Papers:</h1>
935
+ #<p>{questionpaper}</p>
936
+ #<p>{markscheme}</p>.
937
+ #"""
938
+ #mail.send(msg)
939
+ emailcount = int(user_from_db["emailsleft"])-1
940
+ user_from_db.update({"emailsleft":emailcount})
941
+ importcsv.db.users.update_one({"email": current_user}, {"$set": user_from_db},upsert=True)
942
+ return {"physicsaqa":{"chapter":chapter,"topic":topic,"question paper":questionpaper,"markscheme":markscheme,"emailcount":emailcount,"end_date_subscription":end_date}}
943
+ elif "end_date_subscription" not in user_from_db and not student_email_exists:
944
+ return {"physicsaqa":{"chapter":chapter,"topic":topic,"question paper":questionpaper,"markscheme":markscheme,"emailcount":0,"end_date_subscription":9999999}}
945
+ # If it is a student account
946
+ elif "end_date_subscription" not in user_from_db and student_email_exists:
947
+ # Check number of emails left
948
+ if user_from_db["emailsleft"] <= 0:
949
+ return {"physicsaqa":{"chapter":chapter,"topic":topic,"question paper":questionpaper,"markscheme":markscheme,"emailcount":emailcount,"end_date_subscription":end_date}}
950
+ elif user_from_db["emailsleft"] > 0:
951
+ now = datetime.now().strftime("%c")
952
+ message = f"""
953
+ <h1>PhysicsAqa Question Papers:</h1>
954
+ <p>{questionpaper}</p>
955
+ <p>{markscheme}</p>.
956
+ """
957
+ response = requests.post("http://0.0.0.0:7860/raspsendemail",json={"raspsendemail":{"email":email,"message":message,"subject":f"PhysicsAqa Papers"}})
958
+
959
+ user_from_db.update({"emailsleft":int(user_from_db["emailsleft"])-1})
960
+ importcsv.db.studentsubscriptions.update_one({"email": current_user}, {"$set": user_from_db},upsert=True)
961
+ return {"physicsaqa":{"chapter":chapter,"topic":topic,"question paper":questionpaper,"markscheme":markscheme,"emailcount":int(user_from_db["emailsleft"])-1,"end_date_subscription":9999999}}
962
+
963
+ except TypeError as tex:
964
+ return {f"error":f"request is wrong shape {tex}"}
965
+ except Exception as ex:
966
+ return {f"error":f"{type(ex)} {str(ex)}"}
967
+ else:
968
+ return jsonify({"message": "Login first please."})
969
+
970
+
971
+ @app.route('/signupapi', methods=['POST'])
972
+ @cross_origin()
973
+ def signup():
974
+ try:
975
+ data = request.get_json()
976
+ data["id"] = ObjectId()
977
+ data["access"] = True
978
+ user = Users(**data)
979
+ signupdata = user.to_bson()
980
+ #print(signupdata)
981
+ email_exists = importcsv.db.users.find_one({"email": signupdata["email"]})
982
+ email_exists_student = importcsv.db.studentsubscriptions.find_one({"email": signupdata["email"]}) # Checks if student account exists
983
+ if email_exists or email_exists_student:
984
+ return jsonify({"message": "Email already exists"}) # , 400
985
+ elif not email_exists:
986
+ # Notifies who are the beta testers
987
+ #if datetime.now() < "2022-05-19T21:37:00.057084":
988
+ # signupdata.update({"betatest":"true"})
989
+ importcsv.db.users.insert_one(signupdata)
990
+ access_token = create_access_token(identity=signupdata["email"])
991
+ callback = {"status": "success","id": str(signupdata["_id"]),"access_token":access_token}
992
+ return callback
993
+ except Exception as ex:
994
+ error_detected = {"error": "error occured","errortype":type(ex), "error": str(ex)}
995
+ return error_detected
996
+ @app.route('/loginapi', methods=['POST'])
997
+ @cross_origin()
998
+ def login():
999
+ # Login API
1000
+ try:
1001
+ def provide_access_token(login_details,student=0):
1002
+ if student == 0:
1003
+ email_exists = list(importcsv.db.users.find({"email": login_details["email"]}))[0]
1004
+ elif student == 1:
1005
+ email_exists = list(importcsv.db.studentsubscriptions.find({"email": login_details["email"]}))[0]
1006
+ encrypted_password = hashlib.sha256(login_details["password"].encode('utf-8')).hexdigest()
1007
+ if email_exists["password"] == encrypted_password:
1008
+ access_token = create_access_token(identity=email_exists["email"])
1009
+ return access_token
1010
+ else:
1011
+ return "Wrong password"
1012
+
1013
+
1014
+ login_details = request.get_json()
1015
+ email_exists = importcsv.db.users.find_one({"email": login_details["email"]})
1016
+ email_exists_student = importcsv.db.studentsubscriptions.find_one({"email": login_details["email"]}) # Checks if student account exists
1017
+ if email_exists:
1018
+ access_token = provide_access_token(login_details,student=0)
1019
+ if access_token == "Wrong password":
1020
+ return jsonify({"message": "The username or password is incorrect."})
1021
+ else:
1022
+ return jsonify({"access_token": access_token}), 200
1023
+ elif email_exists_student:
1024
+ access_token = provide_access_token(login_details,student=1)
1025
+ if access_token == "Wrong password":
1026
+ return jsonify({"message": "The username or password is incorrect."})
1027
+ else:
1028
+ return jsonify({"access_token": access_token}), 200
1029
+ return jsonify({"message": "The username or password is incorrect."})
1030
+ except Exception as ex:
1031
+ return jsonify({"error": f"{type(ex)} {str(ex)}"})
1032
+ #
1033
+ @app.route('/forgotpassword', methods=['POST'])
1034
+ @cross_origin()
1035
+ def forgotpassword():
1036
+ # Login API
1037
+ data = request.get_json()
1038
+ try:
1039
+ #print(data["email"])
1040
+ access_token = create_access_token(identity=data["email"])
1041
+ # store token in database temporarily
1042
+ now = datetime.now().strftime("%c")
1043
+ response = requests.post("http://0.0.0.0:7860/raspsendemail",json={"raspsendemail":{"email":data["email"],"message":forgotpasswordemail(data["email"],access_token),"subject":f"RevsionBank Password Reset"}})
1044
+ #msg = Message(f"RevsionBank Password Reset", recipients=[data["email"]]) # "[email protected]"
1045
+ #msg.body = f"Mail from RevisionBank at {now}"
1046
+ #msg.html = forgotpasswordemail(data["email"],access_token)
1047
+ #mail.send(msg)
1048
+ return jsonify({"message": "Reset Email sent"})
1049
+ except Exception as ex:
1050
+ return {"error": f"{type(ex)} {str(ex)}"}
1051
+
1052
+ @app.route('/resetpassword', methods=['PUT'])
1053
+ @cross_origin()
1054
+ @jwt_required()
1055
+ def resetpassword():
1056
+ current_user = get_jwt_identity()
1057
+ if current_user:
1058
+ try:
1059
+ data = request.get_json()
1060
+ email_exists = importcsv.db.users.find_one({"email": current_user})
1061
+ #print(email_exists)
1062
+ if email_exists:
1063
+ user_from_db = list(importcsv.db.users.find({"email": current_user}))[0]
1064
+ #print(user_from_db)
1065
+ # TODO Delete password from here and replace.
1066
+ importcsv.db.users.delete_many(user_from_db)
1067
+ del user_from_db["password"]
1068
+ encrypted_password = hashlib.sha256(data["password"].encode('utf-8')).hexdigest()
1069
+ user_from_db.update({"password": encrypted_password})
1070
+ importcsv.db.users.insert_one(user_from_db)
1071
+ return jsonify({"message": "Password reset successful."})
1072
+ elif not email_exists:
1073
+ return {"message": "Email Doesn't exist."}
1074
+ except Exception as ex:
1075
+ return {"error": f"{type(ex)} {str(ex)}"}
1076
+
1077
+
1078
+
1079
+ @app.route('/storesubscription', methods=['POST'])
1080
+ @cross_origin()
1081
+ @jwt_required()
1082
+ def storesubscription():
1083
+ current_user = get_jwt_identity() # outputs the email of the user [email protected]
1084
+ if current_user:
1085
+ try:
1086
+ data = request.get_json()
1087
+ user_from_db = list(importcsv.db.users.find({"email": current_user}))[0] # Gets wanted data for user
1088
+ if data["subscription"] == 'basic':
1089
+ emailsleft = {'emailsleft': 0}
1090
+ elif data["subscription"] == 'standard':
1091
+ emailsleft = {'emailsleft': 40}
1092
+ elif data["subscription"] == 'premium' or data["subscription"] == 'educational':
1093
+ emailsleft = {'emailsleft': 10000000000}
1094
+ if data["subscription"] == "educational":
1095
+ user_from_db.update({"numofaccounts": 200}) # TODO Constant Value needs to be changed when frontend is changed
1096
+ user_from_db.update({"start_date_subscription": data["start_date_subscription"]})
1097
+ user_from_db.update({"end_date_subscription": data["end_date_subscription"]})
1098
+ user_from_db.update({"subscription": data["subscription"]}) # Updates the user with the new subscription
1099
+ user_from_db.update(emailsleft)
1100
+ importcsv.db.users.update_one( { "email": current_user}, {"$set": user_from_db}, upsert = True )
1101
+
1102
+ importcsv.db.subscriptionlog.insert_one({"email": user_from_db["email"],"start_date_subscription": data["start_date_subscription"], "end_date_subscription": data["end_date_subscription"], "subscription": data["subscription"], "emailsleft": emailsleft["emailsleft"]})
1103
+ return jsonify({"message": "Subscription Completed."})
1104
+ except Exception as ex:
1105
+ return {"error": f"{type(ex)}-{ex}"}
1106
+
1107
+ else:
1108
+ return jsonify({"message": "User not found"})
1109
+ @app.route('/storebetatester', methods=['POST']) # @jwt_required()
1110
+ @cross_origin()
1111
+ def storebetatester():
1112
+ data = request.get_json()
1113
+ emailsleft = {'emailsleft': 10000000000}
1114
+ email_exists = importcsv.db.users.find_one({"email": data["email"]})
1115
+ if email_exists:
1116
+ user_from_db = list(importcsv.db.users.find({"email": data["email"]}))[0] # Gets wanted data for user
1117
+ #user_from_db.update({"numofaccounts": 200}) # TODO Constant Value needs to be changed when frontend is changed
1118
+ date_now = datetime.now()
1119
+ datetime_delta = dt.timedelta(weeks=2)
1120
+ user_from_db.update({"start_date_subscription": date_now.isoformat()})
1121
+
1122
+ user_from_db.update({"end_date_subscription": (datetime_delta + date_now).isoformat()})
1123
+ user_from_db.update({"subscription": "premium"}) # Updates the user with the new subscription
1124
+ user_from_db.update(emailsleft)
1125
+ user_from_db.update({"betatester": "true"})
1126
+ importcsv.db.users.update_one( { "email": data["email"]}, {"$set": user_from_db}, upsert = True )
1127
+
1128
+ #importcsv.db.subscriptionlog.insert_one({"email": user_from_db["email"],"start_date_subscription": data["start_date_subscription"], "end_date_subscription": data["end_date_subscription"], "subscription": data["subscription"], "emailsleft": emailsleft["emailsleft"]})
1129
+ return jsonify({"message": "Beta Tester Subscription Completed."})
1130
+ elif not email_exists:
1131
+ return jsonify({"message": "User not found"})
1132
+ @app.route('/storeeducationalfreetrial', methods=['POST']) # @jwt_required()
1133
+ @cross_origin()
1134
+ def storeeducationalfreetrial():
1135
+ data = request.get_json()
1136
+ try:
1137
+ emailsleft = {'emailsleft': 10000000000}
1138
+ email_exists = importcsv.db.users.find_one({"email": data["email"]})
1139
+ if email_exists:
1140
+ user_from_db = list(importcsv.db.users.find({"email": data["email"]}))[0] # Gets wanted data for user
1141
+ #user_from_db.update({"numofaccounts": 200}) # TODO Constant Value needs to be changed when frontend is changed
1142
+ date_now = datetime.now()
1143
+ decimal_part = float(3 / 7)
1144
+ datetime_delta = dt.timedelta(weeks=4 + decimal_part)
1145
+ user_from_db.update({"start_date_subscription": date_now.isoformat()})
1146
+ user_from_db.update({"numofaccounts": 200})
1147
+
1148
+ user_from_db.update({"end_date_subscription": (datetime_delta + date_now).isoformat()})
1149
+ user_from_db.update({"subscription": "educational"}) # Updates the user with the new subscription
1150
+ user_from_db.update(emailsleft)
1151
+ importcsv.db.users.update_one( { "email": data["email"]}, {"$set": user_from_db}, upsert = True )
1152
+
1153
+ #importcsv.db.subscriptionlog.insert_one({"email": user_from_db["email"],"start_date_subscription": data["start_date_subscription"], "end_date_subscription": data["end_date_subscription"], "subscription": data["subscription"], "emailsleft": emailsleft["emailsleft"]})
1154
+ return jsonify({"message": "Educational Freetrial Subscription Completed."})
1155
+ elif not email_exists:
1156
+ return jsonify({"message": "User not found"})
1157
+ except Exception as ex:
1158
+ return {"error": f"{type(ex)}-{ex}"}
1159
+ @app.route('/scheduleeducationalfreetrial', methods=['POST']) # @jwt_required()
1160
+ @cross_origin()
1161
+ def scheduleeducationalfreetrial():
1162
+ data = request.get_json()
1163
+ try:
1164
+ regexdatetime = re.compile(r'\d\d\d\d-\d\d-\d\d')
1165
+ mo = regexdatetime.search(data["educationalfreetrialdate"])
1166
+ educationalfreetrialdate = mo.group()
1167
+ except AttributeError as aex:
1168
+ return {"error":r"Datetime shape is %Y-%m-%d"}
1169
+ try:
1170
+ email_exists = importcsv.db.users.find_one({"email": data["email"]})
1171
+ if email_exists:
1172
+ importcsv.db.schedulededucationalfreetrial.insert_one({"email": data["email"],"educationalfreetrialdate":educationalfreetrialdate})
1173
+ return jsonify({"message": "Educational Freetrial Scheduled."})
1174
+ elif not email_exists:
1175
+ return jsonify({"message": "User not found"})
1176
+ except Exception as ex:
1177
+ return {"error": f"{type(ex)}-{ex}"}
1178
+ @app.route('/deletescheduleeducationalfreetrial', methods=['POST']) # @jwt_required()
1179
+ @cross_origin()
1180
+ def deletescheduleeducationalfreetrial():
1181
+ data = request.get_json()
1182
+ current_user = data["email"]
1183
+ current_user = importcsv.db.users.find_one({"email": data["email"]})
1184
+ if current_user:
1185
+ try:
1186
+ user_from_db = list(importcsv.db.schedulededucationalfreetrial.find({"email": data["email"]}))[0]
1187
+ importcsv.db.schedulededucationalfreetrial.delete_many(user_from_db)
1188
+ return jsonify({"message":"Educational Freetrial Unscheduled."})
1189
+ except Exception as ex:
1190
+ return {"error": f"{type(ex)}-{ex}"}
1191
+ @app.route('/removebetatester', methods=['POST']) # @jwt_required()
1192
+ @cross_origin()
1193
+ def removebetatester():
1194
+ data = request.get_json()
1195
+ email_exists = importcsv.db.users.find_one({"email": data["email"]})
1196
+ if email_exists:
1197
+ user_from_db = list(importcsv.db.users.find({"email": data["email"]}))[0] # Gets wanted data for user
1198
+ importcsv.db.users.delete_many(user_from_db)
1199
+ del user_from_db["end_date_subscription"], user_from_db["start_date_subscription"],user_from_db["subscription"],user_from_db["emailsleft"], user_from_db["betatester"]
1200
+ importcsv.db.users.update_one( { "email": data["email"]}, {"$set": user_from_db}, upsert = True )
1201
+ return jsonify({"message": "Beta Tester Subscription Deleted."})
1202
+ elif not email_exists:
1203
+ return jsonify({"message": "User not found"})
1204
+ @app.route('/getsubscription', methods=['GET'])
1205
+ @cross_origin()
1206
+ @jwt_required()
1207
+ def getsubscription():
1208
+ current_user = get_jwt_identity() # outputs the email of the user [email protected]
1209
+ if current_user:
1210
+ try:
1211
+ user_from_db = list(importcsv.db.users.find({"email": current_user}))[0] # Gets wanted data for user
1212
+ end_date = user_from_db["end_date_subscription"]
1213
+ end_date_subscription = {"end_date_subscription": end_date}
1214
+ return jsonify(end_date_subscription)
1215
+ except Exception as ex:
1216
+ return {"error": f"{type(ex)}-{ex}"}
1217
+ @app.route('/getemailcount', methods=['GET'])
1218
+ @cross_origin()
1219
+ @jwt_required()
1220
+ def getemailcount():
1221
+ current_user = get_jwt_identity() # outputs the email of the user [email protected]
1222
+ if current_user:
1223
+ try:
1224
+ user_from_db = list(importcsv.db.users.find({"email": current_user}))[0] # Gets wanted data for user
1225
+ emailcount = user_from_db["emailsleft"]
1226
+ emailcountres = {"emailcount": emailcount}
1227
+ return jsonify(emailcountres)
1228
+ except Exception as ex:
1229
+ return {"error": f"{type(ex)}-{ex}"}
1230
+ @app.route('/storefreetrial', methods=['POST'])
1231
+ @cross_origin()
1232
+ @jwt_required()
1233
+ def storefreetrial():
1234
+ current_user = get_jwt_identity() # outputs the email of the user [email protected]
1235
+ if current_user:
1236
+ try:
1237
+ data = request.get_json()
1238
+ user_from_db = list(importcsv.db.users.find({"email": current_user}))[0] # Gets wanted data for user
1239
+ if 'freetrial' not in user_from_db:
1240
+ user_from_db.update({"freetrial": "true"})
1241
+ emailsleft = {'emailsleft': 10000000000}
1242
+ user_from_db.update({"start_date_subscription": data["start_date_subscription"]})
1243
+ user_from_db.update({"end_date_subscription": data["end_date_subscription"]})
1244
+ user_from_db.update({"subscription": data["subscription"]}) # Updates the user with the new subscription
1245
+ user_from_db.update(emailsleft)
1246
+ importcsv.db.users.update_one( { "email": current_user}, {"$set": user_from_db}, upsert = True )
1247
+ importcsv.db.users.update_one({"email": current_user}, {"$set": user_from_db}, upsert = True)
1248
+ importcsv.db.freetrialhistory.insert_one({"email": user_from_db["email"],"freetrial":"true"})
1249
+ return jsonify({"message": "Freetrial Redeemed."})
1250
+ elif 'freetrial' in user_from_db:
1251
+ return jsonify({"error": "Freetrial has already used."})
1252
+ except Exception as ex:
1253
+ return {"error": f"{type(ex)}-{ex}"}
1254
+ @app.route('/setstudentsubscriptions', methods=['POST'])
1255
+ @cross_origin()
1256
+ @jwt_required()
1257
+ def setstudentsubscriptions():
1258
+ current_user = get_jwt_identity() # outputs the email of the user [email protected]
1259
+ if current_user:
1260
+ # Hostemail is the primary key for the studentsubscription collection
1261
+ try:
1262
+ data = request.get_json()
1263
+ # {"hostemail": "[email protected]","hostnumofaccounts": 198,"studentemails": [{"email": "[email protected]","password": "mann35"},{"email": "[email protected]","password": "billy45"},{"email": "[email protected]","password": "bobby46"}],"studentemailsleft": 20,"studentsubscription": "student educational"}
1264
+ user_from_db = list(importcsv.db.users.find({"email": current_user}))[0] # Host emails data
1265
+ studentsnotexist = []
1266
+ for student in data["studentemails"]: # data["studentemails"] is a list of dictionaries [{"email":"[email protected]","password":"password"},{"email":"[email protected]","password":"password"}]
1267
+ student_user_from_db = importcsv.db.studentsubscriptions.find_one({"email": student["email"]}) # Checks if any of the emails added are in the database
1268
+ if not student_user_from_db: # If the email is not in the database, then we need to store the data into the database
1269
+ studentsnotexist.append(student) # Adds the email to the list of emails that do not exist in the database
1270
+
1271
+ if studentsnotexist == []: # If all data is already in the database, no need to store it.
1272
+ return jsonify({"message": "all students exist."})
1273
+ elif studentsnotexist != []: # If there are emails that are not in the database, we need to store the data into the database
1274
+ if user_from_db["numofaccounts"] > 0:
1275
+ for student in studentsnotexist: # Goes through the emails not in the database
1276
+ encrypted_password = hashlib.sha256(student["password"].encode('utf-8')).hexdigest()# Encrypts the password
1277
+ # Then stores data into the studentsubscriptions collection
1278
+ importcsv.db.studentsubscriptions.insert_one({"hostemail":current_user,"email": student["email"],"password": encrypted_password,"emailsleft": 20,"subscription": "student educational"})
1279
+
1280
+ return {"message": "student subscriptions Set."}
1281
+ elif user_from_db["numofaccounts"] <= 0:
1282
+ return {"error": "No more student accounts left."}
1283
+ except Exception as ex:
1284
+ return {"error": f"{type(ex)}-{ex}"}
1285
+ @app.route('/getstudentsubscriptions', methods=['GET'])
1286
+ @cross_origin()
1287
+ @jwt_required()
1288
+ def getstudentsubscriptions():
1289
+ current_user = get_jwt_identity()
1290
+ if current_user:
1291
+ try:
1292
+ student_user_from_db = list(importcsv.db.studentsubscriptions.find({"hostemail": current_user})) # [0]
1293
+ user_from_db = list(importcsv.db.users.find({"email": current_user}))[0]
1294
+ for student in student_user_from_db:
1295
+ del student["_id"], student["password"],student["hostemail"],student['subscription']
1296
+
1297
+ importcsv.db.users.delete_many(user_from_db) # Deletes the data in order to update it.
1298
+ del user_from_db["numofaccounts"] # Deletes the numofaccounts to update it.
1299
+ user_from_db.update({"numofaccounts": 200 - len(student_user_from_db)}) # Updates the number of accounts
1300
+ importcsv.db.users.insert_one(user_from_db) # inserts updated data into the host emails account
1301
+ return jsonify({"result":student_user_from_db})
1302
+ except Exception as ex:
1303
+ return {"error": f"{type(ex)}-{ex}"}
1304
+ @app.route('/checkstudentsubscriptions', methods=['GET'])
1305
+ @cross_origin()
1306
+ @jwt_required()
1307
+ def checkstudentsubscriptions():
1308
+ current_user = get_jwt_identity() # outputs the email of the user [email protected]
1309
+ if current_user:
1310
+ try:
1311
+ student_from_db = list(importcsv.db.studentsubscriptions.find({"email": current_user}))[0] # Gets wanted data for user
1312
+ student_subscription = student_from_db["subscription"]
1313
+ student_subscription_json = {"student_subscription": student_subscription}
1314
+ return jsonify(student_subscription_json)
1315
+ except Exception as ex:
1316
+ return {"error": f"{type(ex)}-{ex}"}
1317
+ @app.route('/deletestudentaccount', methods=['POST'])
1318
+ @cross_origin()
1319
+ @jwt_required()
1320
+ def deletestudentaccount():
1321
+ current_user = get_jwt_identity()
1322
+ if current_user:
1323
+ data = request.get_json()
1324
+ try:
1325
+ hostkey = importcsv.db.studentsubscriptions.find_one({"hostemail": current_user})
1326
+ studentkey = importcsv.db.studentsubscriptions.find_one({"email": data["studentemail"]})
1327
+ if hostkey and studentkey:
1328
+ importcsv.db.studentsubscriptions.delete_one({"email": data["studentemail"]})
1329
+ return jsonify({"message": "Student account deleted."})
1330
+ else:
1331
+ return jsonify({"error": "Student account does not exist."})
1332
+ except Exception as ex:
1333
+ return {"error": f"{type(ex)}-{ex}"}
1334
+ @app.route('/changestudentpassword', methods=['PUT'])
1335
+ @cross_origin()
1336
+ @jwt_required()
1337
+ def changestudentpassword():
1338
+ current_user = get_jwt_identity()
1339
+ if current_user:
1340
+ data = request.get_json()
1341
+ try:
1342
+ hostkey = importcsv.db.studentsubscriptions.find_one({"hostemail": current_user})
1343
+ studentkey = importcsv.db.studentsubscriptions.find_one({"email": data["studentemail"]})
1344
+ if hostkey and studentkey:
1345
+ student_user_from_db = list(importcsv.db.studentsubscriptions.find({"email": data["studentemail"]}))[0]
1346
+ # TODO Delete password from here and replace.
1347
+ importcsv.db.studentsubscriptions.delete_many(student_user_from_db)
1348
+ del student_user_from_db["password"]
1349
+ encrypted_password = hashlib.sha256(data["password"].encode('utf-8')).hexdigest()
1350
+ student_user_from_db.update({"password": encrypted_password})
1351
+ importcsv.db.studentsubscriptions.insert_one(student_user_from_db)
1352
+ return jsonify({"message": "Password reset successful."})
1353
+ else:
1354
+ return jsonify({"error": "Student account does not exist."})
1355
+ except Exception as ex:
1356
+ return {"error": f"{type(ex)}-{ex}"}
1357
+
1358
+
1359
+
1360
+ @app.route('/getfreetrial', methods=['GET'])
1361
+ @cross_origin()
1362
+ @jwt_required()
1363
+ def getfreetrial():
1364
+ current_user = get_jwt_identity() # outputs the email of the user [email protected]
1365
+ if current_user:
1366
+ try:
1367
+ freetrialhistory = list(importcsv.db.freetrialhistory.find({"email": current_user}))[0] # Gets wanted data for user
1368
+ freetrial = freetrialhistory["freetrial"]
1369
+ freetrial_subscription = {"freetrial": freetrial} # check freetrial
1370
+ return jsonify(freetrial_subscription)
1371
+ except Exception as ex:
1372
+ return {"error": f"{type(ex)}-{ex}"}
1373
+ @app.route('/getemail', methods=['GET'])
1374
+ @cross_origin()
1375
+ @jwt_required()
1376
+ def getemail():
1377
+ current_user = get_jwt_identity() # outputs the email of the user [email protected]
1378
+ if current_user:
1379
+ try:
1380
+ user_from_db = check_user_from_db(current_user)
1381
+ return {"email":user_from_db["email"]}
1382
+ except Exception as ex:
1383
+ return {"error": f"{type(ex)}-{ex}"}
1384
+
1385
+ @app.route('/deletesubscription', methods=['DELETE'])
1386
+ @cross_origin()
1387
+ @jwt_required()
1388
+ def deletesubscription():
1389
+ current_user = get_jwt_identity() # outputs the email of the user [email protected]
1390
+ if current_user:
1391
+ try:
1392
+ user_from_db = list(importcsv.db.users.find({"email": current_user}))[0]
1393
+ importcsv.db.users.delete_many(user_from_db)
1394
+ if "end_date_subscription" in user_from_db:
1395
+ del user_from_db["end_date_subscription"]
1396
+ if "start_date_subscription" in user_from_db:
1397
+ del user_from_db["start_date_subscription"]
1398
+ if "subscription" in user_from_db:
1399
+ del user_from_db["subscription"]
1400
+ if "emailsleft" in user_from_db:
1401
+ del user_from_db["emailsleft"]
1402
+ if "numofaccounts" in user_from_db:
1403
+ del user_from_db["numofaccounts"]
1404
+ importcsv.db.users.update_one( { "email": current_user}, {"$set": user_from_db}, upsert = True )
1405
+
1406
+ return jsonify({"message":"Subscription deleted from expiration"})
1407
+ except Exception as ex:
1408
+ return {"error": f"{type(ex)}-{ex}"}
1409
+ @app.route('/getaccountinfo', methods=['GET'])
1410
+ @cross_origin()
1411
+ @jwt_required()
1412
+ def getaccountinfo():
1413
+ current_user = get_jwt_identity() # outputs the email of the user [email protected]
1414
+ if current_user:
1415
+ try:
1416
+ email_exists = importcsv.db.users.find_one({"email": current_user})
1417
+ email_exists_student = importcsv.db.studentsubscriptions.find_one({"email": current_user})
1418
+ if email_exists:
1419
+ user_from_db = list(importcsv.db.users.find({"email": current_user}))[0]
1420
+ del user_from_db["password"], user_from_db["_id"]
1421
+ return jsonify(user_from_db)
1422
+ elif email_exists_student:
1423
+ student_user_from_db = list(importcsv.db.studentsubscriptions.find({"email": current_user}))[0]
1424
+ host_from_db = list(importcsv.db.users.find({"email": student_user_from_db["hostemail"]}))[0]
1425
+ student_user_from_db.update({"start_date_subscription":host_from_db["start_date_subscription"]})
1426
+ student_user_from_db.update({"end_date_subscription":host_from_db["end_date_subscription"]})
1427
+ del student_user_from_db["password"], student_user_from_db["_id"]
1428
+ return jsonify(student_user_from_db)
1429
+ #return {"error": f"account not found"}
1430
+ except Exception as ex:
1431
+ return {"error": f"{type(ex)}-{ex}"}
1432
+ @app.route('/deleteaccount', methods=['DELETE'])
1433
+ @cross_origin()
1434
+ @jwt_required()
1435
+ def deleteaccount():
1436
+ current_user = get_jwt_identity() # outputs the email of the user [email protected]
1437
+ if current_user:
1438
+ try:
1439
+ user_from_db = list(importcsv.db.users.find({"email": current_user}))[0]
1440
+ importcsv.db.users.delete_many(user_from_db)
1441
+ return jsonify({"message":"Account Deleted"})
1442
+ except Exception as ex:
1443
+ return {"error": f"{type(ex)}-{ex}"}
1444
+ @app.route('/getedexcelpapers',methods=['GET'])
1445
+ @cross_origin() # allow all origins all methods.
1446
+ def getedexcelpapers():
1447
+ try:
1448
+ data = request.get_json()
1449
+ dataedexcel = list(importcsv.db.edexcelpapers.find({"year":"AS Level"}))
1450
+ return {"result":dataedexcel}
1451
+ except Exception as ex:
1452
+ return {"error":f"{type(ex)},ex"}
1453
+
1454
+ if __name__ == "__main__":
1455
+ app.run(debug=True,host="0.0.0.0",port=5000)
1456
+ #app.run(debug=True)
1457
+
config.py ADDED
@@ -0,0 +1,15 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ from dotenv import load_dotenv
3
+
4
+ basedir = os.path.abspath(os.path.dirname(__file__))
5
+ load_dotenv(os.path.join(basedir, "secrets"))
6
+ load_dotenv(os.path.join(basedir, "configuration"))
7
+
8
+
9
+ class Config(object):
10
+ MAIL_DEFAULT_SENDER = os.environ.get("MAIL_DEFAULT_SENDER")
11
+ MAIL_PASSWORD = os.environ.get("MAIL_PASSWORD")
12
+ MAIL_PORT = int(os.environ.get("MAIL_PORT") or 25)
13
+ MAIL_SERVER = os.environ.get("MAIL_SERVER")
14
+ MAIL_USE_TLS = os.environ.get("MAIL_USE_TLS") != "False"
15
+ MAIL_USERNAME = os.environ.get("MAIL_USERNAME")
configuration ADDED
@@ -0,0 +1,5 @@
 
 
 
 
 
 
1
2
+ MAIL_PORT=587
3
+ MAIL_SERVER=smtp.sendgrid.net
4
+ MAIL_USE_TLS=True
5
+ MAIL_USERNAME=apikey
csv_to_db.py ADDED
@@ -0,0 +1,27 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import pymongo
2
+ import json
3
+ import certifi
4
+ # Mongo client Debugging:
5
+ # Tsl error :https://stackoverflow.com/questions/54484890/ssl-handshake-issue-with-pymongo-on-python3
6
+ # Ip address whilisting mongo atlas..
7
+ class ImportCSV:
8
+ def __init__(self,database,maindb=0) -> None:
9
+ ca = certifi.where()
10
+ # This tells python to specifically send a tls certificate for the connection.
11
+ if maindb == 0: # User Accounts Database
12
+ client = pymongo.MongoClient(f"mongodb+srv://palondrome:[email protected]/roadmaptestdb?retryWrites=true&w=majority",tlsCAFile=ca)
13
+ self.db = client[database]
14
+ elif maindb == 1:# Question Paper 1 Database
15
+ client = pymongo.MongoClient(f"mongodb+srv://palondrome2:[email protected]/chemistryqp?retryWrites=true&w=majority",tlsCAFile=ca)
16
+ self.db = client[database]
17
+ elif maindb == 2:# Question Paper 1 Database
18
+ client = pymongo.MongoClient(f"mongodb+srv://palondrome3:[email protected]/?retryWrites=true&w=majority",tlsCAFile=ca)
19
+ self.db = client[database]
20
+ def load_data(self,collection_name,init_data):
21
+ # Initialises collection
22
+ db_cm = self.db[collection_name]
23
+ def load_n_insert(data):
24
+ # Input is Dataframe
25
+ data_json = json.loads(data.to_json(orient='records'))
26
+ db_cm.insert_many(data_json)
27
+ load_n_insert(init_data)
forgotpassemail.py ADDED
@@ -0,0 +1,20 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+
2
+ def forgotpasswordemail(email,access_token):
3
+ emailtext = f"""
4
+ <h1 style="color:#264BE4;">RevisionBank</h1>
5
+ <strong>
6
+ Reset Password
7
+ </strong>
8
+ <p >
9
+ Hello {email}
10
+ </p>
11
+ <p>
12
+ A request has been received to change the password for your RevisionBank account.
13
+ </p>
14
+ <a href="https://revisionbank.org/resetpassword?token={access_token}" target="_blank" rel="noopener noreferrer">
15
+ <button style="width:40%;background-color: #264BE4;border: 1px solid #264BE4;border-radius: 10px;">
16
+ <p style="color:white">Reset Password</p>
17
+ </button>
18
+ </a>
19
+ """
20
+ return emailtext
image.png ADDED
main.py ADDED
@@ -0,0 +1,1414 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import base64
2
+ import concurrent
3
+ import os
4
+ from concurrent.futures import thread
5
+ from datetime import datetime
6
+ import datetime as dt
7
+ import requests
8
+ from bs4 import BeautifulSoup
9
+ from flask import Flask, app, jsonify, request
10
+ from flask_cors import CORS, cross_origin
11
+ from flask_mail import Mail, Message
12
+ from physicsaqa import PhysicsAQA
13
+ from config import Config
14
+ from flask_jwt_extended import JWTManager, jwt_required, create_access_token, get_jwt_identity
15
+ from csv_to_db import ImportCSV
16
+ from models import Users
17
+ from bson.objectid import ObjectId #
18
+ import hashlib
19
+ import random
20
+ from datetime import datetime
21
+ from PIL import Image, ImageOps
22
+ from io import BytesIO
23
+ import base64
24
+ import json
25
+ import stripe
26
+ import jwt
27
+ #import cv2
28
+ import re
29
+ import jwt
30
+ from fastapi import FastAPI, Header
31
+ from fastapi.middleware.cors import CORSMiddleware
32
+ from pydantic import BaseModel
33
+ from typing import Optional
34
+ from typing import Generic, TypeVar,Dict,List,AnyStr,Any,Union
35
+ import asyncio
36
+ import uvicorn
37
+ import pytesseract
38
+ from forgotpassemail import forgotpasswordemail
39
+ from RevisionBankModels import *
40
+ from fastapi_utils.tasks import repeat_every
41
+ from revisionbankscheduler import RevisionBankScheduler
42
+ app = FastAPI()
43
+ app.add_middleware(
44
+ CORSMiddleware,
45
+ allow_origins=["*"],
46
+ allow_credentials=True,
47
+ allow_methods=["*"],
48
+ allow_headers=["*"],
49
+ )
50
+ importcsv = ImportCSV("RevisionBankDB",maindb=0)
51
+ importcsvqp = ImportCSV("RevisionBankDB",maindb= 1)
52
+ importcsvqp1 = ImportCSV("RevisionBankQPs1",maindb=2)
53
+ revisionbankschedule = RevisionBankScheduler(importcsv)
54
+ JWT_SECRET = "Peter Piper picked a peck of pickled peppers, A peck of pickled peppers Peter Piper picked, If Peter Piper picked a peck of pickled peppers,Where's the peck of pickled peppers Peter Piper picked" #'super-secret'
55
+ # IRL we should NEVER hardcode the secret: it should be an evironment variable!!!
56
+ JWT_ALGORITHM = "HS256"
57
+
58
+ JSONObject = Dict[Any, Any]
59
+ JSONArray = List[Any]
60
+ JSONStructure = Union[JSONArray, JSONObject]
61
+ time_hour = 60 * 60 # 1 hour,
62
+ def secure_encode(token):
63
+ # if we want to sign/encrypt the JSON object: {"hello": "world"}, we can do it as follows
64
+ # encoded = jwt.encode({"hello": "world"}, JWT_SECRET, algorithm=JWT_ALGORITHM)
65
+ encoded_token = jwt.encode(token, JWT_SECRET, algorithm=JWT_ALGORITHM)
66
+ # this is often used on the client side to encode the user's email address or other properties
67
+ return encoded_token
68
+
69
+ def secure_decode(token):
70
+ # if we want to sign/encrypt the JSON object: {"hello": "world"}, we can do it as follows
71
+ # encoded = jwt.encode({"hello": "world"}, JWT_SECRET, algorithm=JWT_ALGORITHM)
72
+ decoded_token = jwt.decode(token, JWT_SECRET, algorithms=JWT_ALGORITHM)
73
+ # this is often used on the client side to encode the user's email address or other properties
74
+ return decoded_token
75
+ def getendsubscription(current_user):
76
+ user_from_db = list(importcsv.db.users.find({"email": current_user}))[0]
77
+ end_date = user_from_db["end_date_subscription"]
78
+ return end_date
79
+ # Sending Emails from Heroku: https://blairconrad.com/2020/03/05/libraryhippo-2020-sending-email-from-heroku/
80
+ # Send Email API: https://app.sendgrid.com/
81
+ # Signin and Signup page: https://shayff.medium.com/building-your-first-flask-rest-api-with-mongodb-and-jwt-e03f2d317f04
82
+ # SetUp Tesseract: https://towardsdatascience.com/deploy-python-tesseract-ocr-on-heroku-bbcc39391a8d
83
+ def check_user_from_db(current_user): #test
84
+ email_exists = importcsv.db.users.find_one({"email":current_user})
85
+ student_email_exists = importcsv.db.studentsubscriptions.find_one({"email":current_user})
86
+ if email_exists:
87
+ user_from_db = list(importcsv.db.users.find({"email": current_user}))[0] # Gets wanted data for user
88
+ return user_from_db
89
+ elif student_email_exists:
90
+ user_from_db = list(importcsv.db.studentsubscriptions.find({"email": current_user}))[0]
91
+ return user_from_db
92
+
93
+
94
+ @app.get('/')# GET # allow all origins all methods.
95
+ async def index():
96
+ return "Hello World"
97
+
98
+
99
+ @app.on_event("startup")
100
+ @repeat_every(seconds= time_hour * 24) # 24 hours
101
+ async def revisionbankschedulerevisioncardsrepeat() -> None:
102
+ revisionbankschedule.runschedule()
103
+ print("All Cards sent.")
104
+
105
+ @app.post("/revisionbankstripepayment") # POST # allow all origins all methods.
106
+ async def revisionbankstripepayment(data : JSONStructure = None, authorization: str = Header(None)):
107
+ current_user = secure_decode(authorization.replace("Bearer ",""))["email"] # outputs the email of the user [email protected]
108
+ if current_user:
109
+ try:
110
+ data = dict(data)#request.get_json()
111
+ price = data["price"]
112
+ stripe.api_key = "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"
113
+ #"sk_test_51La4WnLpfbhhIhYRjP1w036wUwBoatAgqNRYEoj9u6jMd7GvSmBioKgmwJsabjgAY8V5W8i2r3QdelOPe5VNOueB00zDxeXtDQ"
114
+
115
+ striperesponse = stripe.PaymentIntent.create(
116
+ amount=round(price*100),
117
+ currency="gbp",
118
+ payment_method_types=["card"],
119
+ )
120
+ clientsecret= striperesponse["client_secret"]
121
+ #print(clientsecret)
122
+ return {"clientsecret":clientsecret}
123
+ except Exception as ex:
124
+ return {"error":f"{type(ex)}-{ex}"}
125
+
126
+ @app.post('/revisionbanktranslate') # POST # allow all origins all methods.
127
+ async def revisionbanktranslate(data : JSONStructure = None, authorization: str = Header(None)):
128
+ async def read_img(img):
129
+ pytesseract.pytesseract.tesseract_cmd = "/app/.apt/usr/bin/tesseract"
130
+ text = pytesseract.image_to_string(img,
131
+ lang="eng",
132
+ config='--dpi 300 --psm 6 --oem 2 -c tessedit_char_blacklist=][|~_}{=!#%&«§><:;—?¢°*@,')
133
+
134
+ return(text)
135
+ try:
136
+ # TODO Use Tesseract OCR to get the text from the image hello
137
+ data = dict(data)#request.get_json()
138
+ img = data["revisioncardscreenshot"].replace("data:image/png;base64,","").replace("data:image/jpeg;base64,","")
139
+ # TODO Next Remove Blurriness and Noise from the image with cv2
140
+ #https://pyimagesearch.com/2017/07/10/using-tesseract-ocr-python/
141
+ img_obj =ImageOps.grayscale(Image.open(BytesIO(base64.b64decode(img))))
142
+ text = read_img(img_obj)
143
+
144
+ return {"revisioncardscreenshotext":text }
145
+ #return {"result":data}
146
+ except Exception as e:
147
+ return {f"error":f"{type(e)},{str(e)}"}
148
+
149
+
150
+ @app.post('/getedexcelqp') # POST # allow all origins all methods.
151
+ async def getedexcelqp(data : JSONStructure = None, authorization: str = Header(None)):
152
+ current_user = secure_decode(authorization.replace("Bearer ",""))["email"] # outputs the email of the user [email protected]
153
+ if current_user:
154
+ try:
155
+ data = dict(data)#request.get_json()
156
+ edexcelpapers = list(importcsvqp.db.edexcelpapers.find({data["edexcelpaper"]:{"$exists":"true"}}))[0]
157
+ del edexcelpapers["_id"]
158
+ return {"edexcelpaper":edexcelpapers}
159
+ except Exception as e:
160
+ return {f"error":f"{type(e)},{str(e)}"}
161
+ @app.post('/getcomputerscienceqp') # POST # allow all origins all methods.
162
+ async def getcomputerscienceqp(data : JSONStructure = None, authorization: str = Header(None)):
163
+ current_user = secure_decode(authorization.replace("Bearer ",""))["email"] # outputs the email of the user [email protected]
164
+ if current_user:
165
+ try:
166
+ data = dict(data)#request.get_json()
167
+ edexcelpapers = list(importcsvqp1.db.computerscienceqp.find({data["aqacomputerscience"]:{"$exists":"true"}}))[0]
168
+ del edexcelpapers["_id"]
169
+ return edexcelpapers # {"aqacomputerscience":edexcelpapers}
170
+ except Exception as e:
171
+ return {f"error":f"{type(e)},{str(e)}"}
172
+ @app.post('/getcomputersciencems') # POST # allow all origins all methods.
173
+ async def getcomputersciencems(data : JSONStructure = None, authorization: str = Header(None)):
174
+ current_user = secure_decode(authorization.replace("Bearer ",""))["email"] # outputs the email of the user [email protected]
175
+ if current_user:
176
+ try:
177
+ data = dict(data)#request.get_json()
178
+ edexcelpapers = list(importcsvqp1.db.computersciencems.find({data["aqacomputerscience"]:{"$exists":"true"}}))[0]
179
+ del edexcelpapers["_id"]
180
+ return edexcelpapers # {"aqacomputerscience":edexcelpapers}
181
+ except Exception as e:
182
+ return {f"error":f"{type(e)},{str(e)}"}
183
+ @app.post('/getphysicsocrqp') # POST # allow all origins all methods.
184
+ async def getphysicsocrqp(data : JSONStructure = None, authorization: str = Header(None)):
185
+ current_user = secure_decode(authorization.replace("Bearer ",""))["email"] # outputs the email of the user [email protected]
186
+ if current_user:
187
+ try:
188
+ data = dict(data)#request.get_json()
189
+ if data["subject"] == "physics":
190
+ edexcelpapers = list(importcsvqp1.db.physicsocrqp.find({data["questionpapersubject"]:{"$exists":"true"}}))[0]
191
+ elif data["subject"] == "chemistry":
192
+ edexcelpapers = list(importcsvqp.db.chemistryaqaqp.find({data["questionpapersubject"]:{"$exists":"true"}}))[0]
193
+ elif data["subject"] == "biology":
194
+ edexcelpapers = list(importcsvqp.db.biologyaqaqp.find({data["questionpapersubject"]:{"$exists":"true"}}))[0]
195
+
196
+ del edexcelpapers["_id"]
197
+ #print(edexcelpapers)
198
+ if data["scheme"] == "qp":
199
+ return {"questionpapersubject":edexcelpapers[data["questionpapersubject"]]["questionpaper"]}
200
+ elif data["scheme"] == "ms":
201
+ return {"questionpapersubject":edexcelpapers[data["questionpapersubject"]]["markscheme"]}
202
+ except Exception as e:
203
+ return {f"error":f"{type(e)},{str(e)}"}
204
+
205
+
206
+ @app.post('/storeocrrevisioncards') # POST # allow all origins all methods.
207
+ async def storeocrrevisioncards(data : JSONStructure = None, authorization: str = Header(None)):
208
+ current_user = secure_decode(authorization.replace("Bearer ",""))["email"] # outputs the email of the user [email protected]
209
+ if current_user:
210
+ try:
211
+ data_json = dict(data)#request.get_json()
212
+ print(data_json)
213
+ data = data_json["revisioncardscheduler"]
214
+ email_exists = importcsv.db.accountrevisioncards.find_one({"email":current_user})
215
+ if email_exists: # Checks if email exists
216
+ cards_not_exist = []
217
+ user_revision_cards = list(importcsv.db.accountrevisioncards.find({"email": current_user}))[0] # Gets the email.
218
+
219
+ #print(user_revision_cards)
220
+ for card in data["revisioncards"]: # Checks if the revision card exists in the database.
221
+ if card not in user_revision_cards["revisioncards"]:
222
+ cards_not_exist.append(card) # If not, add it to the list.
223
+ #cards_that_exist.append(card)
224
+ if cards_not_exist != []:
225
+ new_cards = cards_not_exist + user_revision_cards["revisioncards"] # adds new cards to the list.
226
+ user_revision_cards["revisioncards"] = new_cards # Updates the list.
227
+ del user_revision_cards["_id"]
228
+ user_revision_cards["email"] = current_user # Sets the email to the current user.
229
+ importcsv.db.accountrevisioncards.delete_many({"email":current_user}) # Allows data to be updated.
230
+ importcsv.db.accountrevisioncards.insert_one(user_revision_cards) # Inserts the new data.
231
+ return {"message":"revision cards updated"}
232
+ elif cards_not_exist == []: # If the cards are already in the database, return a message.
233
+ return {"message":"No new cards"}
234
+
235
+ elif not email_exists:
236
+ return {"message": "account doesn't exist"}
237
+ except Exception as ex:
238
+ print(type(ex),ex)
239
+ @app.post('/storerevisioncards') # POST # allow all origins all methods.
240
+ async def storerevisioncards(data : JSONStructure = None, authorization: str = Header(None)):
241
+ try:
242
+ current_user = secure_decode(authorization.replace("Bearer ",""))["email"]
243
+ if current_user:
244
+ data_json = dict(data)#request.get_json() # test
245
+ data = data_json["revisioncardscheduler"]
246
+ email_exists = importcsv.db.accountrevisioncards.find_one({"email":current_user})
247
+ if email_exists: # Checks if email exists
248
+ cards_not_exist = []
249
+ user_revision_cards = list(importcsv.db.accountrevisioncards.find({"email": current_user}))[0] # Gets the email.
250
+
251
+ #print(user_revision_cards)
252
+ for card in data["revisioncards"]: # Checks if the revision card exists in the database.
253
+ if card not in user_revision_cards["revisioncards"]:
254
+ cards_not_exist.append(card) # If not, add it to the list.
255
+ #cards_that_exist.append(card)
256
+ if cards_not_exist != []:
257
+ new_cards = cards_not_exist + user_revision_cards["revisioncards"] # adds new cards to the list.
258
+ user_revision_cards["revisioncards"] = new_cards # Updates the list.
259
+ del user_revision_cards["_id"]
260
+ user_revision_cards["email"] = current_user # Sets the email to the current user.
261
+ importcsv.db.accountrevisioncards.delete_many({"email":current_user}) # Allows data to be updated.
262
+ importcsv.db.accountrevisioncards.insert_one(user_revision_cards) # Inserts the new data.
263
+ return {"message":"revision cards updated"}
264
+ elif cards_not_exist == []: # If the cards are already in the database, return a message.
265
+ return {"message":"No new cards"}
266
+
267
+ elif not email_exists:
268
+ data["email"] = current_user
269
+ importcsv.db.accountrevisioncards.insert_one(data)
270
+
271
+ return {"message": "revision card stored"}
272
+ except Exception as ex:
273
+ print(type(ex),ex)
274
+ @app.put('/changesendtoemail')# PUT # allow all origins all methods.
275
+ async def changesendtoemail(data : JSONStructure = None, authorization: str = Header(None)): # TODO
276
+ current_user = secure_decode(authorization.replace("Bearer ",""))["email"]
277
+ if current_user:
278
+ try:
279
+ data = dict(data)#request.get_json()
280
+ email_exists = importcsv.db.accountrevisioncards.find_one({"email":current_user})
281
+ if email_exists:
282
+ scheduled_exists = importcsv.db.scheduledcards.find_one({"email":current_user})
283
+ if scheduled_exists:
284
+ user_scheduled_cards = list(importcsv.db.scheduledcards.find({"email": current_user}))[0]
285
+ importcsv.db.scheduledcards.delete_many(user_scheduled_cards)
286
+ del user_scheduled_cards["sendtoemail"]
287
+ sendtoemailscheduled = user_scheduled_cards["sendtoemail"]
288
+ user_scheduled_cards.update({"sendtoemail": sendtoemailscheduled})
289
+ importcsv.db.scheduledcards.insert_one(user_scheduled_cards)
290
+
291
+
292
+ user_revision_cards = list(importcsv.db.accountrevisioncards.find({"email": current_user}))[0]
293
+ importcsv.db.accountrevisioncards.delete_many(user_revision_cards)
294
+ del user_revision_cards["sendtoemail"]
295
+ sendtoemail = data["sendtoemail"]
296
+ user_revision_cards.update({"sendtoemail": sendtoemail})
297
+ importcsv.db.accountrevisioncards.insert_one(user_revision_cards)
298
+ return {"message": "Send to email changed."}
299
+ elif not email_exists:
300
+ return {"message":"email does not exist"}
301
+ except Exception as ex:
302
+ return {f"error":f"{type(ex)},{str(ex)}"}
303
+ @app.post('/changerevisioncard') # POST # allow all origins all methods.
304
+ async def changerevisioncard(data : JSONStructure = None, authorization: str = Header(None)):
305
+ current_user = secure_decode(authorization.replace("Bearer ",""))["email"]
306
+ if current_user:
307
+ try:
308
+ data = dict(data)#request.get_json()
309
+ email_exists = importcsv.db.accountrevisioncards.find_one({"email":current_user})
310
+ if email_exists: # Checks if email exists
311
+ # TODO Slightly buggy here - removes old schedule from the database.
312
+ user_scheduled_cards = list(importcsv.db.scheduledcards.find({"email": current_user}))[0]
313
+ if user_scheduled_cards:
314
+ for card in user_scheduled_cards["revisioncards"]:
315
+ oldcard = {i:data[i] for i in data if i!='newrevisioncard'}
316
+ if card == oldcard:
317
+ user_scheduled_cards["revisioncards"].remove(card)
318
+ #importcsv.db.scheduledcards.delete_many({"email":current_user})
319
+ #importcsv.db.scheduledcards.insert_one(user_scheduled_cards)
320
+ importcsv.db.scheduledcards.replace_one(
321
+ {"email":current_user},user_scheduled_cards
322
+ )
323
+
324
+
325
+ user_revision_cards = list(importcsv.db.accountrevisioncards.find({"email": current_user}))[0]
326
+ for card in user_revision_cards["revisioncards"]:
327
+ oldcard = {i:data[i] for i in data if i!='newrevisioncard'}
328
+ if card == oldcard:
329
+ user_revision_cards["revisioncards"].remove(card)
330
+ del data["revisioncard"]
331
+ data["revisioncard"] = data["newrevisioncard"]
332
+ del data["newrevisioncard"]
333
+ user_revision_cards["revisioncards"].append(data)
334
+ importcsv.db.accountrevisioncards.replace_one(
335
+ {"email":current_user},user_revision_cards
336
+ )
337
+ #importcsv.db.accountrevisioncards.delete_many({"email":current_user})
338
+ #importcsv.db.accountrevisioncards.insert_one(user_revision_cards)
339
+ return {"message":"revision card changed."}
340
+ except Exception as ex:
341
+ return {f"error":f"{type(ex)},{str(ex)}"}
342
+
343
+
344
+
345
+ @app.get('/getrevisioncards')# GET # allow all origins all methods.
346
+ async def getrevisioncards(authorization: str = Header(None)):
347
+ current_user = secure_decode(authorization.replace("Bearer ",""))["email"]
348
+ if current_user:
349
+ try:
350
+ email_exists = importcsv.db.accountrevisioncards.find_one({"email":current_user})
351
+ if email_exists: # Checks if email exists
352
+ user_revision_cards = list(importcsv.db.accountrevisioncards.find({"email": current_user}))[0]
353
+ del user_revision_cards["_id"],user_revision_cards["email"]
354
+ return user_revision_cards
355
+ elif not email_exists:
356
+ return {"message":"No revision cards"} # Send in shape of data
357
+ except Exception as ex:
358
+ return {f"error":f"{type(ex)},{str(ex)}"}
359
+ @app.post('/uploadrevisioncardtxtfile') # POST # allow all origins all methods.
360
+ async def uploadrevisioncardtxtfile(data : JSONStructure = None, authorization: str = Header(None)):
361
+ try:
362
+ current_user = secure_decode(authorization.replace("Bearer ",""))["email"]
363
+ if current_user:
364
+ file = request.files["file"]
365
+ if file:
366
+ return {"message":file}
367
+ elif not file:
368
+ {"message":"No file"}
369
+ except Exception as ex:
370
+ return {f"error":f"{type(ex)},{str(ex)}"}
371
+
372
+
373
+ @app.post('/removerevisioncard') # POST # allow all origins all methods.
374
+ async def removerevisioncard(data : JSONStructure = None, authorization: str = Header(None)):
375
+ current_user = secure_decode(authorization.replace("Bearer ",""))["email"]
376
+ if current_user:
377
+ try:
378
+ data = dict(data)#request.get_json()
379
+ email_exists = importcsv.db.accountrevisioncards.find_one({"email":current_user})
380
+ if email_exists: # Checks if email exists
381
+ # Remove the revision card from the database.
382
+ user_revision_cards = list(importcsv.db.accountrevisioncards.find({"email": current_user}))[0]
383
+ for card in user_revision_cards["revisioncards"]:
384
+ if card == data:
385
+ user_revision_cards["revisioncards"].remove(card)
386
+ importcsv.db.accountrevisioncards.delete_many({"email":current_user})
387
+ importcsv.db.accountrevisioncards.insert_one(user_revision_cards)
388
+ # Remove the revision card from the scheduled cards
389
+ try:
390
+ user_scheduled_cards = list(importcsv.db.scheduledcards.find({"email": current_user}))[0]
391
+ for card in user_scheduled_cards["revisioncards"]:
392
+ if card == data:
393
+ user_scheduled_cards["revisioncards"].remove(card)
394
+ importcsv.db.scheduledcards.delete_many({"email":current_user})
395
+ importcsv.db.scheduledcards.insert_one(user_scheduled_cards)
396
+ return {"message":"revision card removed"}
397
+ except IndexError as iex:
398
+ return {"message":"revision card removed"}
399
+
400
+ except Exception as ex:
401
+ return {f"error":f"{type(ex)},{str(ex)}"}
402
+ @app.post('/schedulerevisioncard') # POST # allow all origins all methods.
403
+ async def schedulerevisioncard(data : JSONStructure = None, authorization: str = Header(None)):
404
+ try:
405
+ current_user = secure_decode(authorization.replace("Bearer ",""))["email"]
406
+ if current_user:
407
+ data = dict(data)#request.get_json() # test
408
+ email_exists = importcsv.db.scheduledcards.find_one({"email":current_user})
409
+ if email_exists: # Checks if email exists
410
+ cards_not_exist = []
411
+ user_scheduled_cards = list(importcsv.db.scheduledcards.find({"email": current_user}))[0] # Gets the email.
412
+
413
+ #print(user_revision_cards)
414
+ for card in data["revisioncards"]: # Checks if the revision card exists in the database.
415
+ if card not in user_scheduled_cards["revisioncards"]:
416
+ cards_not_exist.append(card) # If not, add it to the list.
417
+ #cards_that_exist.append(card)
418
+ if cards_not_exist != []:
419
+ new_cards = cards_not_exist + user_scheduled_cards["revisioncards"] # adds new cards to the list.
420
+ user_scheduled_cards["revisioncards"] = new_cards # Updates the list.
421
+ del user_scheduled_cards["_id"]
422
+ user_scheduled_cards["email"] = current_user # Sets the email to the current user.
423
+ importcsv.db.scheduledcards.delete_many({"email":current_user}) # Allows data to be updated.
424
+ importcsv.db.scheduledcards.insert_one(user_scheduled_cards) # Inserts the new data.
425
+ return {"message":"revision cards scheduled"}
426
+ elif cards_not_exist == []: # If the cards are already in the database, return a message.
427
+ return {"message":"revision cards already scheduled"}
428
+
429
+ elif not email_exists:
430
+ data["email"] = current_user
431
+ importcsv.db.scheduledcards.insert_one(data)
432
+
433
+ return {"message": "revision card scheduled"}
434
+ except Exception as ex:
435
+ print(type(ex),ex)
436
+ @app.delete('/unscheduleallrevisioncard') # DELETE # allow all origins all methods.
437
+ async def unscheduleallrevisioncard(authorization: str = Header(None)):
438
+ current_user = secure_decode(authorization.replace("Bearer ",""))["email"]
439
+ if current_user:
440
+ try:
441
+ email_exists = importcsv.db.scheduledcards.find_one({"email":current_user})
442
+ if email_exists: # Checks if email exists
443
+ user_revision_cards = list(importcsv.db.scheduledcards.find({"email": current_user}))[0]
444
+ user_revision_cards["revisioncards"] = []
445
+ importcsv.db.scheduledcards.delete_many({"email":current_user})
446
+ importcsv.db.scheduledcards.insert_one(user_revision_cards)
447
+ return {"message":"Allrevision card unscheduled"}
448
+ except Exception as ex:
449
+ return {f"error":f"{type(ex)},{str(ex)}"}
450
+ @app.post('/unschedulerevisioncard') # POST # allow all origins all methods.
451
+ async def unschedulerevisioncard(data : JSONStructure = None, authorization: str = Header(None)):
452
+ current_user = secure_decode(authorization.replace("Bearer ",""))["email"]
453
+ if current_user:
454
+ try:
455
+ data = dict(data)#request.get_json()
456
+ email_exists = importcsv.db.scheduledcards.find_one({"email":current_user})
457
+ if email_exists: # Checks if email exists
458
+
459
+ user_revision_cards = list(importcsv.db.scheduledcards.find({"email": current_user}))[0]
460
+ for card in user_revision_cards["revisioncards"]:
461
+ if card == data:
462
+ user_revision_cards["revisioncards"].remove(card)
463
+ importcsv.db.scheduledcards.delete_many({"email":current_user})
464
+ importcsv.db.scheduledcards.insert_one(user_revision_cards)
465
+ return {"message":"revision card unscheduled"}
466
+ except Exception as ex:
467
+ return {f"error":f"{type(ex)},{str(ex)}"}
468
+ @app.post('/sendnowrevisioncard') # POST # allow all origins all methods.
469
+ async def sendnowrevisioncard(data : JSONStructure = None, authorization: str = Header(None)):
470
+ try:
471
+ current_user = secure_decode(authorization.replace("Bearer ",""))["email"]
472
+ if current_user:
473
+ data = dict(data)#request.get_json()
474
+ now = datetime.now().strftime("%c")
475
+ message = f"""{data['revisioncards'][0]['revisioncardtitle']}{data["revisioncards"][0]["revisioncard"]}"""
476
+ response = requests.post("http://0.0.0.0:7860/raspsendemail",json={"raspsendemail":{"email":data["sendtoemail"],"message":message,"subject":f"{data['revisioncards'][0]['subject']} Send Now"}})
477
+ #print(response.text)
478
+ #msg = Message(f"{data['revisioncards'][0]['subject']} Send Now", recipients=[data["sendtoemail"]]) # "[email protected]"
479
+ #msg.body = f"Mail from RevisionCard Send Now at {now}"
480
+ #if "!DOCTYPE" not in data["revisioncards"][0]["revisioncard"] or "h1" not in data["revisioncards"][0]["revisioncard"]:
481
+ # msg.html = f"""<pre>{data['revisioncards'][0]['revisioncardtitle']}
482
+ # {data["revisioncards"][0]["revisioncard"]}</pre>"""
483
+ #elif "!DOCTYPE" in data["revisioncards"][0]["revisioncard"] or "h1" in data["revisioncards"][0]["revisioncard"]:
484
+ # msg.html = f"""
485
+ # {data['revisioncards'][0]['revisioncardtitle']}
486
+ # {data["revisioncards"][0]["revisioncard"]}
487
+ # """
488
+ #print(msg)
489
+ #mail.send(msg)
490
+ return {"message":"revision card sent"}
491
+ except Exception as ex:
492
+ return {f"error":f"{type(ex)},{str(ex)}"}
493
+ @app.get('/checkschedulerevisioncard')# GET # allow all origins all methods.
494
+ async def checkschedulerevisioncard(authorization: str = Header(None)):
495
+ current_user = secure_decode(authorization.replace("Bearer ",""))["email"]
496
+ if current_user:
497
+ try:
498
+ email_exists = importcsv.db.scheduledcards.find_one({"email":current_user})
499
+ if email_exists: # Checks if email exists
500
+ user_scheduled_cards = list(importcsv.db.scheduledcards.find({"email": current_user}))[0]
501
+ del user_scheduled_cards["_id"],user_scheduled_cards["email"],user_scheduled_cards["revisionscheduleinterval"],user_scheduled_cards["sendtoemail"]
502
+ return user_scheduled_cards
503
+ elif not email_exists:
504
+ return {"message":"revision cards not scheduled"} # Send in shape of data
505
+ except Exception as ex:
506
+ return {f"error":f"{type(ex)},{str(ex)}"}
507
+
508
+ @app.post('/fmathsqp') # POST # allow all origins all methods.
509
+ async def fmathsqp(data : JSONStructure = None, authorization: str = Header(None)):
510
+ current_user = secure_decode(authorization.replace("Bearer ",""))["email"] # outputs the email of the user [email protected]
511
+ if current_user:
512
+ datajson = dict(data)#request.get_json()
513
+ try:
514
+ main_qp_url = "https://www.physicsandmathstutor.com/a-level-maths-papers/"
515
+ data = datajson["furthermaths"]
516
+ email = data["email"]
517
+ book_inp = data["furthermathsbook"]
518
+ topic_inp = data["furthermathstopic"]
519
+ platform = data["platform"]
520
+ qp_sections = {"Core":["c1",'c2','c3','c4'],"Mechanics":['m1','m2','m3','m4','m5'],"Statistics":['s1','s2','s3','s4'],'Further Pure':['fp1','fp2','fp3'],'Decision Maths':['d1','d2']}
521
+ if "c".lower() in book_inp.lower():
522
+ book_choice = "c"
523
+ elif "m".lower() in book_inp.lower():
524
+ book_choice = "m"
525
+ elif "s".lower() in book_inp.lower():
526
+ book_choice = "s"
527
+ elif "fp".lower() in book_inp.lower():
528
+ book_choice = "fp"
529
+ elif "d".lower() in book_inp.lower():
530
+ book_choice = "d"
531
+ elif "a".lower() in book_inp.lower():
532
+ book_choice = "a"
533
+ else:
534
+ return {"result": "doesn't exist"}
535
+ if book_choice != "a":
536
+ endpoints = [endpoint for val in qp_sections.values() for endpoint in val if book_choice in endpoint]
537
+ elif book_choice == "a":
538
+ endpoints = [endpoint for val in qp_sections.values() for endpoint in val]
539
+
540
+
541
+ pdf_result = []
542
+ pdf_titles = []
543
+ def qp_extraction(qp_url,end):
544
+ headers = {"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:66.0) Gecko/20100101 Firefox/66.0","Accept-Encoding": "gzip, async deflate", "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8","DNT": "1", "Connection": "close", "Upgrade-Insecure-Requests": "1"}
545
+ response_topic = requests.get(f"{qp_url}/{end}-by-topic/",headers=headers).text
546
+ #if "This site is currently under going scheduled maintenance." in response_topic:
547
+ # return {"error":"Physics maths tutor is in maintenance mode."}
548
+ soup = BeautifulSoup(response_topic,features='lxml')
549
+ for child in soup.find_all(['a'],href=True):
550
+ if topic_inp.lower() in str(child.text).lower():
551
+ pdf_url = child['href']
552
+ #print(pdf_url)
553
+ #print(f'{str(child.text).capitalize()}.pdf')
554
+ pdf_titles.append(f'{str(child.text).capitalize()}.pdf')
555
+ pdf_result.append(pdf_url)
556
+ #response = requests.get(pdf_url)
557
+ #pdf_result.append(str(response.content).replace("b'","").replace("'",""))
558
+
559
+
560
+
561
+
562
+ #print(endpoints)
563
+ def topic_extraction(end):
564
+ qp_extraction(main_qp_url,end)
565
+
566
+ def threads_url(data : JSONStructure = None, authorization: str = Header(None)):
567
+ #threads = 60 # 20 # TODO Number of threads may be blowing up the router.
568
+ threads = 4
569
+ with concurrent.futures.ThreadPoolExecutor(max_workers=threads) as executor: #max_workers=threads
570
+ executor.map(topic_extraction,endpoints)
571
+ threads_url()
572
+ message = """
573
+ The Further Maths question papers, email has been sent to you:
574
+ """
575
+ linkmessage = """
576
+ The Further Maths question papers links:
577
+ """
578
+
579
+ #random.shuffle(pdf_result)
580
+ #random.shuffle(pdf_titles)
581
+ if pdf_result != []:
582
+ if len(pdf_result) > 5:
583
+ pdf_slice = round(len(pdf_result) * (100/100))
584
+ else:
585
+ pdf_slice = round(len(pdf_result) * (100/100))
586
+ for link,title in zip(pdf_result[:pdf_slice],pdf_titles[:pdf_slice]):
587
+ linkmessage += "<br>"
588
+ linkmessage += f"{title}" + "<br>"
589
+ linkmessage += link.replace(" ",'%20') + "<br>"
590
+ for i in pdf_titles:
591
+ message += "\n"
592
+ message += i + "\n"
593
+
594
+
595
+
596
+ user_from_db = check_user_from_db(current_user)
597
+ student_email_exists = importcsv.db.studentsubscriptions.find_one({"email":current_user})
598
+ if "end_date_subscription" in user_from_db:
599
+ end_date = getendsubscription(current_user)
600
+ if user_from_db["emailsleft"] <= 0:
601
+ if platform == "app":
602
+ pdf_response = {"furthermathsresult":{"furthermathsmessage":message}} # "furthermathslinks":pdf_result,"furthermathstitles":pdf_titles,"furthermathslinkmessage":linkmessage
603
+ elif platform == "web":
604
+ pdf_response = {"furthermathsresult":{"furthermathsmessage":linkmessage,"emailcount":0,"end_date_subscription":end_date}}# "furthermathslinks":pdf_result,"furthermathstitles":pdf_titles,"furthermathslinkmessage":linkmessage
605
+ return pdf_response
606
+
607
+ elif user_from_db["emailsleft"] > 0:
608
+ now = datetime.now().strftime("%c")
609
+ message = f"""
610
+ <h1>The Further Maths question papers links:</h1>
611
+ <p>{linkmessage}</p>.
612
+ """
613
+ response = requests.post("http://0.0.0.0:7860/raspsendemail",json={"raspsendemail":{"email":email,"message":message,"subject":"FMathqp PDFs"}})
614
+
615
+ #msg = Message("FMathqp PDFs", recipients=[email]) # "[email protected]"
616
+ #msg.body = f"Mail from FMathqp at {now}"
617
+ #msg.html = f"""
618
+ #<h1>The Further Maths question papers links:</h1>
619
+ #<p>{linkmessage}</p>.
620
+ #"""
621
+
622
+ #mail.send(msg)
623
+ user_from_db.update({"emailsleft":int(user_from_db["emailsleft"])-1})
624
+ importcsv.db.users.update_one({"email": current_user}, {"$set": user_from_db},upsert=True)
625
+ if platform == "app":
626
+ pdf_response = {"furthermathsresult":{"furthermathsmessage":message}} # "furthermathslinks":pdf_result,"furthermathstitles":pdf_titles,"furthermathslinkmessage":linkmessage
627
+ elif platform == "web":
628
+ pdf_response = {"furthermathsresult":{"furthermathsmessage":linkmessage,"emailcount":int(user_from_db["emailsleft"])-1,"end_date_subscription":end_date}}
629
+
630
+ return pdf_response
631
+ elif "end_date_subscription" not in user_from_db and not student_email_exists:
632
+ if platform == "app":
633
+ pdf_response = {"furthermathsresult":{"furthermathsmessage":message}} # "furthermathslinks":pdf_result,"furthermathstitles":pdf_titles,"furthermathslinkmessage":linkmessage
634
+ elif platform == "web":
635
+ pdf_response = {"furthermathsresult":{"furthermathsmessage":linkmessage,"emailcount":0,"end_date_subscription":99999999}}# "furthermathslinks":pdf_result,"furthermathstitles":pdf_titles,"furthermathslinkmessage":linkmessage
636
+ return pdf_response
637
+ elif "end_date_subscription" not in user_from_db and student_email_exists:
638
+ if user_from_db["emailsleft"] <= 0:
639
+ if platform == "app":
640
+ pdf_response = {"furthermathsresult":{"furthermathsmessage":message}} # "furthermathslinks":pdf_result,"furthermathstitles":pdf_titles,"furthermathslinkmessage":linkmessage
641
+ elif platform == "web":
642
+ pdf_response = {"furthermathsresult":{"furthermathsmessage":linkmessage,"emailcount":0,"end_date_subscription":end_date}}# "furthermathslinks":pdf_result,"furthermathstitles":pdf_titles,"furthermathslinkmessage":linkmessage
643
+ return pdf_response
644
+
645
+ elif user_from_db["emailsleft"] > 0:
646
+ now = datetime.now().strftime("%c")
647
+ message = f"""
648
+ <h1>The Further Maths question papers links:</h1>
649
+ <p>{linkmessage}</p>.
650
+ """
651
+ response = requests.post("http://0.0.0.0:7860/raspsendemail",json={"raspsendemail":{"email":email,"message":message,"subject":"FMathqp PDFs"}})
652
+
653
+ user_from_db.update({"emailsleft":int(user_from_db["emailsleft"])-1})
654
+ importcsv.db.studentsubscriptions.update_one({"email": current_user}, {"$set": user_from_db},upsert=True)
655
+ if platform == "app":
656
+ pdf_response = {"furthermathsresult":{"furthermathsmessage":message}} # "furthermathslinks":pdf_result,"furthermathstitles":pdf_titles,"furthermathslinkmessage":linkmessage
657
+ elif platform == "web":
658
+ pdf_response = {"furthermathsresult":{"furthermathsmessage":linkmessage,"emailcount":int(user_from_db["emailsleft"])-1,"end_date_subscription":99999999}}# "furthermathslinks":pdf_result,"furthermathstitles":pdf_titles,"furthermathslinkmessage":linkmessage
659
+ return pdf_response
660
+ elif pdf_result == []:
661
+ return {"error":"No further maths question papers available"}
662
+ except Exception as e:
663
+ return {f"error":f"{type(e)},{str(e)}"}
664
+ else:
665
+ return {"message": "Login first please."}
666
+
667
+
668
+ @app.post('/fmathsb') # POST # allow all origins all methods.
669
+ async def fmathsb(data : JSONStructure = None, authorization: str = Header(None)):
670
+ #pure maths: 0, statistics mechanics: 1, core pure maths: 2, further pure maths: 3, further statistics: 4, further mechanics: 5, decision maths: 6"
671
+ # year/book: 1, year/book: 2
672
+ # {"furthermathsb":{"email":"[email protected]","furthermathsbbook": 0,"furthermathsbyear":2}}
673
+ # Output PureMaths Book 2
674
+ current_user = secure_decode(authorization.replace("Bearer ",""))["email"] # outputs the email of the user [email protected]
675
+ if current_user:
676
+ try:
677
+ sb_books_list = {"0":"pure-maths","1":"statistics-mechanics","2":"core-pure-maths","3":"further-pure-maths","4":"further-statistics","5":"further-mechanics","6":"decision-maths"}
678
+ datajson = dict(data)#request.get_json()
679
+ data = datajson["furthermathsb"]
680
+ email = data["email"]
681
+ sb_book_inp = str(data["furthermathsbbook"])
682
+ sb_year_inp = str(data["furthermathsbyear"])
683
+ sb_exercise = str(data["furthermathsbexercise"])
684
+ platform = data["platform"]
685
+
686
+ sb_book = sb_books_list[str(sb_book_inp)]
687
+ sb_year = str(sb_year_inp)
688
+
689
+ if sb_book == "pure-maths" or sb_book == "statistics-mechanics":
690
+ sb_url = f"https://www.physicsandmathstutor.com/maths-revision/solutionbanks/edexcel-{sb_book}-year-{sb_year}/"
691
+ #print(sb_url)
692
+ else:
693
+ sb_url = f"https://www.physicsandmathstutor.com/maths-revision/solutionbanks/edexcel-{sb_book}-{sb_year}/"
694
+
695
+ book_dir_name = f"{sb_book}{str(sb_year)}".capitalize()
696
+
697
+ response = requests.get(sb_url).text
698
+ soup = BeautifulSoup(response,features='lxml')
699
+ soup_a_tags = soup.find_all(['a'],href=True)
700
+ sb_result = []
701
+ sb_titles = []
702
+ async def sb_extraction(child):
703
+ if "Exercise" in child.text and sb_exercise.upper() in child.text:
704
+ print(child.text)
705
+ pdf_url = child['href']
706
+ #response = requests.get(pdf_url)
707
+ sb_titles.append(f'{book_dir_name}-{str(child.text).capitalize()}.pdf')
708
+ sb_result.append(pdf_url)
709
+ async def threads_url(data : JSONStructure = None, authorization: str = Header(None)):
710
+ #threads = 60 # 20 # TODO Number of threads may be blowing up the router.
711
+ threads = 4
712
+ with concurrent.futures.ThreadPoolExecutor(max_workers=threads) as executor: #max_workers=threads
713
+ executor.map(sb_extraction,soup_a_tags)
714
+ threads_url()
715
+ if sb_result != []:
716
+ message = """
717
+ The Further Maths solution bank, email has been sent to you:
718
+ """
719
+ linkmessage = """
720
+ The Further Maths question papers links:
721
+ """
722
+ for link,title in zip(sb_result,sb_titles):
723
+ linkmessage += "<br>"
724
+ linkmessage += f"{title}" + "<br>"
725
+ linkmessage += link.replace(" ",'%20') + "<br>"
726
+ for i in sb_titles:
727
+ message += "\n"
728
+ message += i + "\n"
729
+ user_from_db = check_user_from_db(current_user)
730
+ student_email_exists = importcsv.db.studentsubscriptions.find_one({"email":current_user})
731
+ if "end_date_subscription" in user_from_db:
732
+ end_date = getendsubscription(current_user)
733
+ if user_from_db["emailsleft"] <= 0:
734
+ if platform == "app":
735
+ pdf_response = {"furthermathsresult":{"furthermathsmessage":message}} # "furthermathslinks":pdf_result,"furthermathstitles":pdf_titles,"furthermathslinkmessage":linkmessage
736
+ elif platform == "web":
737
+ pdf_response = {"furthermathsresult":{"furthermathsmessage":linkmessage,"emailcount":0,"end_date_subscription":end_date}}# "furthermathslinks":pdf_result,"furthermathstitles":pdf_titles,"furthermathslinkmessage":linkmessage
738
+ return pdf_response
739
+
740
+ elif user_from_db["emailsleft"] > 0:
741
+ now = datetime.now().strftime("%c")
742
+ message = f"""
743
+ <h1>The Further Maths Solution Bank links:</h1>
744
+ <p>{linkmessage}</p>.
745
+ """
746
+ response = requests.post("http://0.0.0.0:7860/raspsendemail",json={"raspsendemail":{"email":email,"message":message,"subject":"FMathSB PDFs"}})
747
+
748
+ #msg = Message("FMathSB PDFs", recipients=[email]) # "[email protected]"
749
+ #msg.body = f"Mail from FMathsb at {now}"
750
+ #msg.html = f"""
751
+ #<h1>The Further Maths Solution Bank links:</h1>
752
+ #<p>{linkmessage}</p>.
753
+ #"""
754
+
755
+ #mail.send(msg)
756
+ emailcount = int(user_from_db["emailsleft"])-1
757
+ user_from_db.update({"emailsleft":emailcount})
758
+ importcsv.db.users.update_one({"email": current_user}, {"$set": user_from_db},upsert=True)
759
+
760
+ if platform == "app":
761
+ pdf_response = {"furthermathsresult":{"furthermathsmessage":message}} # "furthermathslinks":pdf_result,"furthermathstitles":pdf_titles,"furthermathslinkmessage":linkmessage
762
+ elif platform == "web":
763
+ pdf_response = {"furthermathsresult":{"furthermathsmessage":linkmessage,"emailcount":emailcount,"end_date_subscription":end_date}}# "furthermathslinks":pdf_result,"furthermathstitles":pdf_titles,"furthermathslinkmessage":linkmessage
764
+ return pdf_response
765
+ elif "end_date_subscription" not in user_from_db and not student_email_exists:
766
+ if platform == "app":
767
+ pdf_response = {"furthermathsresult":{"furthermathsmessage":message}} # "furthermathslinks":pdf_result,"furthermathstitles":pdf_titles,"furthermathslinkmessage":linkmessage
768
+ elif platform == "web":
769
+ pdf_response = {"furthermathsresult":{"furthermathsmessage":linkmessage,"emailcount":0,"end_date_subscription":9999999}}# "furthermathslinks":pdf_result,"furthermathstitles":pdf_titles,"furthermathslinkmessage":linkmessage
770
+ return pdf_response
771
+ elif "end_date_subscription" not in user_from_db and student_email_exists:
772
+ if user_from_db["emailsleft"] <= 0:
773
+ if platform == "app":
774
+ pdf_response = {"furthermathsresult":{"furthermathsmessage":message}} # "furthermathslinks":pdf_result,"furthermathstitles":pdf_titles,"furthermathslinkmessage":linkmessage
775
+ elif platform == "web":
776
+ pdf_response = {"furthermathsresult":{"furthermathsmessage":linkmessage,"emailcount":0,"end_date_subscription":end_date}}# "furthermathslinks":pdf_result,"furthermathstitles":pdf_titles,"furthermathslinkmessage":linkmessage
777
+ return pdf_response
778
+
779
+ elif user_from_db["emailsleft"] > 0:
780
+ now = datetime.now().strftime("%c")
781
+ message = f"""
782
+ <h1>The Further Maths Solution Bank links:</h1>
783
+ <p>{linkmessage}</p>.
784
+ """
785
+ response = requests.post("http://0.0.0.0:7860/raspsendemail",json={"raspsendemail":{"email":email,"message":message,"subject":"FMathSB PDFs"}})
786
+
787
+ user_from_db.update({"emailsleft":int(user_from_db["emailsleft"])-1})
788
+ importcsv.db.studentsubscriptions.update_one({"email": current_user}, {"$set": user_from_db},upsert=True)
789
+ if platform == "app":
790
+ pdf_response = {"furthermathsresult":{"furthermathsmessage":message}} # "furthermathslinks":pdf_result,"furthermathstitles":pdf_titles,"furthermathslinkmessage":linkmessage
791
+ elif platform == "web":
792
+ pdf_response = {"furthermathsresult":{"furthermathsmessage":linkmessage,"emailcount":int(user_from_db["emailsleft"])-1,"end_date_subscription":9999999}}# "furthermathslinks":pdf_result,"furthermathstitles":pdf_titles,"furthermathslinkmessage":linkmessage
793
+ return pdf_response
794
+
795
+ elif sb_result == []:
796
+ return {f"error":f"No further maths solution bank for {sb_book} {sb_year}"}
797
+ except Exception as e:
798
+ return {f"error":f"{type(e)},{str(e)}"}
799
+ else:
800
+ return {"message": "Login first please."}
801
+ @app.post('/ocrsciencebookanswers') # POST # allow all origins all methods.
802
+ async def scienceocranswers(data : JSONStructure = None, authorization: str = Header(None)):
803
+ current_user = secure_decode(authorization.replace("Bearer ",""))["email"] # outputs the email of the user [email protected]
804
+ if current_user:
805
+ datajson = dict(data)#request.get_json()
806
+
807
+ async def ocrscienceanswers(querydata):
808
+ examboards = "OCR"
809
+ url = "https://global.oup.com/education/content/secondary/series/ocr-a-level-sciences/a-level-sciences-for-ocr-student-book-answers/?region=uk"
810
+ physicsanswerspdf = {}
811
+
812
+ response= requests.get(url).text
813
+ soup = BeautifulSoup(response,features='lxml')
814
+ for divele in soup.find_all('div',{'class':'content_block half_width enclosed'}): # inner_block text_only_single ##
815
+ if querydata in divele.text:
816
+ for a in divele.find_all("a",href=True):
817
+ if a["href"] != "?region=uk":
818
+ physicsanswerspdf.update({a.text.replace("\xa0",' '): a["href"].replace("?region=uk",'')})
819
+
820
+ result = {querydata:{examboards:physicsanswerspdf}}
821
+ return result
822
+ try:
823
+ data = datajson["physicsocr"]
824
+ email = data["email"]
825
+ subject = data["subject"] # physics, chemistry, biology
826
+ physicsocralph = data["physicsocralph"] # A or B
827
+ chapter = data["chapter"] # Chapter 1
828
+ year = data["year"] # AS/Year 1, A Level
829
+ platform = data["platform"] # web or app
830
+
831
+ query = f"{subject.capitalize()} {physicsocralph} {year}"
832
+ papers = ocrscienceanswers(query)
833
+ answerlink = papers[query]["OCR"][f"{chapter.capitalize()} (PDF)"].replace(" ",'%20')
834
+
835
+ user_from_db = check_user_from_db(current_user)
836
+ student_email_exists = importcsv.db.studentsubscriptions.find_one({"email":current_user})
837
+ if "end_date_subscription" in user_from_db:
838
+ end_date = getendsubscription(current_user)
839
+ if user_from_db["emailsleft"] <= 0:
840
+ result = {"scienceocranswers": answerlink,"emailcount":0,"end_date_subscription":end_date}
841
+ return result
842
+ elif user_from_db["emailsleft"] > 0:
843
+ now = datetime.now().strftime("%c")
844
+ message = f"""
845
+ <h1>OCR Science {query} Answers:</h1>
846
+ <p>{answerlink}</p>.
847
+ """
848
+ response = requests.post("http://0.0.0.0:7860/raspsendemail",json={"raspsendemail":{"email":email,"message":message,"subject":f"OCR {query} Answers"}})
849
+
850
+ #msg = Message(f"OCR {query} Answers", recipients=[email]) # "[email protected]"
851
+ #msg.body = f"Mail from {query} at {now}"
852
+ #msg.html = f"""
853
+ #<h1>OCR Science {query} Answers:</h1>
854
+ #<p>{answerlink}</p>.
855
+ #"""
856
+
857
+ #mail.send(msg)
858
+ emailcount = int(user_from_db["emailsleft"])-1
859
+ user_from_db.update({"emailsleft":emailcount})
860
+ importcsv.db.users.update_one({"email": current_user}, {"$set": user_from_db},upsert=True)
861
+ result = {"scienceocranswers": answerlink,"emailcount":emailcount,"end_date_subscription":end_date}
862
+ return result
863
+ elif "end_date_subscription" not in user_from_db and not student_email_exists:
864
+ result = {"scienceocranswers": answerlink,"emailcount":0,"end_date_subscription":9999999}
865
+ return result
866
+ elif "end_date_subscription" not in user_from_db and student_email_exists:
867
+ if user_from_db["emailsleft"] <= 0:
868
+ result = {"scienceocranswers": answerlink,"emailcount":0,"end_date_subscription":end_date}
869
+ return result
870
+ elif user_from_db["emailsleft"] > 0:
871
+ now = datetime.now().strftime("%c")
872
+ message = f"""
873
+ <h1>OCR Science {query} Answers:</h1>
874
+ <p>{answerlink}</p>.
875
+ """
876
+ response = requests.post("http://0.0.0.0:7860/raspsendemail",json={"raspsendemail":{"email":email,"message":message,"subject":f"OCR {query} Answers"}})
877
+ user_from_db.update({"emailsleft":int(user_from_db["emailsleft"])-1})
878
+ importcsv.db.studentsubscriptions.update_one({"email": current_user}, {"$set": user_from_db},upsert=True)
879
+ result = {"scienceocranswers": answerlink,"emailcount":int(user_from_db["emailsleft"])-1,"end_date_subscription":9999999}
880
+ return result
881
+ except Exception as e:
882
+ return {f"error":f"{type(e)},{str(e)}"}
883
+ else:
884
+ return {"message": "Login first please."}
885
+ @app.post('/physicsaqa') # POST # allow all origins all methods.
886
+ async def physicsaqa(data : JSONStructure = None, authorization: str = Header(None)):
887
+ current_user = secure_decode(authorization.replace("Bearer ",""))["email"] # outputs the email of the user [email protected]
888
+ if current_user:
889
+ try:
890
+ datajson = dict(data)#request.get_json()
891
+ topicquestions = PhysicsAQA().collectdata()
892
+ data = datajson["physicsaqa"]
893
+ email = data["email"]
894
+ chapter = data["chapter"] # Section 1: Measurement & Their Errors
895
+ topic = data["topic"] # Constituents of the Atom or The Law of the Atom
896
+ platform = data["platform"] # web or app
897
+ try:
898
+ questionpaper = topicquestions[chapter][topic]
899
+ except Exception as ex:
900
+ return {"error":"chapter or topic not found"}
901
+ try:
902
+ markscheme = topicquestions[chapter][f"{topic} MS"]
903
+ except Exception as ex:
904
+ return {"error":"chapter or topic mark scheme not found"}
905
+
906
+
907
+ user_from_db = check_user_from_db(current_user)
908
+ student_email_exists = importcsv.db.studentsubscriptions.find_one({"email":current_user})
909
+ if "end_date_subscription" in user_from_db:
910
+ end_date = getendsubscription(current_user)
911
+ if user_from_db["emailsleft"] <= 0:
912
+ return {"physicsaqa":{"chapter":chapter,"topic":topic,"question paper":questionpaper,"markscheme":markscheme,"emailcount":emailcount,"end_date_subscription":end_date}}
913
+ elif user_from_db["emailsleft"] > 0:
914
+ now = datetime.now().strftime("%c")
915
+ message = f"""
916
+ <h1>PhysicsAqa Question Papers:</h1>
917
+ <p>{questionpaper}</p>
918
+ <p>{markscheme}</p>.
919
+ """
920
+ response = requests.post("http://0.0.0.0:7860/raspsendemail",json={"raspsendemail":{"email":email,"message":message,"subject":f"PhysicsAqa Papers"}})
921
+ #msg = Message(f"PhysicsAqa Papers", recipients=[email]) # "[email protected]"
922
+ #msg.body = f"Mail from physicsaqaApi at {now}"
923
+ #msg.html = f"""
924
+ #<h1>PhysicsAqa Question Papers:</h1>
925
+ #<p>{questionpaper}</p>
926
+ #<p>{markscheme}</p>.
927
+ #"""
928
+ #mail.send(msg)
929
+ emailcount = int(user_from_db["emailsleft"])-1
930
+ user_from_db.update({"emailsleft":emailcount})
931
+ importcsv.db.users.update_one({"email": current_user}, {"$set": user_from_db},upsert=True)
932
+ return {"physicsaqa":{"chapter":chapter,"topic":topic,"question paper":questionpaper,"markscheme":markscheme,"emailcount":emailcount,"end_date_subscription":end_date}}
933
+ elif "end_date_subscription" not in user_from_db and not student_email_exists:
934
+ return {"physicsaqa":{"chapter":chapter,"topic":topic,"question paper":questionpaper,"markscheme":markscheme,"emailcount":0,"end_date_subscription":9999999}}
935
+ # If it is a student account
936
+ elif "end_date_subscription" not in user_from_db and student_email_exists:
937
+ # Check number of emails left
938
+ if user_from_db["emailsleft"] <= 0:
939
+ return {"physicsaqa":{"chapter":chapter,"topic":topic,"question paper":questionpaper,"markscheme":markscheme,"emailcount":emailcount,"end_date_subscription":end_date}}
940
+ elif user_from_db["emailsleft"] > 0:
941
+ now = datetime.now().strftime("%c")
942
+ message = f"""
943
+ <h1>PhysicsAqa Question Papers:</h1>
944
+ <p>{questionpaper}</p>
945
+ <p>{markscheme}</p>.
946
+ """
947
+ response = requests.post("http://0.0.0.0:7860/raspsendemail",json={"raspsendemail":{"email":email,"message":message,"subject":f"PhysicsAqa Papers"}})
948
+
949
+ user_from_db.update({"emailsleft":int(user_from_db["emailsleft"])-1})
950
+ importcsv.db.studentsubscriptions.update_one({"email": current_user}, {"$set": user_from_db},upsert=True)
951
+ return {"physicsaqa":{"chapter":chapter,"topic":topic,"question paper":questionpaper,"markscheme":markscheme,"emailcount":int(user_from_db["emailsleft"])-1,"end_date_subscription":9999999}}
952
+
953
+ except TypeError as tex:
954
+ return {f"error":f"request is wrong shape {tex}"}
955
+ except Exception as ex:
956
+ return {f"error":f"{type(ex)} {str(ex)}"}
957
+ else:
958
+ return {"message": "Login first please."}
959
+
960
+
961
+ @app.post('/signupapi') # POST
962
+ async def signup(data: RevisionBankAuth):
963
+ try:
964
+ data = dict(data)
965
+ print(data)
966
+ data["id"] = ObjectId()
967
+ data["access"] = True
968
+ user = Users(**data)
969
+ signupdata = user.to_bson()
970
+
971
+ print(signupdata["email"])
972
+ email_exists = importcsv.db.users.find_one({"email": signupdata["email"]})
973
+ email_exists_student = importcsv.db.studentsubscriptions.find_one({"email": signupdata["email"]}) # Checks if student account exists
974
+ if email_exists or email_exists_student:
975
+ return {"message": "Email already exists"} # , 400
976
+ elif not email_exists:
977
+ # Notifies who are the beta testers
978
+ #if datetime.now() < "2022-05-19T21:37:00.057084":
979
+ # signupdata.update({"betatest":"true"})
980
+ importcsv.db.users.insert_one(signupdata)
981
+ access_token = secure_encode({{"email":signupdata["email"]}})#create_access_token(identity=signupdata["email"])
982
+ callback = {"status": "success","id": str(signupdata["_id"]),"access_token":access_token}
983
+ return callback
984
+ except Exception as ex:
985
+ error_detected = {"error": "error occured","errortype":type(ex), "error": str(ex)}
986
+ return error_detected
987
+ @app.post('/loginapi') # POST
988
+ async def login(login_details: RevisionBankAuth): # ,authorization: str = Header(None)
989
+ # Login API
990
+ try:
991
+ def provide_access_token(login_details,student=0):
992
+ if student == 0:
993
+ email_exists = list(importcsv.db.users.find({"email": login_details["email"]}))[0]
994
+ elif student == 1:
995
+ email_exists = list(importcsv.db.studentsubscriptions.find({"email": login_details["email"]}))[0]
996
+ encrypted_password = hashlib.sha256(login_details["password"].encode('utf-8')).hexdigest()
997
+ if email_exists["password"] == encrypted_password:
998
+ access_token = secure_encode({"email":email_exists["email"]}) #create_access_token(identity=email_exists["email"])
999
+ return access_token
1000
+ else:
1001
+ return "Wrong password"
1002
+
1003
+
1004
+ login_details = dict(login_details)
1005
+ #print(login_details)
1006
+ email_exists = importcsv.db.users.find_one({"email": login_details["email"]})
1007
+ email_exists_student = importcsv.db.studentsubscriptions.find_one({"email": login_details["email"]}) # Checks if student account exists
1008
+ if email_exists:
1009
+ access_token = provide_access_token(login_details,student=0)
1010
+ if access_token == "Wrong password":
1011
+ return {"message": "The username or password is incorrect."}
1012
+ else:
1013
+ return {"access_token": access_token}
1014
+ elif email_exists_student:
1015
+ access_token = provide_access_token(login_details,student=1)
1016
+ if access_token == "Wrong password":
1017
+ return {"message": "The username or password is incorrect."}
1018
+ else:
1019
+ return {"access_token": access_token}
1020
+ return {"message": "The username or password is incorrect."}
1021
+ except Exception as ex:
1022
+ return {"error": f"{type(ex)} {str(ex)}"}
1023
+ #
1024
+ @app.post('/forgotpassword') # POST
1025
+ async def forgotpassword(data : JSONStructure = None, authorization: str = Header(None)):
1026
+ # Login API
1027
+ data = dict(data)#request.get_json()
1028
+ try:
1029
+ #print(data["email"])
1030
+ access_token = secure_decode(data["email"]) #create_access_token(identity=data["email"])
1031
+ # store token in database temporarily
1032
+ now = datetime.now().strftime("%c")
1033
+ response = requests.post("http://0.0.0.0:7860/raspsendemail",json={"raspsendemail":{"email":data["email"],"message":forgotpasswordemail(data["email"],access_token),"subject":f"RevsionBank Password Reset"}})
1034
+ #msg = Message(f"RevsionBank Password Reset", recipients=[data["email"]]) # "[email protected]"
1035
+ #msg.body = f"Mail from RevisionBank at {now}"
1036
+ #msg.html = forgotpasswordemail(data["email"],access_token)
1037
+ #mail.send(msg)
1038
+ return {"message": "Reset Email sent"}
1039
+ except Exception as ex:
1040
+ return {"error": f"{type(ex)} {str(ex)}"}
1041
+
1042
+ @app.put('/resetpassword') # PUT
1043
+ async def resetpassword(data : JSONStructure = None, authorization: str = Header(None)):
1044
+ current_user = secure_decode(authorization.replace("Bearer ",""))["email"]
1045
+ if current_user:
1046
+ try:
1047
+ data = dict(data)#request.get_json()
1048
+ email_exists = importcsv.db.users.find_one({"email": current_user})
1049
+ #print(email_exists)
1050
+ if email_exists:
1051
+ user_from_db = list(importcsv.db.users.find({"email": current_user}))[0]
1052
+ #print(user_from_db)
1053
+ # TODO Delete password from here and replace.
1054
+ importcsv.db.users.delete_many(user_from_db)
1055
+ del user_from_db["password"]
1056
+ encrypted_password = hashlib.sha256(data["password"].encode('utf-8')).hexdigest()
1057
+ user_from_db.update({"password": encrypted_password})
1058
+ importcsv.db.users.insert_one(user_from_db)
1059
+ return {"message": "Password reset successful."}
1060
+ elif not email_exists:
1061
+ return {"message": "Email Doesn't exist."}
1062
+ except Exception as ex:
1063
+ return {"error": f"{type(ex)} {str(ex)}"}
1064
+
1065
+
1066
+
1067
+ @app.post('/storesubscription') # POST
1068
+ async def storesubscription(data : JSONStructure = None, authorization: str = Header(None)):
1069
+ current_user = secure_decode(authorization.replace("Bearer ",""))["email"] # outputs the email of the user [email protected]
1070
+ if current_user:
1071
+ try:
1072
+ data = dict(data)#request.get_json()
1073
+ user_from_db = list(importcsv.db.users.find({"email": current_user}))[0] # Gets wanted data for user
1074
+ if data["subscription"] == 'basic':
1075
+ emailsleft = {'emailsleft': 0}
1076
+ elif data["subscription"] == 'standard':
1077
+ emailsleft = {'emailsleft': 40}
1078
+ elif data["subscription"] == 'premium' or data["subscription"] == 'educational':
1079
+ emailsleft = {'emailsleft': 10000000000}
1080
+ if data["subscription"] == "educational":
1081
+ user_from_db.update({"numofaccounts": 200}) # TODO Constant Value needs to be changed when frontend is changed
1082
+ user_from_db.update({"start_date_subscription": data["start_date_subscription"]})
1083
+ user_from_db.update({"end_date_subscription": data["end_date_subscription"]})
1084
+ user_from_db.update({"subscription": data["subscription"]}) # Updates the user with the new subscription
1085
+ user_from_db.update(emailsleft)
1086
+ importcsv.db.users.update_one( { "email": current_user}, {"$set": user_from_db}, upsert = True )
1087
+
1088
+ importcsv.db.subscriptionlog.insert_one({"email": user_from_db["email"],"start_date_subscription": data["start_date_subscription"], "end_date_subscription": data["end_date_subscription"], "subscription": data["subscription"], "emailsleft": emailsleft["emailsleft"]})
1089
+ return {"message": "Subscription Completed."}
1090
+ except Exception as ex:
1091
+ return {"error": f"{type(ex)}-{ex}"}
1092
+
1093
+ else:
1094
+ return {"message": "User not found"}
1095
+ @app.post('/storebetatester') # POST #
1096
+ async def storebetatester(data : JSONStructure = None, authorization: str = Header(None)):
1097
+ data = dict(data)#request.get_json()
1098
+ emailsleft = {'emailsleft': 10000000000}
1099
+ email_exists = importcsv.db.users.find_one({"email": data["email"]})
1100
+ if email_exists:
1101
+ user_from_db = list(importcsv.db.users.find({"email": data["email"]}))[0] # Gets wanted data for user
1102
+ #user_from_db.update({"numofaccounts": 200}) # TODO Constant Value needs to be changed when frontend is changed
1103
+ date_now = datetime.now()
1104
+ datetime_delta = dt.timedelta(weeks=2)
1105
+ user_from_db.update({"start_date_subscription": date_now.isoformat()})
1106
+
1107
+ user_from_db.update({"end_date_subscription": (datetime_delta + date_now).isoformat()})
1108
+ user_from_db.update({"subscription": "premium"}) # Updates the user with the new subscription
1109
+ user_from_db.update(emailsleft)
1110
+ user_from_db.update({"betatester": "true"})
1111
+ importcsv.db.users.update_one( { "email": data["email"]}, {"$set": user_from_db}, upsert = True )
1112
+
1113
+ #importcsv.db.subscriptionlog.insert_one({"email": user_from_db["email"],"start_date_subscription": data["start_date_subscription"], "end_date_subscription": data["end_date_subscription"], "subscription": data["subscription"], "emailsleft": emailsleft["emailsleft"]})
1114
+ return {"message": "Beta Tester Subscription Completed."}
1115
+ elif not email_exists:
1116
+ return {"message": "User not found"}
1117
+ @app.post('/storeeducationalfreetrial') # POST #
1118
+ async def storeeducationalfreetrial(data : JSONStructure = None, authorization: str = Header(None)):
1119
+ data = dict(data)#request.get_json()
1120
+ try:
1121
+ emailsleft = {'emailsleft': 10000000000}
1122
+ email_exists = importcsv.db.users.find_one({"email": data["email"]})
1123
+ if email_exists:
1124
+ user_from_db = list(importcsv.db.users.find({"email": data["email"]}))[0] # Gets wanted data for user
1125
+ #user_from_db.update({"numofaccounts": 200}) # TODO Constant Value needs to be changed when frontend is changed
1126
+ date_now = datetime.now()
1127
+ decimal_part = float(3 / 7)
1128
+ datetime_delta = dt.timedelta(weeks=4 + decimal_part)
1129
+ user_from_db.update({"start_date_subscription": date_now.isoformat()})
1130
+ user_from_db.update({"numofaccounts": 200})
1131
+
1132
+ user_from_db.update({"end_date_subscription": (datetime_delta + date_now).isoformat()})
1133
+ user_from_db.update({"subscription": "educational"}) # Updates the user with the new subscription
1134
+ user_from_db.update(emailsleft)
1135
+ importcsv.db.users.update_one( { "email": data["email"]}, {"$set": user_from_db}, upsert = True )
1136
+
1137
+ #importcsv.db.subscriptionlog.insert_one({"email": user_from_db["email"],"start_date_subscription": data["start_date_subscription"], "end_date_subscription": data["end_date_subscription"], "subscription": data["subscription"], "emailsleft": emailsleft["emailsleft"]})
1138
+ return {"message": "Educational Freetrial Subscription Completed."}
1139
+ elif not email_exists:
1140
+ return {"message": "User not found"}
1141
+ except Exception as ex:
1142
+ return {"error": f"{type(ex)}-{ex}"}
1143
+ @app.post('/scheduleeducationalfreetrial') # POST #
1144
+ async def scheduleeducationalfreetrial(data : JSONStructure = None, authorization: str = Header(None)):
1145
+ data = dict(data)#request.get_json()
1146
+ try:
1147
+ regexdatetime = re.compile(r'\d\d\d\d-\d\d-\d\d')
1148
+ mo = regexdatetime.search(data["educationalfreetrialdate"])
1149
+ educationalfreetrialdate = mo.group()
1150
+ except AttributeError as aex:
1151
+ return {"error":r"Datetime shape is %Y-%m-%d"}
1152
+ try:
1153
+ email_exists = importcsv.db.users.find_one({"email": data["email"]})
1154
+ if email_exists:
1155
+ importcsv.db.schedulededucationalfreetrial.insert_one({"email": data["email"],"educationalfreetrialdate":educationalfreetrialdate})
1156
+ return {"message": "Educational Freetrial Scheduled."}
1157
+ elif not email_exists:
1158
+ return {"message": "User not found"}
1159
+ except Exception as ex:
1160
+ return {"error": f"{type(ex)}-{ex}"}
1161
+ @app.post('/deletescheduleeducationalfreetrial') # POST #
1162
+ async def deletescheduleeducationalfreetrial(data : JSONStructure = None, authorization: str = Header(None)):
1163
+ data = dict(data)#request.get_json()
1164
+ current_user = data["email"]
1165
+ current_user = importcsv.db.users.find_one({"email": data["email"]})
1166
+ if current_user:
1167
+ try:
1168
+ user_from_db = list(importcsv.db.schedulededucationalfreetrial.find({"email": data["email"]}))[0]
1169
+ importcsv.db.schedulededucationalfreetrial.delete_many(user_from_db)
1170
+ return {"message":"Educational Freetrial Unscheduled."}
1171
+ except Exception as ex:
1172
+ return {"error": f"{type(ex)}-{ex}"}
1173
+ @app.post('/removebetatester') # POST #
1174
+ async def removebetatester(data : JSONStructure = None, authorization: str = Header(None)):
1175
+ data = dict(data)#request.get_json()
1176
+ email_exists = importcsv.db.users.find_one({"email": data["email"]})
1177
+ if email_exists:
1178
+ user_from_db = list(importcsv.db.users.find({"email": data["email"]}))[0] # Gets wanted data for user
1179
+ importcsv.db.users.delete_many(user_from_db)
1180
+ del user_from_db["end_date_subscription"], user_from_db["start_date_subscription"],user_from_db["subscription"],user_from_db["emailsleft"], user_from_db["betatester"]
1181
+ importcsv.db.users.update_one( { "email": data["email"]}, {"$set": user_from_db}, upsert = True )
1182
+ return {"message": "Beta Tester Subscription Deleted."}
1183
+ elif not email_exists:
1184
+ return {"message": "User not found"}
1185
+ @app.get('/getsubscription') # GET
1186
+ async def getsubscription(authorization: str = Header(None)):
1187
+ current_user = secure_decode(authorization.replace("Bearer ",""))["email"] # outputs the email of the user [email protected]
1188
+ if current_user:
1189
+ try:
1190
+ user_from_db = list(importcsv.db.users.find({"email": current_user}))[0] # Gets wanted data for user
1191
+ end_date = user_from_db["end_date_subscription"]
1192
+ end_date_subscription = {"end_date_subscription": end_date}
1193
+ return end_date_subscription
1194
+ except Exception as ex:
1195
+ return {"error": f"{type(ex)}-{ex}"}
1196
+ @app.get('/getemailcount') # GET
1197
+ async def getemailcount(authorization: str = Header(None)):
1198
+ current_user = secure_decode(authorization.replace("Bearer ",""))["email"] # outputs the email of the user [email protected]
1199
+ if current_user:
1200
+ try:
1201
+ user_from_db = list(importcsv.db.users.find({"email": current_user}))[0] # Gets wanted data for user
1202
+ emailcount = user_from_db["emailsleft"]
1203
+ emailcountres = {"emailcount": emailcount}
1204
+ return emailcountres
1205
+ except Exception as ex:
1206
+ return {"error": f"{type(ex)}-{ex}"}
1207
+ @app.post('/storefreetrial') # POST
1208
+ async def storefreetrial(data : JSONStructure = None, authorization: str = Header(None)):
1209
+ current_user = secure_decode(authorization.replace("Bearer ",""))["email"] # outputs the email of the user [email protected]
1210
+ if current_user:
1211
+ try:
1212
+ data = dict(data)#request.get_json()
1213
+ user_from_db = list(importcsv.db.users.find({"email": current_user}))[0] # Gets wanted data for user
1214
+ if 'freetrial' not in user_from_db:
1215
+ user_from_db.update({"freetrial": "true"})
1216
+ emailsleft = {'emailsleft': 10000000000}
1217
+ user_from_db.update({"start_date_subscription": data["start_date_subscription"]})
1218
+ user_from_db.update({"end_date_subscription": data["end_date_subscription"]})
1219
+ user_from_db.update({"subscription": data["subscription"]}) # Updates the user with the new subscription
1220
+ user_from_db.update(emailsleft)
1221
+ importcsv.db.users.update_one( { "email": current_user}, {"$set": user_from_db}, upsert = True )
1222
+ importcsv.db.users.update_one({"email": current_user}, {"$set": user_from_db}, upsert = True)
1223
+ importcsv.db.freetrialhistory.insert_one({"email": user_from_db["email"],"freetrial":"true"})
1224
+ return {"message": "Freetrial Redeemed."}
1225
+ elif 'freetrial' in user_from_db:
1226
+ return {"error": "Freetrial has already used."}
1227
+ except Exception as ex:
1228
+ return {"error": f"{type(ex)}-{ex}"}
1229
+ @app.post('/setstudentsubscriptions') # POST
1230
+ async def setstudentsubscriptions(data : JSONStructure = None, authorization: str = Header(None)):
1231
+ current_user = secure_decode(authorization.replace("Bearer ",""))["email"] # outputs the email of the user [email protected]
1232
+ if current_user:
1233
+ # Hostemail is the primary key for the studentsubscription collection
1234
+ try:
1235
+ data = dict(data)#request.get_json()
1236
+ # {"hostemail": "[email protected]","hostnumofaccounts": 198,"studentemails": [{"email": "[email protected]","password": "mann35"},{"email": "[email protected]","password": "billy45"},{"email": "[email protected]","password": "bobby46"}],"studentemailsleft": 20,"studentsubscription": "student educational"}
1237
+ user_from_db = list(importcsv.db.users.find({"email": current_user}))[0] # Host emails data
1238
+ studentsnotexist = []
1239
+ for student in data["studentemails"]: # data["studentemails"] is a list of dictionaries [{"email":"[email protected]","password":"password"},{"email":"[email protected]","password":"password"}]
1240
+ student_user_from_db = importcsv.db.studentsubscriptions.find_one({"email": student["email"]}) # Checks if any of the emails added are in the database
1241
+ if not student_user_from_db: # If the email is not in the database, then we need to store the data into the database
1242
+ studentsnotexist.append(student) # Adds the email to the list of emails that do not exist in the database
1243
+
1244
+ if studentsnotexist == []: # If all data is already in the database, no need to store it.
1245
+ return {"message": "all students exist."}
1246
+ elif studentsnotexist != []: # If there are emails that are not in the database, we need to store the data into the database
1247
+ if user_from_db["numofaccounts"] > 0:
1248
+ for student in studentsnotexist: # Goes through the emails not in the database
1249
+ encrypted_password = hashlib.sha256(student["password"].encode('utf-8')).hexdigest()# Encrypts the password
1250
+ # Then stores data into the studentsubscriptions collection
1251
+ importcsv.db.studentsubscriptions.insert_one({"hostemail":current_user,"email": student["email"],"password": encrypted_password,"emailsleft": 20,"subscription": "student educational"})
1252
+
1253
+ return {"message": "student subscriptions Set."}
1254
+ elif user_from_db["numofaccounts"] <= 0:
1255
+ return {"error": "No more student accounts left."}
1256
+ except Exception as ex:
1257
+ return {"error": f"{type(ex)}-{ex}"}
1258
+ @app.get('/getstudentsubscriptions') # GET
1259
+ async def getstudentsubscriptions(authorization: str = Header(None)):
1260
+ current_user = secure_decode(authorization.replace("Bearer ",""))["email"]
1261
+ if current_user:
1262
+ try:
1263
+ student_user_from_db = list(importcsv.db.studentsubscriptions.find({"hostemail": current_user})) # [0]
1264
+ user_from_db = list(importcsv.db.users.find({"email": current_user}))[0]
1265
+ for student in student_user_from_db:
1266
+ del student["_id"], student["password"],student["hostemail"],student['subscription']
1267
+
1268
+ importcsv.db.users.delete_many(user_from_db) # Deletes the data in order to update it.
1269
+ del user_from_db["numofaccounts"] # Deletes the numofaccounts to update it.
1270
+ user_from_db.update({"numofaccounts": 200 - len(student_user_from_db)}) # Updates the number of accounts
1271
+ importcsv.db.users.insert_one(user_from_db) # inserts updated data into the host emails account
1272
+ return {"result":student_user_from_db}
1273
+ except Exception as ex:
1274
+ return {"error": f"{type(ex)}-{ex}"}
1275
+ @app.get('/checkstudentsubscriptions') # GET
1276
+ async def checkstudentsubscriptions(authorization: str = Header(None)):
1277
+ current_user = secure_decode(authorization.replace("Bearer ",""))["email"] # outputs the email of the user [email protected]
1278
+ if current_user:
1279
+ try:
1280
+ student_from_db = list(importcsv.db.studentsubscriptions.find({"email": current_user}))[0] # Gets wanted data for user
1281
+ student_subscription = student_from_db["subscription"]
1282
+ student_subscription_json = {"student_subscription": student_subscription}
1283
+ return student_subscription_json
1284
+ except Exception as ex:
1285
+ return {"error": f"{type(ex)}-{ex}"}
1286
+ @app.post('/deletestudentaccount') # POST
1287
+ async def deletestudentaccount(data : JSONStructure = None, authorization: str = Header(None)):
1288
+ current_user = secure_decode(authorization.replace("Bearer ",""))["email"]
1289
+ if current_user:
1290
+ data = dict(data)#request.get_json()
1291
+ try:
1292
+ hostkey = importcsv.db.studentsubscriptions.find_one({"hostemail": current_user})
1293
+ studentkey = importcsv.db.studentsubscriptions.find_one({"email": data["studentemail"]})
1294
+ if hostkey and studentkey:
1295
+ importcsv.db.studentsubscriptions.delete_one({"email": data["studentemail"]})
1296
+ return {"message": "Student account deleted."}
1297
+ else:
1298
+ return {"error": "Student account does not exist."}
1299
+ except Exception as ex:
1300
+ return {"error": f"{type(ex)}-{ex}"}
1301
+ @app.put('/changestudentpassword') # PUT
1302
+ async def changestudentpassword(data : JSONStructure = None, authorization: str = Header(None)):
1303
+ current_user = secure_decode(authorization.replace("Bearer ",""))["email"]
1304
+ if current_user:
1305
+ data = dict(data)#request.get_json()
1306
+ try:
1307
+ hostkey = importcsv.db.studentsubscriptions.find_one({"hostemail": current_user})
1308
+ studentkey = importcsv.db.studentsubscriptions.find_one({"email": data["studentemail"]})
1309
+ if hostkey and studentkey:
1310
+ student_user_from_db = list(importcsv.db.studentsubscriptions.find({"email": data["studentemail"]}))[0]
1311
+ # TODO Delete password from here and replace.
1312
+ importcsv.db.studentsubscriptions.delete_many(student_user_from_db)
1313
+ del student_user_from_db["password"]
1314
+ encrypted_password = hashlib.sha256(data["password"].encode('utf-8')).hexdigest()
1315
+ student_user_from_db.update({"password": encrypted_password})
1316
+ importcsv.db.studentsubscriptions.insert_one(student_user_from_db)
1317
+ return {"message": "Password reset successful."}
1318
+ else:
1319
+ return {"error": "Student account does not exist."}
1320
+ except Exception as ex:
1321
+ return {"error": f"{type(ex)}-{ex}"}
1322
+
1323
+
1324
+
1325
+ @app.get('/getfreetrial') # GET
1326
+ async def getfreetrial(authorization: str = Header(None)):
1327
+ current_user = secure_decode(authorization.replace("Bearer ",""))["email"] # outputs the email of the user [email protected]
1328
+ if current_user:
1329
+ try:
1330
+ freetrialhistory = list(importcsv.db.freetrialhistory.find({"email": current_user}))[0] # Gets wanted data for user
1331
+ freetrial = freetrialhistory["freetrial"]
1332
+ freetrial_subscription = {"freetrial": freetrial} # check freetrial
1333
+ return freetrial_subscription
1334
+ except Exception as ex:
1335
+ return {"error": f"{type(ex)}-{ex}"}
1336
+ @app.get('/getemail') # GET
1337
+ async def getemail(authorization: str = Header(None)):
1338
+ current_user = secure_decode(authorization.replace("Bearer ",""))["email"] # outputs the email of the user [email protected]
1339
+ if current_user:
1340
+ try:
1341
+ user_from_db = check_user_from_db(current_user)
1342
+ return {"email":user_from_db["email"]}
1343
+ except Exception as ex:
1344
+ return {"error": f"{type(ex)}-{ex}"}
1345
+
1346
+ @app.delete('/deletesubscription') # DELETE
1347
+ async def deletesubscription(authorization: str = Header(None)):
1348
+ current_user = secure_decode(authorization.replace("Bearer ",""))["email"] # outputs the email of the user [email protected]
1349
+ if current_user:
1350
+ try:
1351
+ user_from_db = list(importcsv.db.users.find({"email": current_user}))[0]
1352
+ importcsv.db.users.delete_many(user_from_db)
1353
+ if "end_date_subscription" in user_from_db:
1354
+ del user_from_db["end_date_subscription"]
1355
+ if "start_date_subscription" in user_from_db:
1356
+ del user_from_db["start_date_subscription"]
1357
+ if "subscription" in user_from_db:
1358
+ del user_from_db["subscription"]
1359
+ if "emailsleft" in user_from_db:
1360
+ del user_from_db["emailsleft"]
1361
+ if "numofaccounts" in user_from_db:
1362
+ del user_from_db["numofaccounts"]
1363
+ importcsv.db.users.update_one( { "email": current_user}, {"$set": user_from_db}, upsert = True )
1364
+
1365
+ return {"message":"Subscription deleted from expiration"}
1366
+ except Exception as ex:
1367
+ return {"error": f"{type(ex)}-{ex}"}
1368
+ @app.get('/getaccountinfo') # GET
1369
+ async def getaccountinfo(authorization: str = Header(None)):
1370
+ current_user = secure_decode(authorization.replace("Bearer ",""))["email"] # outputs the email of the user [email protected]
1371
+ if current_user:
1372
+ try:
1373
+ email_exists = importcsv.db.users.find_one({"email": current_user})
1374
+ email_exists_student = importcsv.db.studentsubscriptions.find_one({"email": current_user})
1375
+ if email_exists:
1376
+ user_from_db = list(importcsv.db.users.find({"email": current_user}))[0]
1377
+ del user_from_db["password"], user_from_db["_id"]
1378
+ return user_from_db
1379
+ elif email_exists_student:
1380
+ student_user_from_db = list(importcsv.db.studentsubscriptions.find({"email": current_user}))[0]
1381
+ host_from_db = list(importcsv.db.users.find({"email": student_user_from_db["hostemail"]}))[0]
1382
+ student_user_from_db.update({"start_date_subscription":host_from_db["start_date_subscription"]})
1383
+ student_user_from_db.update({"end_date_subscription":host_from_db["end_date_subscription"]})
1384
+ del student_user_from_db["password"], student_user_from_db["_id"]
1385
+ return student_user_from_db
1386
+ #return {"error": f"account not found"}
1387
+ except Exception as ex:
1388
+ return {"error": f"{type(ex)}-{ex}"}
1389
+ @app.delete('/deleteaccount') # DELETE
1390
+ async def deleteaccount(authorization: str = Header(None)):
1391
+ current_user = secure_decode(authorization.replace("Bearer ",""))["email"] # outputs the email of the user [email protected]
1392
+ if current_user:
1393
+ try:
1394
+ user_from_db = list(importcsv.db.users.find({"email": current_user}))[0]
1395
+ importcsv.db.users.delete_many(user_from_db)
1396
+ return {"message":"Account Deleted"}
1397
+ except Exception as ex:
1398
+ return {"error": f"{type(ex)}-{ex}"}
1399
+ @app.get('/getedexcelpapers')# GET # allow all origins all methods.
1400
+ async def getedexcelpapers(authorization: str = Header(None)):
1401
+ try:
1402
+ data = dict(data)#request.get_json()
1403
+ dataedexcel = list(importcsv.db.edexcelpapers.find({"year":"AS Level"}))
1404
+ return {"result":dataedexcel}
1405
+ except Exception as ex:
1406
+ return {"error":f"{type(ex)},ex"}
1407
+
1408
+ async def main():
1409
+ config = uvicorn.Config("main:app", port=7860, log_level="info",host="0.0.0.0",reload=True)
1410
+ server = uvicorn.Server(config)
1411
+ await server.serve()
1412
+
1413
+ if __name__ == "__main__":
1414
+ asyncio.run(main())
maintest.py ADDED
@@ -0,0 +1,76 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import jwt
2
+ from fastapi import FastAPI, Header
3
+ from pydantic import BaseModel
4
+ from typing import Optional
5
+ import asyncio
6
+ import uvicorn
7
+ from RevisionBankModels import *
8
+ JWT_SECRET = "secret" # IRL we should NEVER hardcode the secret: it should be an evironment variable!!!
9
+ JWT_ALGORITHM = "HS256"
10
+
11
+ app = FastAPI()
12
+
13
+ class Auth(BaseModel):
14
+ name: str
15
+ password: str
16
+ class Person(BaseModel):
17
+ name: str
18
+ gender: Optional[str] = None
19
+ age: float
20
+ checked: Optional[bool] = None
21
+
22
+ @app.post("/signup")
23
+ async def root(person: Auth):
24
+ try:
25
+ person = dict(person)
26
+ access_token = secure_encode({"name":person})
27
+ print(access_token)
28
+ # here we can add code to check the user (by email)
29
+ # e.g. select the user from the DB and see its permissions
30
+ return {"access_token":access_token}
31
+ except Exception as ex:
32
+ print(ex)
33
+ return "Unauthorized Access!"
34
+ # in this example we'll simply return the person entity from the request body
35
+ # after adding a "checked"
36
+
37
+ @app.post("/signin")
38
+ async def root(person: Person, authorization: str = Header(None)):
39
+ try:
40
+ decoded = secure_decode(authorization.replace("Bearer ",""))
41
+ # here we can add code to check the user (by email)
42
+ # e.g. select the user from the DB and see its permissions
43
+ print(decoded)
44
+ return {"message":"signed in"}
45
+ except:
46
+ return "Unauthorized Access!"
47
+ # in this example we'll simply return the person entity from the request body
48
+ # after adding a "checked"
49
+
50
+ @app.post('/forgotpassword') # POST
51
+ def forgotpassword(data : GenericSingleObject):
52
+ data = dict(data)
53
+ print(data)
54
+ return {"message":"hi"}
55
+
56
+ def secure_encode(token):
57
+ # if we want to sign/encrypt the JSON object: {"hello": "world"}, we can do it as follows
58
+ # encoded = jwt.encode({"hello": "world"}, JWT_SECRET, algorithm=JWT_ALGORITHM)
59
+ encoded_token = jwt.encode(token, JWT_SECRET, algorithm=JWT_ALGORITHM)
60
+ # this is often used on the client side to encode the user's email address or other properties
61
+ return encoded_token
62
+
63
+ def secure_decode(token):
64
+ # if we want to sign/encrypt the JSON object: {"hello": "world"}, we can do it as follows
65
+ # encoded = jwt.encode({"hello": "world"}, JWT_SECRET, algorithm=JWT_ALGORITHM)
66
+ decoded_token = jwt.decode(token, JWT_SECRET, algorithms=JWT_ALGORITHM)
67
+ # this is often used on the client side to encode the user's email address or other properties
68
+ return decoded_token
69
+
70
+ async def main():
71
+ config = uvicorn.Config("main:app", port=7860, log_level="info",host="0.0.0.0",reload=True)
72
+ server = uvicorn.Server(config)
73
+ await server.serve()
74
+
75
+ if __name__ == "__main__":
76
+ asyncio.run(main())
models.py ADDED
@@ -0,0 +1,38 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from pydantic import BaseModel, Field
2
+ from typing import Optional
3
+ from bson.objectid import ObjectId
4
+ import bcrypt
5
+ import hashlib
6
+ # https://www.mongodb.com/developer/how-to/flask-python-mongodb/
7
+ # https://codehandbook.org/creating-rest-api-using-python-mongodb/
8
+ # https://zetcode.com/python/bcrypt/
9
+ class PydanticObjectID(ObjectId):
10
+ @classmethod
11
+ def __get_validators__(cls):
12
+ yield cls.validate
13
+ @classmethod
14
+ def validate(cls, v):
15
+ if not isinstance(v, ObjectId):
16
+ raise TypeError(f'Must be an ObjectId')
17
+ return str(v)
18
+ class Users(BaseModel):
19
+ id : PydanticObjectID # Sets MongoDB ID
20
+ email: str
21
+ password: str
22
+ access: bool
23
+ def generate_hash_pw(self):
24
+ salt = bcrypt.gensalt()
25
+ data = self.dict(by_alias=True, exclude_none=True)
26
+ hashed = bcrypt.hashpw(data["password"].encode('utf-8'), salt)
27
+ return hashed,str(salt).replace("b'","").replace("'","")
28
+
29
+ def to_bson(self):
30
+ data = self.dict(by_alias=True,exclude_none=True)
31
+ hashed = hashlib.sha256(data["password"].encode('utf-8')).hexdigest()
32
+ del data["password"]
33
+ data["password"] = hashed
34
+ data["_id"] = data["id"]
35
+ del data["id"]
36
+ return data
37
+ #data_val = json.loads(json_util.dumps(data))
38
+
physics.py ADDED
@@ -0,0 +1,18 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from physicsaqa import PhysicsAQA
2
+
3
+ data = PhysicsAQA().collectdata()
4
+ #print(data.keys())
5
+ #chapt = list({"label":chapter,"value":ind}for ind,chapter in enumerate(list(data.keys())))
6
+ #print(chapt)
7
+ topic = list(top for dic in list(data.values()) for top in dic.keys() if "MS" not in top)
8
+ topicms = list(top for dic in list(data.values()) for top in dic.keys() if "MS" in top)
9
+ resulttop = [{"label":top,"value":ind} for ind,top in enumerate(topic)]
10
+ resulttopms = [{"label":top,"value":ind} for ind,top in enumerate(topicms)]
11
+ #print(resulttop)
12
+ dic = {}
13
+ dic["physicsaqadata"] = {}
14
+ for key,val in data.items():
15
+ dic["physicsaqadata"][key] = [{"label":val,"value":ind}for ind,val in enumerate(list(val.keys()))]
16
+
17
+ ## = list(for key,val in data.items())
18
+ print(dic) #["physicsaqadata"]["Section 2: Particles & Radiation"]
physicsaqa.py ADDED
@@ -0,0 +1,44 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import requests
2
+ import re
3
+ from bs4 import BeautifulSoup
4
+ class PhysicsAQA:
5
+ def __init__(self) -> None:
6
+
7
+ self.url = "https://www.savemyexams.co.uk/a-level/physics/aqa/-/pages/topic-questions-pdf/"
8
+
9
+ response= requests.get(self.url).text
10
+ self.soup = BeautifulSoup(response,features='lxml')#
11
+
12
+ def collectdata(self):
13
+ physicsaqa = {}
14
+ slice_indexes = []
15
+ data = []
16
+ data = self.soup.find_all(["td"])[2:]
17
+ for ind,td in enumerate(data):
18
+ if "." in td.text or "Section" in td.text:
19
+ #print(td.text,ind)
20
+ slice_indexes.append(ind)
21
+
22
+ #print(len(slice_indexes))
23
+ for ind in range(len(slice_indexes)+1):
24
+ if ind == len(slice_indexes) -1:
25
+ break
26
+
27
+ sliceone = slice_indexes[ind]
28
+ slicetwo = slice_indexes[ind + 1]
29
+ chapterdata = data[sliceone:slicetwo]
30
+ chapternum = data[sliceone:slicetwo][0].text.replace('\n','').replace('\xa0','')
31
+ #print(sliceone,slicetwo)
32
+ #print(data[sliceone:slicetwo])
33
+ physicsaqa[chapternum] = {}
34
+ for chapter in chapterdata:
35
+ #print(chapter)
36
+ if chapter.find("a",href=True) != None:
37
+ #print(chapter)
38
+ physicsaqa[chapternum][chapter.find("a",href=True).text.replace('\xa0','').replace('\n','').replace("\u200b","")] = chapter.find("a",href=True)["href"]
39
+ return physicsaqa
40
+ if __name__ == "__main__":
41
+ data = PhysicsAQA().collectdata()
42
+
43
+ print(data)
44
+
raspsendemail.py ADDED
@@ -0,0 +1,95 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import smtplib, ssl
2
+ from email import encoders
3
+ from email.mime.base import MIMEBase
4
+ from email.mime.multipart import MIMEMultipart
5
+ from email.mime.text import MIMEText
6
+
7
+
8
+ class RaspEmail:
9
+ @staticmethod
10
+ def send(receiver_email,subject,htmlmessage,attachment=None):
11
+ sender_email = "[email protected]"
12
+ message = MIMEMultipart("alternative")
13
+ message["Subject"] = subject
14
+ message["From"] = sender_email
15
+ message["To"] = receiver_email
16
+ password = "ktqgjfzgcbfacsve"
17
+
18
+
19
+ # Turn these into plain/html MIMEText objects
20
+ part1 = MIMEText(htmlmessage, "html")
21
+
22
+ # Add HTML/plain-text parts to MIMEMultipart message.
23
+ # The email client will try to render the last part first
24
+
25
+ message.attach(part1)
26
+ # files should be a dictionary of filenames & base64 content
27
+ #print(attachment)
28
+ if attachment != None:
29
+ for file in attachment:
30
+ for key,val in file.items():
31
+ if ".png" in key:
32
+ part2 = MIMEBase('image', 'png')
33
+ image = val.replace("data:image/png;base64,","")
34
+ part2.set_payload(image)
35
+ part2.add_header('Content-Transfer-Encoding', 'base64')
36
+ part2['Content-Disposition'] = 'attachment; filename="%s"' % key
37
+ message.attach(part2)
38
+ elif ".jpg" in key or "jpeg" in key:
39
+ part2 = MIMEBase('image', 'jpeg')
40
+ image = val.replace("data:image/jpeg;base64,","")
41
+ part2.set_payload(image)
42
+ part2.add_header('Content-Transfer-Encoding', 'base64')
43
+ part2['Content-Disposition'] = 'attachment; filename="%s"' % key
44
+ message.attach(part2)
45
+
46
+
47
+
48
+ # Create secure connection with server and send email
49
+ context = ssl.create_default_context()
50
+ with smtplib.SMTP_SSL("smtp.gmail.com", 465, context=context) as server:
51
+ server.login(sender_email, password)
52
+ server.sendmail(
53
+ sender_email, receiver_email, message.as_string()
54
+ )
55
+ @staticmethod
56
+ def send_attachment(receiver_email,subject,filename,htmlmessage):
57
+ sender_email = "[email protected]"
58
+ password = "ktqgjfzgcbfacsve"
59
+
60
+ # Create a multipart message and set headers
61
+ message = MIMEMultipart()
62
+ message["From"] = sender_email
63
+ message["To"] = receiver_email
64
+ message["Subject"] = subject
65
+ message["Bcc"] = receiver_email # Recommended for mass emails
66
+
67
+ part1 = MIMEText(htmlmessage, "html")
68
+ # Add body to email
69
+ message.attach(part1)
70
+
71
+ # Open PDF file in binary mode
72
+ with open(filename, "rb") as attachment:
73
+ # Add file as application/octet-stream
74
+ # Email client can usually download this automatically as attachment
75
+ part = MIMEBase("application", "octet-stream")
76
+ part.set_payload(attachment.read())
77
+
78
+ # Encode file in ASCII characters to send by email
79
+ encoders.encode_base64(part)
80
+
81
+ # Add header as key/value pair to attachment part
82
+ part.add_header(
83
+ "Content-Disposition",
84
+ f"attachment; filename= {filename}",
85
+ )
86
+
87
+ # Add attachment to message and convert message to string
88
+ message.attach(part)
89
+ text = message.as_string()
90
+
91
+ # Log in to server using secure context and send email
92
+ context = ssl.create_default_context()
93
+ with smtplib.SMTP_SSL("smtp.gmail.com", 465, context=context) as server:
94
+ server.login(sender_email, password)
95
+ server.sendmail(sender_email, receiver_email, text)
requirements.txt ADDED
@@ -0,0 +1,77 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ aniso8601==9.0.1
2
+ backcall==0.2.0
3
+ beautifulsoup4==4.9.3
4
+ blis==0.7.5
5
+ catalogue==2.0.6
6
+ certifi==2021.10.8
7
+ charset-normalizer==2.0.9
8
+ click==8.0.3
9
+ colorama==0.4.4
10
+ python-dotenv==0.19.2
11
+ cymem==2.0.6
12
+ stripe==4.1.0
13
+ debugpy==1.5.1
14
+ decorator==5.1.0
15
+ Flask-Mail==0.9.1
16
+ fastapi-utils==0.2.1
17
+ dnspython==2.1.0
18
+ passlib==1.7.4
19
+ opencv-python==4.6.0.66
20
+ en-core-web-sm @ https://github.com/explosion/spacy-models/releases/download/en_core_web_sm-3.2.0/en_core_web_sm-3.2.0-py3-none-any.whl
21
+ entrypoints==0.3
22
+ pytesseract==0.3.9
23
+ Flask==2.0.1
24
+ fastapi
25
+ uvicorn
26
+ Flask-Bcrypt==0.7.1
27
+ Flask-Cors==3.0.10
28
+ sendgrid==6.9.7
29
+ Flask-JWT-Extended==4.3.1
30
+ Flask-Mail==0.9.1
31
+ Flask-RESTful==0.3.9
32
+ Flask-WTF==0.15.1
33
+ lxml==4.8.0
34
+ gunicorn==20.1.0
35
+ idna==3.3
36
+ ipykernel==6.6.0
37
+ ipython==7.30.1
38
+ itsdangerous==2.0.1
39
+ jedi==0.18.1
40
+ Jinja2==3.0.3
41
+ jupyter-client==7.1.0
42
+ jupyter-core==4.9.1
43
+ langcodes==3.3.0
44
+ MarkupSafe==2.0.1
45
+ matplotlib-inline==0.1.3
46
+ murmurhash==1.0.6
47
+ nest-asyncio==1.5.4
48
+ numpy==1.21.4
49
+ packaging==21.3
50
+ parso==0.8.3
51
+ pathy==0.6.1
52
+ pickleshare==0.7.5
53
+ preshed==3.0.6
54
+ prompt-toolkit==3.0.24
55
+ pydantic==1.8.2
56
+ Pygments==2.10.0
57
+ pymongo==4.0.1
58
+ pyparsing==3.0.6
59
+ python-dateutil==2.8.2
60
+ requests==2.26.0
61
+ six==1.16.0
62
+ smart-open==5.2.1
63
+ soupsieve==2.3.1
64
+ spacy==3.2.1
65
+ spacy-legacy==3.0.8
66
+ spacy-loggers==1.0.1
67
+ srsly==2.4.2
68
+ thinc==8.0.13
69
+ tornado==6.1
70
+ tqdm==4.62.3
71
+ traitlets==5.1.1
72
+ typer==0.4.0
73
+ typing_extensions==4.0.1
74
+ urllib3==1.26.7
75
+ wasabi==0.9.0
76
+ wcwidth==0.2.5
77
+ Werkzeug==2.0.2
revisionbankscheduler ADDED
@@ -0,0 +1 @@
 
 
1
+ Subproject commit a7502270f2f36643bbe13ea3f4da6498f642b3af
revisionbankscheduler.py ADDED
@@ -0,0 +1,138 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import random
2
+ from raspsendemail import RaspEmail
3
+
4
+
5
+ class RevisionBankScheduler:
6
+ def __init__(self,importcsv) -> None:
7
+ #self.usercardstosend = list()
8
+ self.importcsv = importcsv
9
+ def sendimagecard(self,user,card):
10
+ imagecardjson = {"email":user["sendtoemail"],"message":f"{card['revisioncardtitle']}\n{card['revisioncard']}","subject":card["subject"],"attachment":[{card["revisioncardimgname"][0]:card["revisioncardimage"][0]}]}
11
+ ##print(user["sendtoemail"])
12
+ RaspEmail.send(receiver_email = imagecardjson["email"],subject = imagecardjson["subject"],htmlmessage = imagecardjson["message"],attachment = imagecardjson["attachment"])
13
+
14
+ #response = requests.post("https://revisionbank-email.onrender.com/raspsendemail",json={"raspsendemail":{"email":user["sendtoemail"],"message":f"{card['revisioncardtitle']}\n{card['revisioncard']}","subject":card["subject"],"attachment":[{card["revisioncardimgname"][0]:card["revisioncardimage"][0]}]}})
15
+
16
+ #print(response.text)
17
+ #sendgrid_send(user["sendtoemail"],f"{card['revisioncardtitle']}\n{card['revisioncard']}",card["subject"])
18
+ def sendtextcard(self,user,card):
19
+ #print(user["sendtoemail"])
20
+ #response = requests.post("https://revisionbank-email.onrender.com/raspsendemail",json={"raspsendemail":{"email":user["sendtoemail"],"message":f"{card['revisioncardtitle']}\n{card['revisioncard']}","subject":card["subject"]}})
21
+ textcardjson = {"email":user["sendtoemail"],"message":f"{card['revisioncardtitle']}\n{card['revisioncard']}","subject":card["subject"]}
22
+ #print(textcardjson["attachment"])
23
+ #print(textcardjson)
24
+ RaspEmail.send(receiver_email = textcardjson["email"],subject = textcardjson["subject"],htmlmessage = textcardjson["message"])#,attachment = textcardjson["attachment"])
25
+
26
+ #sendgrid_send(user["sendtoemail"],f"{card['revisioncardtitle']}\n{card['revisioncard']}",card["subject"])
27
+ #print(response.text)
28
+ #brlvuddpzmanpidi
29
+ def getcarddetails(self):
30
+ # TODO Separate cards to there own collection
31
+ userscheduledcards = list(self.importcsv.db.scheduledcards.find())
32
+ usercardstosend = []
33
+ for user in userscheduledcards:
34
+ usercardstosend.append({"sendtoemail":user["sendtoemail"],"revisioncards":user["revisioncards"],"revisionscheduleinterval":user["revisionscheduleinterval"]})
35
+ return usercardstosend
36
+ def runschedule(self):
37
+ def setprobabilities(revisioncard):
38
+ try:
39
+ revcolor = revisioncard["color"]
40
+ if revcolor == "green":
41
+ return 25
42
+ if revcolor == "amber":
43
+ return 50
44
+ if revcolor == "red":
45
+ return 75
46
+ except Exception as ex:
47
+ #print(type(ex),ex)
48
+ return 100
49
+
50
+ print("Revision card loading...")
51
+ usercardstosend = self.getcarddetails()
52
+ #print("Revision card loaded.")
53
+ #print(usercardstosend)
54
+ for user in usercardstosend:
55
+ # Creating a name list
56
+ revisioncards = user["revisioncards"]
57
+ #print(revisioncards)
58
+ weights = list(map(setprobabilities,revisioncards))
59
+ trafficlightemailsleft = 3
60
+
61
+
62
+ for card,weight in zip(revisioncards,weights):
63
+ #print(card)
64
+ #print(weight)
65
+ if weight == 100:
66
+ # send email
67
+ print("Sending revision card...")
68
+ #time.sleep(10)
69
+ #print(card)
70
+ #
71
+ if "revisioncardimage" in card :
72
+ if card["revisioncardimage"] != [] :
73
+ self.sendimagecard(user,card)
74
+
75
+ print("Card sent.")
76
+ trafficlightemailsleft -= 1
77
+ elif card["revisioncardimage"] == []:
78
+ #print("hi")
79
+ self.sendtextcard(user,card)
80
+ print("Card sent.")
81
+ trafficlightemailsleft -= 1
82
+
83
+ elif "revisioncardimage" not in card:
84
+ self.sendtextcard(user,card)
85
+ print("Card sent.")
86
+ trafficlightemailsleft -= 1
87
+ #elif
88
+ #print(revisioncards)
89
+ #print(weights)
90
+
91
+ #if len(revisioncards) < 3:
92
+ try:
93
+ # Makes sure that no duplicates are sent. Whilst also picking each card randomly with red
94
+ duplicates = True
95
+
96
+ while duplicates == True:
97
+ trafficlightemails = random.choices(revisioncards, weights=weights, k=trafficlightemailsleft)
98
+ #print(len(trafficlightemails))
99
+ if trafficlightemails != []:
100
+ original = list(map(lambda x:x["revisioncard"],trafficlightemails))
101
+ duplicateset = set(original)
102
+ #print(len(original),len(duplicateset))
103
+ #print(original,duplicateset)
104
+ if len(duplicateset) < len(original):
105
+ trafficlightemails = random.choices(revisioncards, weights=weights, k=trafficlightemailsleft)
106
+ trafficlightemailsleft -= 1
107
+ #duplicates = False
108
+ if len(duplicateset) == len(original):
109
+ duplicates = False
110
+ elif trafficlightemails == []:
111
+ duplicates = False
112
+
113
+ #print(trafficlightemailsleft)
114
+
115
+
116
+ for card in trafficlightemails:
117
+ #user["revisionscheduleinterval"]
118
+ print("Sending traffic light revision card...")
119
+ #time.sleep(10)
120
+ ##192.168.0.180
121
+ if "revisioncardimage" in card:
122
+ #print([{card["revisioncardimgname"][0]:card["revisioncardimage"][0]}])
123
+ imagecardjson = {"email":user["sendtoemail"],"message":f"{card['revisioncardtitle']}\n{card['revisioncard']}","subject":card["subject"],"attachment":[{card["revisioncardimgname"][0]:card["revisioncardimage"][0]}]}
124
+ RaspEmail.send(receiver_email = imagecardjson["email"],subject = imagecardjson["subject"],htmlmessage = imagecardjson["message"],attachment = imagecardjson["attachment"])
125
+
126
+ #response = requests.post("https://revisionbank-email.onrender.com/raspsendemail",json={"raspsendemail":{"email":user["sendtoemail"],"message":f"{card['revisioncardtitle']}\n{card['revisioncard']}","subject":card["subject"],"attachment":[{card["revisioncardimgname"][0]:card["revisioncardimage"][0]}]}})
127
+ #sendgrid_send(user["sendtoemail"],f"{card['revisioncardtitle']}\n{card['revisioncard']}",card["subject"])
128
+ print("Traffic light card sent.")
129
+ elif "revisioncardimage" not in card:
130
+ #response = requests.post("https://revisionbank-email.onrender.com/raspsendemail",json={"raspsendemail":{"email":user["sendtoemail"],"message":f"{card['revisioncardtitle']}\n{card['revisioncard']}","subject":card["subject"]}})
131
+ textcardjson = {"email":user["sendtoemail"],"message":f"{card['revisioncardtitle']}\n{card['revisioncard']}","subject":card["subject"]}
132
+ RaspEmail.send(receiver_email = textcardjson["email"],subject = textcardjson["subject"],htmlmessage = textcardjson["message"],attachment = textcardjson["attachment"])
133
+
134
+ #sendgrid_send(user["sendtoemail"],f"{card['revisioncardtitle']}\n{card['revisioncard']}",card["subject"])
135
+ print("Traffic light card sent.")
136
+ except IndexError as ex:
137
+ #print(type(ex),ex)
138
+ continue
revisionbankunit.py ADDED
@@ -0,0 +1,22 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import requests
2
+ import unittest
3
+ uri = "http://0.0.0.0:7860"
4
+ #uri = "http://192.168.0.10:5000"
5
+ class RevisionBankAuth(unittest.TestCase):
6
+ def signup(self):
7
+ response = requests.post(f"{uri}/signupapi",json={"email":"[email protected]","password":"kya63amari"})
8
+ print(response.json())
9
+ def signin(self):
10
+ response = requests.post(f"{uri}/loginapi",json={"email":"[email protected]","password":"kya63amari"})
11
+ print(response.json())
12
+ def checkgeneric(self):
13
+ response = requests.post(f"{uri}/forgotpassword",json={"email":"[email protected]","password":"kya63amari"})
14
+ print(response.json())
15
+
16
+
17
+
18
+
19
+
20
+
21
+ if __name__ == "__main__":
22
+ unittest.main()
runtime.txt ADDED
@@ -0,0 +1 @@
 
 
1
+ python-3.10.5
secrets.md ADDED
@@ -0,0 +1 @@
 
 
1
+ MAIL_PASSWORD = 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
storerevisioncards.py ADDED
@@ -0,0 +1,74 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from csv_to_db import ImportCSV
2
+ import os
3
+ importcsv = ImportCSV("RevisionBankDB")
4
+ importcsvqp = ImportCSV("RevisionBankDB",maindb= False)
5
+ """
6
+ if __name__ == '__main__':
7
+ try:
8
+ edexcelpapers = list(importcsv.db.edexcelpapers.find()[:2])
9
+ print(edexcelpapers)
10
+ #del edexcelpapers["_id"]
11
+ #print({"edexcelpaper":edexcelpapers}
12
+ except Exception as e:
13
+ print({f"error":f"{type(e)},{str(e)}"})
14
+ """
15
+
16
+ def insert_cards(revision_cards):
17
+ try:
18
+ data = {"email":"[email protected]","revisioncards":revision_cards}
19
+ email_exists = importcsv.db.accountrevisioncards.find_one({"email":"[email protected]"})
20
+ if email_exists: # Checks if email exists
21
+ cards_not_exist = []
22
+ user_revision_cards = list(importcsv.db.accountrevisioncards.find({"email": "[email protected]"}))[0] # Gets the email.
23
+
24
+ #print(user_revision_cards)
25
+ for card in data["revisioncards"]: # Checks if the revision card exists in the database.
26
+ if card not in user_revision_cards["revisioncards"]:
27
+ cards_not_exist.append(card) # If not, add it to the list.
28
+ #cards_that_exist.append(card)
29
+ if cards_not_exist != []:
30
+ new_cards = cards_not_exist + user_revision_cards["revisioncards"] # adds new cards to the list.
31
+ user_revision_cards["revisioncards"] = new_cards # Updates the list.
32
+ del user_revision_cards["_id"]
33
+ user_revision_cards["email"] = "[email protected]" # Sets the email to the current user.
34
+ importcsv.db.accountrevisioncards.delete_many({"email":"[email protected]"}) # Allows data to be updated.
35
+ importcsv.db.accountrevisioncards.insert_one(user_revision_cards) # Inserts the new data.
36
+ print({"message":"revision cards updated"})
37
+ elif cards_not_exist == []: # If the cards are already in the database, print(a message.
38
+ print({"message":"No new cards"})
39
+
40
+ elif not email_exists:
41
+ data["email"] = "[email protected]"
42
+ importcsv.db.accountrevisioncards.insert_one(data)
43
+
44
+ print({"message": "revision card stored"})
45
+ except Exception as ex:
46
+ print(type(ex),ex)
47
+
48
+ def load_cards(dir, subject):
49
+ chapter_revision_cards = []
50
+ chapters = os.listdir(dir)
51
+ for chapter in chapters:
52
+ cards = os.listdir(f"{dir}/{chapter}")
53
+ for card in cards:
54
+ if card.endswith(".txt"):
55
+ with open(f"{dir}/{chapter}/{card}", "r", encoding="utf8") as f:
56
+ cardjson = {"subject":f"AS Level {subject.capitalize()}","revisioncardtitle":chapter,"revisioncard":f.read()}
57
+ chapter_revision_cards.append(cardjson)
58
+
59
+ return chapter_revision_cards
60
+ if __name__ == "__main__":
61
+ physicsdir = f"C:/Users/user1/Desktop/RevisionBank/RevisionBank Scheduler/AS Level Card Sender/physicscards"
62
+ computersciencedir = f"C:/Users/user1/Desktop/RevisionBank/RevisionBank Scheduler/AS Level Card Sender/computersciencecards"
63
+
64
+
65
+
66
+ if __name__ == "__main__":
67
+ #revisioncards = load_cards(physicsdir,"physics")
68
+ #insert_cards(revisioncards)
69
+ #print(revisioncards[0])
70
+ revisioncardscmp = load_cards(computersciencedir,"computer science")
71
+ insert_cards(revisioncardscmp)
72
+ #print(revisioncardscmp[0])
73
+ #load_cards(computersciencedir,"computer science")
74
+
stripetest.py ADDED
@@ -0,0 +1,17 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import requests
2
+ import requests
3
+ resptoken = requests.post("https://revisionbankapi.herokuapp.com/loginapi",json={"email":"[email protected]","password":"kya63amari"})
4
+ print()
5
+ 'headers:'
6
+ config = {'headers:{Authorization: Bearer {}'.format(resptoken.json()["access_token"])}
7
+ resptoken = requests.post("https://revisionbankapi.herokuapp.com/revisionbankstripepayment",json={"price"},headers=
8
+ #import stripe
9
+ #stripe.api_key = "sk_test_51La4WnLpfbhhIhYRjP1w036wUwBoatAgqNRYEoj9u6jMd7GvSmBioKgmwJsabjgAY8V5W8i2r3QdelOPe5VNOueB00zDxeXtDQ"#
10
+ #
11
+ #striperesponse = stripe.PaymentIntent.create(
12
+ # amount=2000,
13
+ # currency="gbp",
14
+ # payment_method_types=["card"],
15
+ #)
16
+ #clientsecret= striperesponse["client_secret"]
17
+