From a4f7902b55b7143bf0194202dd63e624f867e7fc Mon Sep 17 00:00:00 2001 From: AhmedElsayed101 Date: Mon, 11 May 2020 23:05:28 +0200 Subject: [PATCH 1/6] creating account confirmation routes --- ayat/account_activation_routes.py | 72 +++++++++++++++++++++++++++++++ ayat/authentication_routes.py | 21 ++++----- docs/users.md | 2 +- run.py | 2 +- 4 files changed, 85 insertions(+), 12 deletions(-) create mode 100644 ayat/account_activation_routes.py diff --git a/ayat/account_activation_routes.py b/ayat/account_activation_routes.py new file mode 100644 index 0000000..c076e73 --- /dev/null +++ b/ayat/account_activation_routes.py @@ -0,0 +1,72 @@ +from flask import Flask, request, jsonify, url_for +from werkzeug.security import generate_password_hash, check_password_hash +import jwt +from flask_cors import cross_origin + +from functools import wraps +from ayat.models.users import * +from ayat import app, db + +from ayat.helpers import send_message +from itsdangerous import URLSafeTimedSerializer, SignatureExpired, BadTimeSignature + +import os +import logging + +from ayat import mail +from flask_mail import Message + + + + + +serializer = URLSafeTimedSerializer("thisissecret") + +@app.route("/v1/users//confirm",methods=['POST','GET']) +@cross_origin() +def confirm_email(public_id): + + data = request.get_json(force=True) + + current_user = User.query.filter_by(public_id=public_id ).first() + if request.method == "POST": + current_user_email = data["email"] + user_email_check = User.query.filter_by(email= current_user_email ).first() + if user_email_check is not None and str(current_user.email) != str(user_email_check.email): + return jsonify({"status":"email exists"}) + + user_email = current_user.email + token_email = serializer.dumps(user_email, salt= "email_confirm") + confirmation_link = url_for('confirm_email_token', token = token_email, public_id = public_id, _external = True) + content = f"Welcome to ayat. \n This is the link to confirm your email which will expire in two hours. \n link : \n {confirmation_link}" + msg = Message("Ayat Email Confirmation",sender="ayatquraancenter@gmail.com",recipients=user_email.split()) + msg.body = content + mail.send(msg) + # send_message(subject="Ayat Email Confirmation",recipients= user_email,content= content,html_content= "

hello

