diff --git a/hodor/controllers/challenges.py b/hodor/controllers/challenges.py new file mode 100644 index 0000000000000000000000000000000000000000..eb109c3024c9e9b97c8b5b96af652ea3570210ae --- /dev/null +++ b/hodor/controllers/challenges.py @@ -0,0 +1,134 @@ +from hodor import app +from flask import request, jsonify, abort, make_response +from hodor.models.challenges import Challenges +from sqlalchemy.exc import IntegrityError + +########################### +# Add a new challenge to the platform # +########################### +@app.route('/challenges/new', methods=['POST']) +def add_new_chall(): + """ + This function is used to add new challenges to the platform + :return: Response Code + """ + newchall=dict() + + if request.method == "POST": + try: + newchall['chall_id'] = request.data.get('chall_id').strip() + newchall['name'] = str(request.data.get('name').strip()) + newchall['points'] = request.data.get('points').strip() + newchall['description'] = str(request.data.get('description').strip()) + newchall['hints'] = str(request.data.get('hints').strip()) + except Exception as e: + print(e) + abort(500) + chall = Challenges(**newchall) + chall.save() + return make_response(jsonify(status=201, msg="Challenge {} successfully added".format(chall.chall_id) + + "to database"), 201) + +########################### +# Edit an existing challenge +########################### +@app.route('/challenges/edit', methods=['PUT']) +def edit_chall(): + """ + This function enables to edit existing challenges + :return: Response Code + """ + chall_id=request.data.get('chall_id').strip() + get_id = Challenges.query.get(chall_id) + chall={} + if(get_id): + try: + get_id.name = str(request.data.get('name').strip()) + get_id.points = str(request.data.get('points').strip()) + get_id.description = str(request.data.get('description').strip()) + get_id.hints = str(request.data.get('hints').strip()) + except Exception as e: + print(e) + abort(500) + get_id.commit() + return make_response(jsonify(status=200, msg="Record succesfully edited"), 200) + else: + return make_response(jsonify(status=404, msg="No such challenge ID found"), 404) + +########################### +# Deleting an existing challenge +########################### +@app.route('/challenges/<id_slug>', methods=['DELETE']) +def del_chall(id_slug): + """ + This function deletes existing challenge + :return: Response Code + """ + check_id = id_slug.strip() + get_id = Challenges.query.filter_by(chall_id=check_id) + if get_id: + Challenges.query.filter_by(chall_id=id_slug).delete() + return make_response(jsonify(status=200, msg="Record succesfully deleted"), 200) + else: + return make_response(jsonify(status=404, msg="No such challenge ID found"), 404) + +########################### +# Extracting required fields +########################### +def _extract_required_fields(chall): + filter_chall = dict() + ''' + This can be done by directly dumping the dictionary but there's always + a risk of data leak.So, we pick what we need to give out out of the API + ''' + filter_chall['name'] = chall.name + filter_chall['description'] = chall.description + filter_chall['points'] = chall.points + filter_chall['hints'] = chall.hints + filter_chall['chall_id'] = chall.chall_id + + return filter_chall + + +########################### +#Get all challenge IDs +########################### +@app.route('/challenges', methods=['GET','POST']) +def get_all_challids(): + """ + Returns all challenge IDs and names + :return: Response Code + """ + response = dict() + response['status'] = 200 + response['data'] = [] + + for challenge in Challenges.get_all(): + ''' + All records for each challenge is retrieved and name, id are only returned + ''' + response['data'].append(_extract_required_fields(challenge)) + + return response + + +################################################ +# Handle Integrity Exceptions in API # +################################################ +@app.errorhandler(IntegrityError) +def handle_sql_assertion_error(err): + try: + ''' + err.orig.args is from the DBAPIError class of SQLAlchemy. It usually + contains the original error message. + The below is an attempt to clean up the message and only return the + relevant part to API + ''' + try: + errmsg = err.orig.args[0].split('\n')[1][9:] + except IndexError: + errmsg = err.orig.args[0].split('\n') + except IndexError: + errmsg = err.orig.args[0] + + return make_response(jsonify(status=400, msg=errmsg), 400) diff --git a/hodor/models/challenges.py b/hodor/models/challenges.py index 615b5eebb80f02e64424fc714e02d84deb03a7ec..5c1e639b6f3d0dae4bdcfe3fe6ee9b6242504f60 100644 --- a/hodor/models/challenges.py +++ b/hodor/models/challenges.py @@ -7,13 +7,13 @@ class Challenges(db.Model): __tablename__= 'challenges' # Data variables for each challenge - id = db.Column(db.String(32), primary_key=True, unique=True, nullable=False) + chall_id = db.Column(db.Integer, primary_key=True, unique=True, nullable=False) name = db.Column(db.String(32), nullable=False) points = db.Column(db.Integer, nullable=False) description = db.Column(db.String(2048), nullable=False) hints = db.Column(db.String(512), nullable=False) - @staticmethod + def save(self): db.session.add(self) db.session.commit() @@ -22,5 +22,10 @@ class Challenges(db.Model): db.session.delete(self) db.session.commit() + @staticmethod def get_all(): return Challenges.query.all() + + @staticmethod + def commit(): + return db.session.commit()