", resource="hello.jpg",resource_type= "jpg") + + + return jsonify({"message":"sent"}) + + + + + + + +@app.route("/v1/users//confirm/",methods=['POST','GET']) +@cross_origin() +def confirm_email_token(token, public_id): + + twoHours = 60*60*2 + + try: + email = serializer.loads(token, salt= "email_confirm", max_age= twoHours) + + except SignatureExpired: + return jsonify({"message":"token has expired"}),401 + + except BadTimeSignature: + + return jsonify({"message":"token is damaged"}),401 + + return jsonify({"message":"confirmed"}),200 diff --git a/ayat/authentication_routes.py b/ayat/authentication_routes.py index 1216f28..f81689c 100644 --- a/ayat/authentication_routes.py +++ b/ayat/authentication_routes.py @@ -196,15 +196,9 @@ def delete_user(current_user, public_id): @cross_origin() def login_or_create(): data = request.get_json(force=True) - print(data) + # login checking - print('this is request') - print(request) - print('this is data') - print(data) - # if not data['action'] : - # return jsonify({"error": "user is unauthorized"}), 403 - + if data['action'] == 'login': user_email = data['email'] @@ -280,8 +274,14 @@ def login_or_create(): new_user.guardians.append(new_guardian) db.session.add(new_user) db.session.commit() + + ############### + + + logger.info('user succeeded to register') - return jsonify({'status': 'created'}), 200 + return jsonify({'status': 'created', + 'public_id': new_user.public_id,}), 200 if data['action'] == 'register_staff': @@ -320,4 +320,5 @@ def login_or_create(): db.session.add(new_user) db.session.commit() logger.info('user succeeded to register') - return jsonify({'status': 'created'}), 200 + return jsonify({'status': 'created', + 'public_id': new_user.public_id,}), 200 diff --git a/docs/users.md b/docs/users.md index 98e7b0b..fb1e76b 100644 --- a/docs/users.md +++ b/docs/users.md @@ -191,7 +191,7 @@ code: **`404`** "phone": 123, "profile_pic": "2d", "birth_date": "2015-05-16", - "gender": false, + "gender": false, "password": "464468", "registeration_date": "2015-05-16" } diff --git a/run.py b/run.py index 8d06ff2..487fefe 100644 --- a/run.py +++ b/run.py @@ -1,7 +1,7 @@ from ayat import app from ayat.authentication_routes import * from ayat.programs_routes import * - +from ayat.account_activation_routes import * if __name__ == '__main__': app.run(debug=True) \ No newline at end of file From 032f42553fdb6fb76cab1a06be939d017b1562ef Mon Sep 17 00:00:00 2001 From: AhmedElsayed101 Date: Mon, 11 May 2020 23:50:29 +0200 Subject: [PATCH 2/6] completing programs --- ayat/programs_routes.py | 65 +++++++++++++++++++++++++++++------------ 1 file changed, 46 insertions(+), 19 deletions(-) diff --git a/ayat/programs_routes.py b/ayat/programs_routes.py index 941e01a..ceb86d3 100644 --- a/ayat/programs_routes.py +++ b/ayat/programs_routes.py @@ -12,7 +12,8 @@ logger = logging.getLogger(__name__) logger.setLevel(logging.DEBUG) -formatter = logging.Formatter('%(asctime)s : %(name)s : %(levelname)s : %(message)s') +formatter = logging.Formatter( + '%(asctime)s : %(name)s : %(levelname)s : %(message)s') file_handler = logging.FileHandler('logging.log') file_handler.setFormatter(formatter) logger.addHandler(file_handler) @@ -35,24 +36,36 @@ def create_program(current_user): difficulty_level=data['program_level'], price=data['price'], program_picture=data['program_pic'], + is_open_to_public=data['is_open_to_public'], #new program_cover=data['program_cover'], program_description=data['Program_description'], available=data['available'], - is_open_to_public=True, - start_date='2015-05-16', - end_date='2015-05-16', - requirement_id=1, + start_date=data['start_date'], #new + end_date=data['end_date'], #new + requirement_id = 1 # dumy code + # ###### ) # db.session.add(new_program) + #new + new_requirement = Requirement( + + min_age=data['requirement_min_age'], + max_age=data['requirement_max_age'], + gender=data['requirement_gender'], + ) + db.session.add(new_requirement) + new_program.requirement.append(new_requirement) + new_program_prerequisites = data['prerequisite'] for prerequisite in new_program_prerequisites: - new_program_prerequisite = Program.query.filter_by(program_name=prerequisite['name']).first() + new_program_prerequisite = Program.query.filter_by( + program_name=prerequisite['name']).first() if new_program_prerequisite: new_program.prerequisites.append(new_program_prerequisite) @@ -60,7 +73,8 @@ def create_program(current_user): for category in new_program_categories: - existing_category = Category.query.filter_by(category_name=category['type']).first() + existing_category = Category.query.filter_by( + category_name=category['type']).first() if not existing_category: print('not exist') @@ -96,7 +110,11 @@ def edit_program(current_user, public_id): data = request.get_json() - current_program = Program.query.filter_by(public_program_id=str(public_id)).first() + current_program = Program.query.filter_by( + public_program_id=str(public_id)).first() + + if not current_program: + return jsonify({"status": "program not found"}), 404 current_program.program_name = data['program_name'] current_program.difficulty_level = data['program_level'] @@ -113,14 +131,16 @@ def edit_program(current_user, public_id): prerequisites = data['prerequisite'] for prerequisite in prerequisites: - current_program_prerequisite = Program.query.filter_by(program_name=prerequisite['name']).first() + current_program_prerequisite = Program.query.filter_by( + program_name=prerequisite['name']).first() if current_program_prerequisite: current_program.prerequisites.append(current_program_prerequisite) current_program_categories = data['program_category'] for category in current_program_categories: - existing_category = Category.query.filter_by(category_name=category['type']).first() + existing_category = Category.query.filter_by( + category_name=category['type']).first() if not existing_category: print('not exist') @@ -146,13 +166,14 @@ def edit_program(current_user, public_id): @app.route('/v1/programs/', methods=['GET']) @cross_origin() def retrieve_program(public_id): - current_program = Program.query.filter_by(public_program_id=public_id).first() + current_program = Program.query.filter_by( + public_program_id=public_id).first() if not current_program: logger.warning("content isn't found") return jsonify({'status': "content not found"}), 404 - #### ?????? + # ?????? prerequisites = current_program.prerequisites prerequisite_list = [] for prerequisite in prerequisites: @@ -193,11 +214,13 @@ def delete_program(current_user, public_id): logger.warning("user hasn't have permission") return jsonify({"status": "forbidden"}), 403 - current_program = Program.query.filter_by(public_program_id=public_id).first() + current_program = Program.query.filter_by( + public_program_id=public_id).first() if current_program is None: - return jsonify({"status": "program not found"}), 403 + return jsonify({"status": "program not found"}), 404 - program_to_delete = Program.query.filter_by(public_program_id=public_id).first() + program_to_delete = Program.query.filter_by( + public_program_id=public_id).first() db.session.delete(program_to_delete) db.session.commit() @@ -212,8 +235,10 @@ def subscribe_to_program(current_user, public_program_id): if current_user['type'] == 'staff': return jsonify({"status": "you are a staff member"}), 403 - selected_user = User.query.filter_by(public_id=current_user['public_id']).first() - current_program = Program.query.filter_by(public_program_id=public_program_id).first() + selected_user = User.query.filter_by( + public_id=current_user['public_id']).first() + current_program = Program.query.filter_by( + public_program_id=public_program_id).first() enrolled = ProgramEnrollment.query.filter_by(program_id=current_program.program_id, student_id=selected_user.user_id @@ -238,8 +263,10 @@ def subscribe_to_program(current_user, public_program_id): @cross_origin() @token_required def delete_program_enrollment(current_user, public_program_id): - selected_user = User.query.filter_by(public_id=current_user['public_id']).first() - current_program = Program.query.filter_by(public_program_id=public_program_id).first() + selected_user = User.query.filter_by( + public_id=current_user['public_id']).first() + current_program = Program.query.filter_by( + public_program_id=public_program_id).first() enrolled = ProgramEnrollment.query.filter_by(program_id=current_program.program_id, student_id=selected_user.user_id From 6998c67b86cecde92b0a0a70bfc2b6dd46d9386c Mon Sep 17 00:00:00 2001 From: AhmedElsayed101 Date: Wed, 13 May 2020 20:01:16 +0200 Subject: [PATCH 3/6] adding get all programs route --- ayat/authentication_routes.py | 6 +- ayat/models/programs.py | 6 +- ayat/programs_routes.py | 222 +++++++++++++++++++++++++++++----- docs/programs.md | 158 ++++++++++++++++++------ docs/users.md | 3 +- 5 files changed, 322 insertions(+), 73 deletions(-) diff --git a/ayat/authentication_routes.py b/ayat/authentication_routes.py index 1216f28..0189f7e 100644 --- a/ayat/authentication_routes.py +++ b/ayat/authentication_routes.py @@ -281,7 +281,8 @@ def login_or_create(): db.session.add(new_user) db.session.commit() logger.info('user succeeded to register') - return jsonify({'status': 'created'}), 200 + return jsonify({'status': 'created', + "public_id" : new_user.public_id}), 200 if data['action'] == 'register_staff': @@ -320,4 +321,5 @@ def login_or_create(): db.session.add(new_user) db.session.commit() logger.info('user succeeded to register') - return jsonify({'status': 'created'}), 200 + return jsonify({'status': 'created', + "public_id" : new_user.public_id}), 200 diff --git a/ayat/models/programs.py b/ayat/models/programs.py index e684ad6..430dc17 100644 --- a/ayat/models/programs.py +++ b/ayat/models/programs.py @@ -41,7 +41,7 @@ class Program(db.Model): available = db.Column(db.Boolean, nullable=False) start_date = db.Column(db.Date, nullable=False) end_date = db.Column(db.Date, nullable=False) - requirement_id = db.Column(db.SMALLINT, db.ForeignKey("requirement.requirement_id"), nullable=False) + requirement_id = db.Column(db.SMALLINT, db.ForeignKey("requirement.requirement_id")) skills = db.relationship('Skill', secondary=program_skill, backref=db.backref('program', lazy='dynamic')) faqs = db.relationship('Faq', secondary=program_faqs, backref=db.backref('program', lazy='dynamic')) category = db.relationship('Category', secondary=program_category, backref=db.backref('program', lazy='dynamic')) @@ -149,7 +149,7 @@ class Requirement(db.Model): requirement_id = db.Column(db.SMALLINT, primary_key=True) min_age = db.Column(db.SMALLINT, nullable=False) max_age = db.Column(db.SMALLINT, nullable=False) - gender = db.Column(db.VARCHAR(60), nullable=False) + gender = db.Column(db.Boolean, nullable=False) def __repr__(self): info_text = (f'requirement id: {self.requirement_id}.\t' @@ -158,7 +158,7 @@ def __repr__(self): f'gender: {self.gender}.\n') return info_text - + class Category(db.Model): __tablename__ = "category" category_id = db.Column(db.SMALLINT, primary_key=True) diff --git a/ayat/programs_routes.py b/ayat/programs_routes.py index ceb86d3..5f55f97 100644 --- a/ayat/programs_routes.py +++ b/ayat/programs_routes.py @@ -27,8 +27,31 @@ def create_program(current_user): logger.warning("user hasn't have permission") return jsonify({"status": "forbidden"}), 403 - data = request.get_json() + ##################################### + data = request.get_json() + # to create uniqe requirements + requirement = data['requirement'] + min_age_requirement_check = Requirement.query.filter_by( + min_age=requirement['min_age']).first() + max_age_requirement_check = Requirement.query.filter_by( + max_age=requirement['max_age']).first() + gender_requirement_check = Requirement.query.filter_by( + gender=requirement['gender']).first() + + if (not min_age_requirement_check) or (not max_age_requirement_check) or (not gender_requirement_check): + new_requirement = Requirement( + + min_age=requirement['min_age'], + max_age=requirement['max_age'], + gender=requirement['gender'], + ) + db.session.add(new_requirement) + requirement_to_add = new_requirement + else: + requirement_to_add = min_age_requirement_check + + # creating new program new_program = Program( public_program_id=str(uuid.uuid4()), @@ -36,13 +59,14 @@ def create_program(current_user): difficulty_level=data['program_level'], price=data['price'], program_picture=data['program_pic'], - is_open_to_public=data['is_open_to_public'], #new + is_open_to_public=data['is_open_to_public'], # new program_cover=data['program_cover'], program_description=data['Program_description'], available=data['available'], - start_date=data['start_date'], #new - end_date=data['end_date'], #new - requirement_id = 1 # dumy code + start_date=data['start_date'], # new + end_date=data['end_date'], # new + # requirement_id = 1, + requirement=requirement_to_add # new # ###### @@ -50,25 +74,23 @@ def create_program(current_user): # db.session.add(new_program) - #new - new_requirement = Requirement( + # new - min_age=data['requirement_min_age'], - max_age=data['requirement_max_age'], - gender=data['requirement_gender'], - ) - db.session.add(new_requirement) - new_program.requirement.append(new_requirement) + # new_program.requirement.append(new_requirement) + # creating new prerequisites new_program_prerequisites = data['prerequisite'] for prerequisite in new_program_prerequisites: - - new_program_prerequisite = Program.query.filter_by( - program_name=prerequisite['name']).first() - if new_program_prerequisite: - new_program.prerequisites.append(new_program_prerequisite) - + try: + new_program_prerequisite = Program.query.filter_by( + public_program_id=prerequisite['public_program_id'], ).first() + if new_program_prerequisite: + new_program.prerequisites.append(new_program_prerequisite) + except: + return jsonify({"error": "not a valid requirement public_id "}),404 + + # creating new categories new_program_categories = data['program_category'] for category in new_program_categories: @@ -84,6 +106,7 @@ def create_program(current_user): else: new_program.category.append(existing_category) + # creating new faqs new_program_faqs = data['FAQ'] for faq in new_program_faqs: @@ -91,6 +114,21 @@ def create_program(current_user): db.session.add(new_faq) new_program.faqs.append(new_faq) + # creating new skill + new_program_skills = data['skills'] # new + for skill in new_program_skills: + existing_skill = Skill.query.filter_by( + skill_name=skill['name']).first() + + if not existing_skill: + print('not exist') + new_skill = Skill(skill_name=skill['name']) + db.session.add(new_skill) + new_program.skills.append(new_skill) + else: + new_program.skills.append(existing_skill) + + # submiting program db.session.add(new_program) db.session.commit() @@ -110,12 +148,36 @@ def edit_program(current_user, public_id): data = request.get_json() + # checking if program exists or not current_program = Program.query.filter_by( public_program_id=str(public_id)).first() if not current_program: return jsonify({"status": "program not found"}), 404 + ####################################### + + # update requirement + requirement = data['requirement'] + min_age_requirement_check = Requirement.query.filter_by( + min_age=requirement['min_age']).first() + max_age_requirement_check = Requirement.query.filter_by( + max_age=requirement['max_age']).first() + gender_requirement_check = Requirement.query.filter_by( + gender=requirement['gender']).first() + + if (not min_age_requirement_check) or (not max_age_requirement_check) or (not gender_requirement_check): + new_requirement = Requirement( + + min_age=requirement['min_age'], + max_age=requirement['max_age'], + gender=requirement['gender'], + ) + db.session.add(new_requirement) + requirement_to_add = new_requirement + else: + requirement_to_add = min_age_requirement_check + # updating program current_program.program_name = data['program_name'] current_program.difficulty_level = data['program_level'] current_program.price = data['price'] @@ -123,19 +185,23 @@ def edit_program(current_user, public_id): current_program.program_cover = data['program_cover'] current_program.program_description = data['Program_description'] current_program.available = data['available'] - current_program.is_open_to_public = True - current_program.start_date = '2015-05-16' - current_program.end_date = '2015-05-16' - current_program.requirement_id = 1 + current_program.is_open_to_public = data['is_open_to_public'] + current_program.start_date = data['start_date'] + current_program.end_date = data['end_date'] + current_program.requirement = requirement_to_add # ###### + # updating prerequisites + current_program.prerequisites = [] prerequisites = data['prerequisite'] for prerequisite in prerequisites: current_program_prerequisite = Program.query.filter_by( - program_name=prerequisite['name']).first() + public_program_id=prerequisite['public_program_id']).first() if current_program_prerequisite: current_program.prerequisites.append(current_program_prerequisite) + # updating categories + current_program.category = [] current_program_categories = data['program_category'] for category in current_program_categories: @@ -149,13 +215,28 @@ def edit_program(current_user, public_id): current_program.category.append(new_category) else: current_program.category.append(existing_category) - + # adding faqs current_program_faqs = data['FAQ'] for faq in current_program_faqs: current_faq = Faq(question=faq['question'], answer=faq['answer']) db.session.add(current_faq) current_program.faqs.append(current_faq) + # updating skills + current_program.skills = [] + current_program_skills = data['skills'] # new + for skill in current_program_skills: + existing_skill = Skill.query.filter_by( + skill_name=skill['name']).first() + + if not existing_skill: + print('not exist') + new_skill = Skill(skill_name=skill['name']) + db.session.add(new_skill) + current_program.skills.append(new_skill) + else: + current_program.skills.append(existing_skill) + db.session.add(current_program) db.session.commit() @@ -177,7 +258,8 @@ def retrieve_program(public_id): prerequisites = current_program.prerequisites prerequisite_list = [] for prerequisite in prerequisites: - prerequisite_list.append({"name": prerequisite.program_name}) + prerequisite_list.append( + {"public_program_id": prerequisite.public_program_id}) program_categories = current_program.category category_list = [] @@ -189,23 +271,105 @@ def retrieve_program(public_id): for faq in program_faqs: faqs_list.append({"question": faq.question, "answer": faq.answer}) + program_skills = current_program.skills + skills_list = [] + for skill in program_skills: + skills_list.append({"name": skill.skill_name}) + + program_requirement = current_program.requirement + requirement_object = {"requirement": { + "min_age": program_requirement.min_age, + "max_age": program_requirement.max_age, + "gender": program_requirement.gender + } + } + logger.info("program is successfully retrieved") return jsonify({ + 'public_program_id': current_program.public_program_id, 'program_name': current_program.program_name, - 'prerequisite': prerequisite_list, 'program_level': current_program.difficulty_level, - 'program_category': category_list, 'price': str(current_program.price), 'program_pic': current_program.program_picture, - 'FAQ': faqs_list, + 'is_open_to_public': current_program.is_open_to_public, 'program_cover': current_program.program_cover, 'Program_description': current_program.program_description, 'available': current_program.available, + 'start_date': current_program.start_date, + 'end_date': current_program.end_date, + 'skills': skills_list, + 'FAQ': faqs_list, + 'program_category': category_list, + 'requirement': requirement_object, + 'prerequisite': prerequisite_list, }), 200 +@app.route('/v1/programs', methods=['GET']) +@cross_origin() +def retrieve_all_programs(): + + # + query_list = Program.query.all() + + program_list = [] + for current_program in query_list: + # prerequisites = current_program.prerequisites + # prerequisite_list = [] + # for prerequisite in prerequisites: + # prerequisite_list.append({"name": prerequisite.program_name}) + + program_categories = current_program.category + category_list = [] + for category in program_categories: + category_list.append({"type": category.category_name}) + + # program_faqs = current_program.faqs + # faqs_list = [] + # for faq in program_faqs: + # faqs_list.append({"question": faq.question, "answer": faq.answer}) + + # program_skills = current_program.skills + # skills_list = [] + # for skill in program_skills: + # skills_list.append({"name": skill.skill_name}) + + # program_requirement = current_program.requirement + # requirement_object = {"requirement": { + # "min_age": program_requirement.min_age, + # "max_age": program_requirement.max_age, + # "gender": program_requirement.gender + # } + # } + + logger.info("program is successfully retrieved") + program_to_append = { + + 'public_program_id': current_program.public_program_id, + 'program_name': current_program.program_name, + 'program_level': current_program.difficulty_level, + 'price': str(current_program.price), + 'program_pic': current_program.program_picture, + 'is_open_to_public': current_program.is_open_to_public, + 'program_cover': current_program.program_cover, + 'Program_description': current_program.program_description, + 'available': current_program.available, + 'start_date': current_program.start_date, + 'end_date': current_program.end_date, + # 'skills': skills_list, + # 'FAQ': faqs_list, + 'program_category': category_list, + # 'requirement': requirement_object, + # 'prerequisite': prerequisite_list, + + } + program_list.append(program_to_append) + logger.info("all programs are successfully retrieved") + return jsonify({'programs': program_list}), 200 + + @app.route('/v1/programs/', methods=['DELETE']) @cross_origin() @token_required diff --git a/docs/programs.md b/docs/programs.md index 0add27a..e82e4da 100644 --- a/docs/programs.md +++ b/docs/programs.md @@ -19,20 +19,20 @@ "prerequisite": [ { - "name": "name of already exist program" + "public_program_id": "e885f927-2b95-4a27-b1c4-223d21f429d0" }, { - "name": "name of already exist program" + "public_program_id": "e885f927-2b95-4a27-b1c4-223d21f429d0" } ], "program_level": "", "program_category": [ { - "type": "text" + "type": "tessxt" }, { - "type": "text" + "type": "tesss2xt" } ], @@ -55,11 +55,22 @@ "Program_description": "text example", - "available": true + "available": true, + "is_open_to_public": true, + "start_date" : "2015-05-05", + "end_date" : "2015-05-05", + "requirement":{ + "min_age": 5, + "max_age": 20, + "gender" : false}, + + "skills":[ + {"name" : "sdf"}, + {"name":"hello"} + ] } - ``` ##### Success response: @@ -92,7 +103,6 @@ ##### Payload ```json - { "x-access-token": "fg5562ase84c4", @@ -100,20 +110,20 @@ "prerequisite": [ { - "name": "name of already exist program" + "public_program_id": "e885f927-2b95-4a27-b1c4-223d21f429d0" }, { - "name": "name of already exist program" + "public_program_id": "e885f927-2b95-4a27-b1c4-223d21f429d0" } ], "program_level": "", "program_category": [ { - "type": "text" + "type": "tessxt" }, { - "type": "text" + "type": "tesss2xt" } ], @@ -136,11 +146,22 @@ "Program_description": "text example", - "available": true + "available": true, + "is_open_to_public": true, + "start_date" : "2015-05-05", + "end_date" : "2015-05-05", + "requirement":{ + "min_age": 5, + "max_age": 20, + "gender" : false}, + + "skills":[ + {"name" : "sdf"}, + {"name":"hello"} + ] } - ``` #### Success responce: @@ -181,47 +202,54 @@ code: **`200`** ```json { - "program_name": "name example", - - "prerequisite": [ + "FAQ": [ { - "type": "example" + "answer": "Text", + "question": "Text" }, { - "type": "example" + "answer": "Text", + "question": "Text" } ], - "program_level": "", - + "Program_description": "text example", + "available": true, + "end_date": "Tue, 05 May 2015 00:00:00 GMT", + "is_open_to_public": true, + "prerequisite": [ + {"public_program_id":"public_program_id example"}, + {"public_program_id":"public_program_id example"} + ], + "price": "551", "program_category": [ { - "type": "example" + "type": "tessxt" }, { - "type": "example" + "type": "tesss2xt" } ], - - "price": "$$$", - - "program_pic": "", - - "FAQ": [ + "program_cover": "", + "program_level": "", + "program_name": "", + "program_pic": "", + "public_program_id": "c8a3608e-bf88-489a-ae63-4e849330d5d6", + "requirement": { + "requirement": { + "gender": false, + "max_age": 20, + "min_age": 5 + } + }, + "skills": [ { - "question": "Text", - "answer": "Text" + "name": "sdf" }, { - "question": "Text", - "answer": "Text" + "name": "hello" } ], - - "program_cover": "", - - "Program_description": "text example", - - "available": "" + "start_date": "Tue, 05 May 2015 00:00:00 GMT" } ``` @@ -237,6 +265,60 @@ code: **`200`**
+### Get all programs + +`api.ayat.com/v1/programs` **`GET`** + +```json + +{ + "programs": [ + { + "Program_description": "text example", + "available": true, + "end_date": "Tue, 05 May 2015 00:00:00 GMT", + "is_open_to_public": true, + "price": "551", + "program_category": [ + { + "type": "tessxt" + }, + { + "type": "tesss2xt" + } + ], + "program_cover": "", + "program_level": "", + "program_name": "", + "program_pic": "", + "public_program_id": "62eb63f1-e4d9-41b8-a1dd-fc6ecbee9807", + "start_date": "Tue, 05 May 2015 00:00:00 GMT" + }, + { + "Program_description": "text example", + "available": true, + "end_date": "Tue, 05 May 2015 00:00:00 GMT", + "is_open_to_public": true, + "price": "551", + "program_category": [ + { + "type": "tessxt" + }, + { + "type": "tesss2xt" + } + ], + "program_cover": "", + "program_level": "", + "program_name": "", + "program_pic": "", + "public_program_id": "c8a3608e-bf88-489a-ae63-4e849330d5d6", + "start_date": "Tue, 05 May 2015 00:00:00 GMT" + } + + +``` + #### Delete a program `api.ayat.com/v1/programs/{id}` **`DELETE`** diff --git a/docs/users.md b/docs/users.md index 98e7b0b..b86990c 100644 --- a/docs/users.md +++ b/docs/users.md @@ -219,7 +219,8 @@ code : **`200`** ```Json { - "status": "created" + "status": "created", + "public_id": "example" } ``` From d11c5d5ae18490a85d3c80fb382c00865a172317 Mon Sep 17 00:00:00 2001 From: AhmedElsayed101 Date: Wed, 13 May 2020 20:11:15 +0200 Subject: [PATCH 4/6] creating account activation routes --- ayat/account_activation_routes.py | 13 ++++++++----- ayat/authentication_routes.py | 26 +++++++++++++++++++++++++- 2 files changed, 33 insertions(+), 6 deletions(-) diff --git a/ayat/account_activation_routes.py b/ayat/account_activation_routes.py index c076e73..2be5b55 100644 --- a/ayat/account_activation_routes.py +++ b/ayat/account_activation_routes.py @@ -29,11 +29,11 @@ def confirm_email(public_id): data = request.get_json(force=True) current_user = User.query.filter_by(public_id=public_id ).first() - if request.method == "POST": - current_user_email = data["email"] - user_email_check = User.query.filter_by(email= current_user_email ).first() - if user_email_check is not None and str(current_user.email) != str(user_email_check.email): - return jsonify({"status":"email exists"}) + # if request.method == "POST": + # current_user_email = data["email"] + # user_email_check = User.query.filter_by(email= current_user_email ).first() + # if user_email_check is not None and str(current_user.email) != str(user_email_check.email): + # return jsonify({"status":"email exists"}) user_email = current_user.email token_email = serializer.dumps(user_email, salt= "email_confirm") @@ -61,6 +61,9 @@ def confirm_email_token(token, public_id): try: email = serializer.loads(token, salt= "email_confirm", max_age= twoHours) + user_to_activate = User.query.filter_by(public_id = public_id).first() + user_to_activate.is_activated = True + db.session.commit() except SignatureExpired: return jsonify({"message":"token has expired"}),401 diff --git a/ayat/authentication_routes.py b/ayat/authentication_routes.py index f81689c..acfcc9f 100644 --- a/ayat/authentication_routes.py +++ b/ayat/authentication_routes.py @@ -1,4 +1,4 @@ -from flask import Flask, request, jsonify, make_response +from flask import Flask, request, jsonify, url_for from werkzeug.security import generate_password_hash, check_password_hash import jwt from flask_cors import cross_origin @@ -9,6 +9,13 @@ import os import logging +from ayat import mail +from flask_mail import Message +from itsdangerous import URLSafeTimedSerializer + + +serializer = URLSafeTimedSerializer("thisissecret") + logger = logging.getLogger(__name__) logger.setLevel(logging.DEBUG) formatter = logging.Formatter('%(asctime)s : %(name)s : %(levelname)s : %(message)s') @@ -277,6 +284,13 @@ def login_or_create(): ############### + user_email = new_user.email + token_email = serializer.dumps(user_email, salt= "email_confirm") + confirmation_link = url_for('confirm_email_token', token = token_email, public_id = new_user.public_id, _external = True) + content = f"Welcome to ayat. \n This is the link to confirm your email which will expire in two hours. \n link : \n {confirmation_link}" + msg = Message("Ayat Email Confirmation",sender="ayatquraancenter@gmail.com",recipients=user_email.split()) + msg.body = content + mail.send(msg) logger.info('user succeeded to register') @@ -319,6 +333,16 @@ def login_or_create(): new_user.permissions.append(new_permission) db.session.add(new_user) db.session.commit() + + user_email = new_user.email + token_email = serializer.dumps(user_email, salt= "email_confirm") + confirmation_link = url_for('confirm_email_token', token = token_email, public_id =new_user.public_id, _external = True) + content = f"Welcome to ayat. \n This is the link to confirm your email which will expire in two hours. \n link : \n {confirmation_link}" + msg = Message("Ayat Email Confirmation",sender="ayatquraancenter@gmail.com",recipients=user_email.split()) + msg.body = content + mail.send(msg) + + logger.info('user succeeded to register') return jsonify({'status': 'created', 'public_id': new_user.public_id,}), 200 From c9f86d5e940dc1ed61187cb0b787340a165de4e5 Mon Sep 17 00:00:00 2001 From: AhmedElsayed101 Date: Fri, 15 May 2020 01:01:35 +0200 Subject: [PATCH 5/6] fixing users.md --- docs/users.md | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/docs/users.md b/docs/users.md index b86990c..a36701c 100644 --- a/docs/users.md +++ b/docs/users.md @@ -188,12 +188,14 @@ code: **`404`** "full_name": "example", "email": "explsaddfeasdasd", "country": "example", - "phone": 123, + "phone": "123", "profile_pic": "2d", "birth_date": "2015-05-16", - "gender": false, + "gender": false, "password": "464468", - "registeration_date": "2015-05-16" + "registeration_date": "2015-05-16", + "guardian_email" : "111d19", + "guardian_phone" : "11d119" } ``` or @@ -204,12 +206,13 @@ or "full_name": "example", "email": "explsaddfeasdasd", "country": "example", - "phone": 123, + "phone": "123", "profile_pic": "2d", "birth_date": "2015-05-16", - "gender": false, + "gender": false, "password": "464468", - "registeration_date": "2015-05-16" + "registeration_date": "2015-05-16", + "permission_name": "teacher" } ``` From bfaa4f22cb6960f4714d249b86a721cdec024b60 Mon Sep 17 00:00:00 2001 From: AhmedElsayed101 Date: Fri, 15 May 2020 01:22:46 +0200 Subject: [PATCH 6/6] adding account_activation.md --- ayat/account_activation_routes.py | 15 +++---- docs/account_activation.md | 70 +++++++++++++++++++++++++++++++ 2 files changed, 78 insertions(+), 7 deletions(-) create mode 100644 docs/account_activation.md diff --git a/ayat/account_activation_routes.py b/ayat/account_activation_routes.py index 2be5b55..11f8f0b 100644 --- a/ayat/account_activation_routes.py +++ b/ayat/account_activation_routes.py @@ -22,13 +22,15 @@ serializer = URLSafeTimedSerializer("thisissecret") -@app.route("/v1/users//confirm",methods=['POST','GET']) +@app.route("/v1/users//confirm",methods=['GET']) #'POST', @cross_origin() def confirm_email(public_id): data = request.get_json(force=True) current_user = User.query.filter_by(public_id=public_id ).first() + if not current_user: + return jsonify({'status': 'user not found'}) # if request.method == "POST": # current_user_email = data["email"] # user_email_check = User.query.filter_by(email= current_user_email ).first() @@ -45,7 +47,7 @@ def confirm_email(public_id): # send_message(subject="Ayat Email Confirmation",recipients= user_email,content= content,html_content= "

hello

", resource="hello.jpg",resource_type= "jpg") - return jsonify({"message":"sent"}) + return jsonify({"status":"message was sent"}) @@ -53,7 +55,7 @@ def confirm_email(public_id): -@app.route("/v1/users//confirm/",methods=['POST','GET']) +@app.route("/v1/users//confirm/",methods=['GET']) #'POST', @cross_origin() def confirm_email_token(token, public_id): @@ -66,10 +68,9 @@ def confirm_email_token(token, public_id): db.session.commit() except SignatureExpired: - return jsonify({"message":"token has expired"}),401 + return jsonify({"status":"token has expired"}) except BadTimeSignature: + return jsonify({"status":"token is damaged"}) - return jsonify({"message":"token is damaged"}),401 - - return jsonify({"message":"confirmed"}),200 + return jsonify({"status":"confirmed"}),200 diff --git a/docs/account_activation.md b/docs/account_activation.md new file mode 100644 index 0000000..ee968ba --- /dev/null +++ b/docs/account_activation.md @@ -0,0 +1,70 @@ +### Account_activation routes + +
+ +#### Ask for acount confirmation + +`api.ayat.com/v1/users//confirm` **`GET`** + +##### Payload: + +```Json +{} + +``` +##### Success Response: + +code : **`200`** + +```Json +{ + "status":"message sent" +} +``` +##### Error Response: + +code: **`403`** + +```json +{ + "status": "user not found" +} +``` +
+ +#### Acount confirmation link + +`api.ayat.com/v1/users//confirm/` **`GET`** + +##### Payload: + +```Json +{} + +``` +##### Success Response: + +code : **`200`** + +```Json +{ + "status":"confirmed" +} +``` +##### Error Response: + +```json +{ + "status": "token has expired" +} +``` +##### Error Response: + +```json +{ + "status": "token is damaged" +} +``` + + +