diff --git a/.gitignore b/.gitignore index eba74f4..d6806b8 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,7 @@ -venv/ \ No newline at end of file +venv/ +__pycache__/ +app/__pycache__/ +app/routes/__pycache__ +.vscode/ +.vscode/settings.json +.pytest_cache/ \ No newline at end of file diff --git a/Procfile b/Procfile new file mode 100644 index 0000000..8001d1a --- /dev/null +++ b/Procfile @@ -0,0 +1 @@ +web: gunicorn app:app \ No newline at end of file diff --git a/app/__init__.py b/app/__init__.py new file mode 100644 index 0000000..a089413 --- /dev/null +++ b/app/__init__.py @@ -0,0 +1,6 @@ +from flask import Flask +from config import Config + +app = Flask(__name__) + +app.config.from_object(Config) diff --git a/app/forms.py b/app/forms.py new file mode 100644 index 0000000..ddc5ba2 --- /dev/null +++ b/app/forms.py @@ -0,0 +1,15 @@ +from flask_wtf import FlaskForm +from wtforms import (StringField, PasswordField, BooleanField, + SubmitField, TextAreaField, IntegerField, TextField) +from wtforms.validators import (DataRequired, ValidationError, Email, Length, Optional) + + +class QuestionForm(FlaskForm): + topic = StringField('Topic', description='Topic') + body = TextAreaField('Question', description='Enter question here') + + + +class AnswerForm(FlaskForm): + Qn_Id = IntegerField('Question Id/No.', description='Enter question Id') + body = StringField('Answer', description='Enter answer here..') \ No newline at end of file diff --git a/app/models.py b/app/models.py new file mode 100644 index 0000000..4931155 --- /dev/null +++ b/app/models.py @@ -0,0 +1,109 @@ + +ans_List = [ + + { + 'answerId': 1, + 'Qn_Id': 1, + 'body': '''Lorem ipsum dolor sit amet, consectetur adipiscing + elit.Vivamus nec tortor ac purus luctus lobortis id et magna. + Pellentesque id odio volutpat, fermentum neque non, + vestibulum enim.Vivamus aliquet libero quis orci mattis + tincidunt.'''}, + {'answerId': 2, + 'Qn_Id': 2, + 'body': '''What's programmingLorem ipsum dolor sit amet, + consectetur adipiscing elit.Vivamus nec tortor ac purus + luctus lobortis id et magna.Pellentesque id odio volutpat, + fermentum neque non, vestibulum enim.Vivamus aliquet libero + quis orci mattis tincidunt.'''}, + {'answerId': 3, + 'Qn_Id': 3, + 'body': '''What are data structuresLorem ipsum dolor sit amet, + consectetur adipiscing elit.Vivamus nec tortor ac purus luctus + lobortis id et magna.Pellentesque id odio volutpat, fermentum + neque non, vestibulum enim.Vivamus + aliquet libero quis orci mattis tincidunt.'''}, + {'answerId': 4, + 'Qn_Id': 4, + 'body': '''Lorem ipsum dolor sit amet, consectetur adipiscing + elit.Vivamus nec tortor ac purus luctus lobortis id et magna. + Pellentesque id odio volutpat, fermentum neque non, + vestibulum enim.Vivamus aliquet libero quis orci mattis + tincidunt.'''} +] + + +class Question: + def __init__(self, questionId=0, topic='', body=''): + self.id = questionId + self.topic = topic + self.body = body + self.answers = [] + + def __repr__(self): + return { + 'questionId': self.id, + 'topic': self.topic, + 'body': self.body + } + + +def createQnsList(): + '''Generates a List of five questions with different topics + and links answers to them''' + + QnsList = [] + body = '''Lorem ipsum dolor sit amet, consectetur adipiscing + elit.Vivamus nec tortor ac purus luctus lobortis id et magna. + Pellentesque id odio volutpat, fermentum neque non, vestibulum + enim.Vivamus aliquet libero quis orci mattis tincidunt.''' + + topics = [0, 'python', 'comp science', 'AI', 'blockchain', 'ethereum'] + + for i in range(1, 6): + Qn = Question(i, topics[i], body) + + for answer in ans_List: + if answer['Qn_Id'] == Qn.id: + Qn.answers.append(answer) + + QnsList.append(Qn.__repr__()) + return QnsList + + +questionsList = createQnsList() + + +class Answer: + def __init__(self, answerId=0, body='', Qn_Id=0): + self.answerId = answerId + self.body = body + self.Qn_Id = Qn_Id + + def __repr__(self): + return { + 'answerId': self.answerId, + 'Qn_Id': self.Qn_Id, + 'body': self.body + } + + +def createAnsList(): + '''Generates list of five answers''' + AnsList = [] + body = '''Lorem ipsum dolor sit amet, consectetur adipiscing + elit.Vivamus nec tortor ac purus luctus lobortis id et magna. + Pellentesque id odio volutpat, fermentum neque non, vestibulum + enim.Vivamus aliquet libero quis orci mattis tincidunt.''' + + l = [question['questionId'] for question in questionsList] + qnIds = [id for id in l] + qnIds[:0] = [0] + + for i in range(1, 6): + Ans = Answer(i, body, qnIds[i]) + AnsList.append(Ans.__repr__()) + return AnsList + +answersList = createAnsList() + diff --git a/app/routes/routes.py b/app/routes/routes.py new file mode 100644 index 0000000..4ace7d0 --- /dev/null +++ b/app/routes/routes.py @@ -0,0 +1,97 @@ +from flask import (Flask, Response, flash, json, jsonify, + request, session, url_for) + +from app import app +from app.models import Answer, Question, answersList, questionsList + + +@app.route('/api/v1/questions', methods=['GET']) +def get_questions(): + return jsonify({'questions': questionsList}) + +@app.route('/api/v1/questions/', methods=['GET']) +def get_question(questionId): + for question in questionsList: + if question['questionId'] == questionId: + temp = { + 'questionId': question['questionId'], + 'topic': question['topic'], + 'body': question['body'] + } + return jsonify(temp) + return Response(json.dumps(['Question not Found']), + status=404, mimetype='application/json') + + +@app.route('/api/v1/questions', methods=['POST']) +def add_question(): + + request_data = request.get_json() + if (valid_question(request_data)): + temp = { + 'questionId': request_data['questionId'], + 'topic': request_data['topic'], + 'body': request_data['body'] + } + questionsList.append(temp) + response = Response('', 201, mimetype='application/json') + response.headers['location'] = ('questions/' + + str(request_data['questionId'])) + + return response + else: + bad_object = { + "error": "Invalid question object", + "hint": '''Request format should be,{'questionId':1, 'topic': 'python', + 'body': 'what is python in programming' }''' + } + response = Response(json.dumps([bad_object]), + status=400, mimetype='application/json') + return response + +@app.route('/api/v1/questions//answers', methods=['POST']) +def add_answer(questionId): + request_data = request.get_json() + if (valid_answer(request_data)): + temp = { + 'answerId': request_data['answerId'], + 'Qn_Id': request_data['Qn_Id'], + 'body': request_data['body'] + } + answersList.append(temp) + for question in questionsList: + if question['questionId'] == request_data['Qn_Id']: + question = Question(question['questionId'], + question['topic'], question['body']) + question.answers.append(temp) + + response = Response('', status=201, mimetype='application/json') + response.headers['location'] = ('answers/' + + str(request_data['answerId'])) + return response + + else: + bad_object = { + "error": "Invalid answer object", + "hint": '''Request format should be {'answerId':1, + 'body': 'this is the body', + 'Qn_Id': 2}''' + } + response = Response(json.dumps([bad_object]), + status=400, mimetype='application/json') + return response + + + + +def valid_question(questionObject): + if 'topic' in questionObject and 'body' in questionObject: + return True + else: + return False + +def valid_answer(answerObject): + if 'Qn_Id' in answerObject and 'answerId' in answerObject and 'body' in answerObject : + return True + else: + return False \ No newline at end of file diff --git a/app/static/011.png b/app/static/011.png new file mode 100644 index 0000000..f605e7a Binary files /dev/null and b/app/static/011.png differ diff --git a/app/static/015.JPG b/app/static/015.JPG new file mode 100644 index 0000000..8ec4b9f Binary files /dev/null and b/app/static/015.JPG differ diff --git a/app/static/gears.jpeg b/app/static/gears.jpeg new file mode 100644 index 0000000..881811e Binary files /dev/null and b/app/static/gears.jpeg differ diff --git a/app/static/img2.jpg b/app/static/img2.jpg new file mode 100644 index 0000000..249fc3b Binary files /dev/null and b/app/static/img2.jpg differ diff --git a/app/static/img3.jpg b/app/static/img3.jpg new file mode 100644 index 0000000..3472d96 Binary files /dev/null and b/app/static/img3.jpg differ diff --git a/app/static/img4.jpg b/app/static/img4.jpg new file mode 100644 index 0000000..62943b9 Binary files /dev/null and b/app/static/img4.jpg differ diff --git a/app/static/kybrd.jpeg b/app/static/kybrd.jpeg new file mode 100644 index 0000000..90316d3 Binary files /dev/null and b/app/static/kybrd.jpeg differ diff --git a/app/static/login.css b/app/static/login.css new file mode 100644 index 0000000..9e033ac --- /dev/null +++ b/app/static/login.css @@ -0,0 +1,178 @@ + + +body { + /*font-family: Arial, Helvetica, sans-seriff; + font-size: 15px; + line-height: 1.5; same as*/ + font: 15px/1.5 Arial,Helvetica, sans-seriff; + padding: 0; + margin: 0; + /*background-color: #35424a;*/ + background-color: #f4f4f4; + + +} + +/*Global*/ +.container{ + width: 90%; + margin: auto; + overflow: hidden; +} + +ul{ + padding: 0; + margin: 0; + + } + +.button_1{ + height: 30px; + margin:auto; + color: #ffffff; + padding-left: 20px; + padding-right: 20px; + background: #e8491d; + border-color:#35424a; +} + + +/*Header*/ +header { + /*background-color: #35424a;*/ + background:url("../img/img2.jpg") no-repeat; + color: #f4f4f4; + /*color:orange;*/ + font-size: 20px; + padding-top:30px; + padding-bottom: 0; + min-height: 70px; + border-bottom: #e8491d 4px solid; +} + +header a{ + color: #ffffff; + text-decoration:none; + text-transform: uppercase; + font-size: 15px; + } + +header li{ + float: left; + display: inline; + padding:0 20px 0 20px; + } + +head #branding{ + float: left; +} + +header #branding h1{ + margin:0; +} + +header nav{ + float:right; + margin-top: 10px; +} + +header .highlight, header .current a{ + color:#e8491d; + font-weight:bold; +} + +header a:hover{ + color: #CCCCCC; + font-weight:bold; +} + +#container2{ + width: 30%; + max-height: 10px; + display: inline; +} + +#container2 #remember{ + float: left; + width:10%; + height: 5px; + margin-top: 10px; + margin-left: 20px; + +} + +#container2 h3{ + float: right; + height: 90%; + width:50%; + margin-right: 30%; + margin-bottom: 10px; +} + +#register{ + background:url("../img/kybrd.jpeg") ; + /*background-color: #35424a;*/ + /*border: #35424a 2px solid;*/ + margin-left:30%; + margin-right: 30% + min-height:50%; + + padding-top: 20px; + padding-bottom: 10px; + width :40%; + +} + +#register h3{ + color:#f4f4f4; +} +/* +#register .box{ + + background:url("../img/015.jpg") no-repeat ; + border: #35424a 4px solid; +} +*/ +#register h2{ + margin-top: 20px; + color: #ffffff; + font-weight: bold; + text-decoration:none; +} + +#register a{ + color: #e8491d; +} + +#register form{ + min-height: 200px; + margin-bottom: 100px; + +} + +#register form input{ + min-height:30px; + padding:3px ; + width: 90%; + /*border: #e8491d 2px solid;*/ + } + + +/*footer */ +footer{ + clear: both; + margin-bottom: 0; + width: 100%; + /*background-color: #35424a;*/ + background:url("../img/img2.jpg") no-repeat; + border-top:#e8491d 4px solid; + text-decoration: none; +} + +footer p{ + padding:10px; + margin:0; + color: #ffffff; + text-align: center; + +} \ No newline at end of file diff --git a/app/static/mthrbrd.jpeg b/app/static/mthrbrd.jpeg new file mode 100644 index 0000000..93bd8ab Binary files /dev/null and b/app/static/mthrbrd.jpeg differ diff --git a/app/static/question.css b/app/static/question.css new file mode 100644 index 0000000..7975ee6 --- /dev/null +++ b/app/static/question.css @@ -0,0 +1,168 @@ + + +body { + /*font-family: Arial, Helvetica, sans-seriff; + font-size: 15px; + line-height: 1.5; same as*/ + font: 15px/1.5 Arial,Helvetica, sans-seriff; + padding: 0; + margin: 0; + background-color: #f4f4f4; + + +} + +/*Global*/ +.container{ + width: 90%; + margin: auto; + overflow: hidden; +} + +ul{ + padding: 0; + margin: 0; + + } + +.button_1{ + height: 30px; + margin :20px; + color: #ffffff + padding-left: 20px; + padding-right: 20px; + background: #e8491d; + border-color:#35424a; +} + +/*Header*/ +header { + /*background-color: #35424a;*/ + background:url("../img/img2.jpg") no-repeat; + color: #f4f4f4; + /*color:orange;*/ + font-size: 20px; + padding-top:30px; + padding-bottom: 0; + min-height: 70px; + border-bottom: #e8491d 4px solid; +} + +header a{ + color: #ffffff; + text-decoration:none; + text-transform: uppercase; + font-size: 15px; + } + +header li{ + float: left; + display: inline; + padding:0 20px 0 20px; + } + +head #branding{ + float: left; +} + +header #branding h1{ + margin:0; +} + +header nav{ + float:right; + margin-top: 10px; +} + +header .highlight, header .current a{ + color:#e8491d; + font-weight:bold; +} + +header a:hover{ + color: #CCCCCC; + font-weight:bold; +} + + +/*showcase*/ +#showcase{ + min-height: 400px; + width: 100%; + color : black; + border: #e8491d; + +} + +#showcase h3{ + text-decoration: none; +} + +/*content*/ +/*answer box*/ +#content { + width: 100%; +} + + +#answer{ + + width:50%; +} + + +#answer .box{ + /*background: grey;*/ + margin-left: 60%; + width:50%; + background:url("{{ url_for('static', filename='kybrd.jpeg') }}") repeat ; + /*background-color: #35424a;*/ + border: #35424a 4px solid; + margin-bottom: 10px; + /*border-bottom: #35424a 4px solid;*/ +} + +#answer h2{ + margin-top: 20px; + color: #ffffff; + font-weight: bold; + text-decoration:none; +} + +#answer form{ + min-height: 30px; + +} + +#answer form input{ + min-height:20px; + padding:3px ; + width: 80%; + /*border: #e8491d 2px solid;*/ +} +#answer form .button_1{ + margin-top: 10px; + margin-bottom: 10px; + +} + +/*footer */ +footer{ + clear: both; + /*position: absolute ;*/ + /*bottom: 0;*/ + margin-bottom: 0; + width: 100%; + /*background-color: #35424a;*/ + background:url("../img/img2.jpg") no-repeat; + border-top:#e8491d 4px solid; + text-decoration: none; +} + +footer p{ + padding:10px; + margin:0; + color: #ffffff; + text-align: center; + +} \ No newline at end of file diff --git a/app/static/signUp.css b/app/static/signUp.css new file mode 100644 index 0000000..0f95960 --- /dev/null +++ b/app/static/signUp.css @@ -0,0 +1,152 @@ + + +body { + /*font-family: Arial, Helvetica, sans-seriff; + font-size: 15px; + line-height: 1.5; same as*/ + font: 15px/1.5 Arial,Helvetica, sans-seriff; + padding: 0; + margin: 0; + background-color: #f4f4f4; + + +} + +/*Global*/ +.container{ + width: 90%; + margin: auto; + overflow: hidden; +} + +ul{ + padding: 0; + margin: 0; + + } + +.button_1{ + height: 30px; + margin:auto; + color: #ffffff; + padding-left: 20px; + padding-right: 20px; + background: #e8491d; + border-color:#35424a; +} + + +/*Header*/ +header { + /*background-color: #35424a;*/ + background:url("../img/img2.jpg") no-repeat; + color: #f4f4f4; + /*color:orange;*/ + font-size: 20px; + padding-top:30px; + padding-bottom: 0; + min-height: 70px; + border-bottom: #e8491d 4px solid; +} + +header a{ + color: #ffffff; + text-decoration:none; + text-transform: uppercase; + font-size: 15px; + } + +header li{ + float: left; + display: inline; + padding:0 20px 0 20px; + } + +head #branding{ + float: left; +} + +header #branding h1{ + margin:0; +} + +header nav{ + float:right; + margin-top: 10px; +} + +header .highlight, header .current a{ + color:#e8491d; + font-weight:bold; +} + +header a:hover{ + color: #CCCCCC; + font-weight:bold; +} + + +#register{ + background:url("../img/kybrd.jpeg") ; + /*border: #35424a 4px solid;*/ + margin-left:30%; + margin-right: 30% + padding-top: 20px; + padding-bottom: 10px; + width :40%; + +} + + +h3{ + color:#f4f4f4; +} +/* +#register .box{ + + background:url("../img/015.jpg") no-repeat ; + border: #35424a 4px solid; +} +*/ +#register h2{ + margin-top: 20px; + color: #ffffff; + font-weight: bold; + text-decoration:none; +} + +#register a{ + color: #e8491d; +} + +#register form{ + min-height: 200px; + +} + +#register form input{ + min-height:30px; + padding:3px ; + width: 90%; + /*border: #e8491d 2px solid;*/ +} + + +/*footer */ +footer{ + clear: both; + margin-bottom: 0; + width: 100%; + /*background-color: #35424a;*/ + background:url("../img/img2.jpg") no-repeat; + border-top:#e8491d 4px solid; + text-decoration: none; +} + +footer p{ + padding:10px; + margin:0; + color: #ffffff; + text-align: center; + +} \ No newline at end of file diff --git a/app/static/style.css b/app/static/style.css new file mode 100644 index 0000000..e06df3f --- /dev/null +++ b/app/static/style.css @@ -0,0 +1,164 @@ + + +body { + /*font-family: Arial, Helvetica, sans-seriff; + font-size: 15px; + line-height: 1.5; same as*/ + font: 15px/1.5 Arial,Helvetica, sans-seriff; + padding: 0; + margin: 0; + background-color: #f4f4f4; + + +} + +/*Global*/ +.container{ + width: 90%; + margin: auto; + overflow: hidden; +} + +ul{ + padding: 0; + margin: 0; + + } + +.button_1{ + height: 30px; + margin :20px; + color: #ffffff + padding-left: 20px; + padding-right: 20px; + background: #e8491d; + border-color:#35424a; +} + +/*Header*/ +header { + /*background-color: #35424a;*/ + background:url("../img/img2.jpg") no-repeat; + color: #f4f4f4; + /*color:orange;*/ + font-size: 20px; + padding-top:30px; + padding-bottom: 0; + min-height: 70px; + border-bottom: #e8491d 4px solid; +} + +header a{ + color: #ffffff; + text-decoration:none; + text-transform: uppercase; + font-size: 15px; + } + +header li{ + float: left; + display: inline; + padding:0 20px 0 20px; + } + +head #branding{ + float: left; +} + +header #branding h1{ + margin:0; +} + +header nav{ + float:right; + margin-top: 10px; +} + +header .highlight, header .current a{ + color:#e8491d; + font-weight:bold; +} + +header a:hover{ + color: #CCCCCC; + font-weight:bold; +} + + +/*showcase*/ +#showcase{ + min-height: 400px; + width: 80%; + /*background:url("../img/015.jpg") no-repeat;*/ + /*margin:20px;*/ + color : black; + float: left; +} + +#showcase h3{ + text-decoration: none; +} + +/*content*/ +/*question box*/ +#content { + width: 100%; +} + + +#question{ + margin-top: 20px; + padding-top: 20px; + width:20%; + padding-bottom: 10px; + float: right; +} +#question .box{ + +<<<<<<< HEAD + background:url("../img/015.jpg") no-repeat ; +======= + background:url("../img/015.JPG") no-repeat ; +>>>>>>> 1fcf8137b2a5018aa69ee9cebea35565080a9044 + border: #35424a 4px solid; +} + +#question h2{ + margin-top: 20px; + color: #ffffff; + font-weight: bold; + text-decoration:none; +} + +#question form{ + min-height: 200px; + +} + +#question form input{ + min-height:30px; + padding:3px ; + width: 90%; + border: #e8491d 2px solid; + } + + +/*footer */ +footer{ + clear: both; + position: absolute ; + bottom: 0; + width: 100%; + /*background-color: #35424a;*/ + background:url("../img/img2.jpg") no-repeat; + border-top:#e8491d 4px solid; + text-decoration: none; +} + +footer p{ + padding:10px; + margin:0; + color: #ffffff; + text-align: center; + +} \ No newline at end of file diff --git a/app/static/style2.css b/app/static/style2.css new file mode 100644 index 0000000..fbe53fd --- /dev/null +++ b/app/static/style2.css @@ -0,0 +1,167 @@ + + +body { + /*font-family: Arial, Helvetica, sans-seriff; + font-size: 15px; + line-height: 1.5; same as*/ + font: 15px/1.5 Arial,Helvetica, sans-seriff; + padding: 0; + margin: 0; + background-color: #f4f4f4; + + +} + +/*Global*/ +.container{ + width: 90%; + margin: auto; + overflow: hidden; +} + +ul{ + padding: 0; + margin: 0; + + } + +.button_1{ + height: 30px; + margin :20px; + color: #ffffff + /*padding-left: 20px; + padding-right: 20px;*/ + padding: 5px 20px 5px 20px; + background: #e8491d; + border-color: #35424a; +} + +/*Header*/ +header { + /*background-color: #35424a;*/ + background:url("../img/img2.jpg") no-repeat; + color: #f4f4f4; + /*color:orange;*/ + font-size: 20px; + padding-top:30px; + padding-bottom: 0; + min-height: 70px; + border-bottom: #e8491d 4px solid; +} + +header a{ + color: #ffffff; + text-decoration:none; + text-transform: uppercase; + font-size: 15px; + } + +header li{ + float: left; + display: inline; + padding:0 20px 0 20px; + } + +head #branding{ + float: left; +} + +header #branding h1{ + margin:0; +} + +header nav{ + float:right; + margin-top: 10px; +} + +header .highlight, header .current a{ + color:#e8491d; + font-weight:bold; +} + +header a:hover{ + color: #CCCCCC; + font-weight:bold; +} + + +/*showcase*/ +#showcase{ + min-height: 400px; + width: 70%; + /*background:url("../img/015.jpg") no-repeat;*/ + /*margin:20px;*/ + color : black; + float: left; +} + +#recent h2{ + color:#e8491d; +} + +/*content*/ +/*question box*/ +#content { + width: 100%; + border-color: #e8491d; +} + + +#question{ + margin-top: 20px; + padding-top: 20px; + margin-right: 5px; + width:25%; + padding-bottom: 10px; + float: right; +} +#question .box{ + background:url("../img/kybrd.jpeg") ; + /*border: #35424a 4px solid;*/ + +} + +#question h2{ + margin-top: 20px; + color: #ffffff; + font-weight: bold; + text-decoration:none; +} + +form label{ + margin-top: 20px; + font-weight: bold; +} + +#question form{ + min-height: 200px; + +} + +#question form.data{ + min-height:30px; + padding:3px ; + width: 90%; + /*border: #e8491d 2px solid;*/ + } + + +/*footer */ +footer{ + clear: both; + margin-bottom: 0; + width: 100%; + /*background-color: #35424a;*/ + background:url("../img/img2.jpg") no-repeat; + border-top:#e8491d 4px solid; + text-decoration: none; +} + +footer p{ + padding:10px; + margin:0; + color: #ffffff; + text-align: center; + +} \ No newline at end of file diff --git a/app/static/user.css b/app/static/user.css new file mode 100644 index 0000000..165da24 --- /dev/null +++ b/app/static/user.css @@ -0,0 +1,159 @@ + + +body { + /*font-family: Arial, Helvetica, sans-seriff; + font-size: 15px; + line-height: 1.5; same as*/ + font: 15px/1.5 Arial,Helvetica, sans-seriff; + padding: 0; + margin: 0; + background-color: #f4f4f4; + + +} + +/*Global*/ +.container{ + width: 90%; + margin: auto; + overflow: hidden; +} + +ul{ + padding: 0; + margin: 0; + + } + +.button_1{ + height: 30px; + margin :20px; + color: #ffffff + padding-left: 20px; + padding-right: 20px; + background: #e8491d; + border-color:#35424a; +} + +/*Header*/ +header { + /*background-color: #35424a;*/ + background:url("../img/img2.jpg") no-repeat; + color: #f4f4f4; + /*color:orange;*/ + font-size: 20px; + padding-top:30px; + padding-bottom: 0; + min-height: 70px; + border-bottom: #e8491d 4px solid; +} + +header a{ + color: #ffffff; + text-decoration:none; + text-transform: uppercase; + font-size: 15px; + } + +header li{ + float: left; + display: inline; + padding:0 20px 0 20px; + } + +head #branding{ + float: left; +} + +header #branding h1{ + margin:0; +} + +header nav{ + float:right; + margin-top: 10px; +} + +header .highlight, header .current a{ + color:#e8491d; + font-weight:bold; +} + +header a:hover{ + color: #CCCCCC; + font-weight:bold; +} + +/*content*/ +#content{ + margin: auto; + width: 100; +} + +/*showcase*/ +#showcase{ + min-height: 400px; + width: 25%; + /*background:url("../img/015.jpg") no-repeat;*/ + /*margin:20px;*/ + color : black; + margin-left: 20px; + float: left; +} + +#showcase h3{ + text-decoration: none; +} + +#content img{ + min-width: auto; + min-height:auto; +} + +#content{ + align-content: center; +} + +aside{ + margin-top: 0; + width: 60%; + float: right; + display: inline; +} +aside .box{ + min-height:520px; + margin: 0; + padding: 0; + /*border: #35424a 4px solid;*/ + /*margin-bottom: 0;*/ +} + +aside h2{ + margin-top: 20px; + color: #35424a; + font-weight: bold; + text-decoration:none; +} + +#activity li{ + margin-left: 0; +} + + +/*footer */ +footer{ + clear: both; + margin-bottom: 0; + /*background-color: #35424a;*/ + background:url("../img/img2.jpg") no-repeat; + border-top:#e8491d 4px solid; + text-decoration: none; +} + +footer p{ + padding:10px; + margin:0; + color: #ffffff; + text-align: center; + +} \ No newline at end of file diff --git a/app/templates/README.md b/app/templates/README.md new file mode 100644 index 0000000..375ed97 --- /dev/null +++ b/app/templates/README.md @@ -0,0 +1 @@ +# StackOverflow-lite \ No newline at end of file diff --git a/app/templates/a.html b/app/templates/a.html new file mode 100644 index 0000000..1989878 --- /dev/null +++ b/app/templates/a.html @@ -0,0 +1,12 @@ + + + + + + + Document + + + + + \ No newline at end of file diff --git a/app/templates/index.html b/app/templates/index.html new file mode 100644 index 0000000..e9c42e2 --- /dev/null +++ b/app/templates/index.html @@ -0,0 +1,47 @@ + +{% extends 'layout.html' %} + +{% block content %} +
+
+
+

Recent questions

+
+ {% for item in questions %} +

User no. {{questions[questions.index(item)]['questionId']}} asked:
+ Topic: {{questions[questions.index(item)]['topic']}}


+ {{questions[questions.index(item)]['body']}} +
+

+ {% endfor %} +
+
+ + +{% endblock %} + \ No newline at end of file diff --git a/app/templates/layout.html b/app/templates/layout.html new file mode 100644 index 0000000..625c821 --- /dev/null +++ b/app/templates/layout.html @@ -0,0 +1,39 @@ + + + + + + + + + StackOverflow-lite + + +
+
+
+

StackOverflow-lite

+
+ {% with messages =get_flashed_messages() %}{% if messages %} +
    + {% for message in messages %} +
  • {{ message }}
  • + {% endfor %} +
+ {% endif %}{% endwith %} +
+
+ + {% block content %}{% endblock%} + +
+

StackOverflow-lite © 2018

+
+ + \ No newline at end of file diff --git a/app/templates/layout2.html b/app/templates/layout2.html new file mode 100644 index 0000000..a4d3138 --- /dev/null +++ b/app/templates/layout2.html @@ -0,0 +1,39 @@ + + + + + + + + + StackOverflow-lite + + +
+
+
+

StackOverflow-lite

+
+ {% with messages =get_flashed_messages() %}{% if messages %} +
    + {% for message in messages %} +
  • {{ message }}
  • + {% endfor %} +
+ {% endif %}{% endwith %} +
+
+ + {% block content %}{% endblock%} + +
+

StackOverflow-lite © 2018

+
+ + \ No newline at end of file diff --git a/app/templates/login.html b/app/templates/login.html new file mode 100644 index 0000000..48f2a5d --- /dev/null +++ b/app/templates/login.html @@ -0,0 +1,32 @@ +{% extends 'layout.html' %} + +{% block content %} + +
+
+
+ +

Sign in

+
+

Username

+

+ +

Email

+

+ +

Password

+

+ +

+
+

Remember me

+

+
+ +
+
+
+ +
+{% endblock %} diff --git a/app/templates/question.html b/app/templates/question.html new file mode 100644 index 0000000..f641485 --- /dev/null +++ b/app/templates/question.html @@ -0,0 +1,48 @@ +{% extends 'layout2.html' %} + +{% block content %} +
+
+
+ {% for question in questions %}{% if question['questionId'] == qId %} +

+ Topic :{{question['topic']}}
+ {{question['body']}}
+



+ {% endif %}{% endfor %} +

Answers

+ {% for answer in answersL %} +

user {{answer['answerId']}} answered:


+ {{answer['body']}} +



+ {% endfor %} +
+
+ +
+
+
+

Answer Question

+
+

+ {{form.Qn_Id.label}}
+ {{form.Qn_Id(size=32)}}
+ {% for error in form.Qn_Id.errors %} + [{{error}}] + {% endfor %} +

+

+ {{form.body.label}}
+ {{form.body}}
+ {% for error in form.body.errors %} + [{{error}}] + {% endfor %} +

+ +
+
+
+ +
+
+{% endblock %} \ No newline at end of file diff --git a/app/templates/signUp.html b/app/templates/signUp.html new file mode 100644 index 0000000..84485c1 --- /dev/null +++ b/app/templates/signUp.html @@ -0,0 +1,56 @@ + + + + + + + + + StackOverflow-lite + + +
+
+
+

StackOverflow-lite

+
+ +
+
+ +
+
+
+

Sign up

+
+

Username

+

+ +

Email

+

+ +

Password

+

+ +

Repeat Password

+

+ +

+

Already have an account?Sign in

+
+
+
+ +
+ +
+

StackOverflow-lite © 2018

+
+ + \ No newline at end of file diff --git a/app/templates/user.html b/app/templates/user.html new file mode 100644 index 0000000..ac9cc58 --- /dev/null +++ b/app/templates/user.html @@ -0,0 +1,66 @@ + + + + + + + + + StackOverflow-lite + + +
+
+
+

StackOverflow-lite

+
+ +
+
+
+
+
+
+

Username

+


+
+

Number of answers given: 20

+

Number of guestions asked: 15

+
+
+
+ + +
+ + + \ No newline at end of file diff --git a/config.py b/config.py new file mode 100644 index 0000000..e4666ff --- /dev/null +++ b/config.py @@ -0,0 +1,6 @@ +import os +basedir = os.path.abspath(os.path.dirname(__file__)) + + +class Config(object): + SECRET_KEY = os.environ.get('SECRET_KEY') or 'tesxting' \ No newline at end of file diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..af2a776 --- /dev/null +++ b/requirements.txt @@ -0,0 +1,12 @@ +nose==1.3.7 +coverage==4.0.3 +coveralls==1.3.0 +Flask==1.0.2 +Flask-Testing==0.7.1 +gunicorn==19.9.0 +pep8==1.7.1 +pylint==2.1.1 +pytest==3.7.1 +python-coveralls==2.9.1 +requests==2.19.1 +Werkzeug==0.14.1 \ No newline at end of file diff --git a/run.py b/run.py new file mode 100644 index 0000000..f886ac8 --- /dev/null +++ b/run.py @@ -0,0 +1,5 @@ +from app import app +from app.routes import routes + +if __name__=='__main__': + app.run(port=5000) \ No newline at end of file diff --git a/tests/__init__.py b/tests/__init__.py new file mode 100644 index 0000000..02038d6 --- /dev/null +++ b/tests/__init__.py @@ -0,0 +1,4 @@ +from app import app +from config import Config + +app.config.from_object(Config) diff --git a/tests/base.py b/tests/base.py new file mode 100644 index 0000000..f2c0db4 --- /dev/null +++ b/tests/base.py @@ -0,0 +1,23 @@ +import unittest + +from flask import current_app +from flask_testing import TestCase + +from app import app +from app.routes import routes +from config import Config + + +class APITestCase(TestCase): + def create_app(self): + app.config['DEBUG'] = True + return app + + def setUp(self): + self.app = app.test_client() + + def tearDown(self): + pass + + def post_question(self): + pass diff --git a/tests/test_models.py b/tests/test_models.py new file mode 100644 index 0000000..32854f3 --- /dev/null +++ b/tests/test_models.py @@ -0,0 +1,39 @@ +from flask import json + +from app.models import Answer, Question, answersList, questionsList +from tests import app + +from .base import APITestCase + + +class TestModels(APITestCase): + + def setUp(self): + self.question1 = Question(1, 'computers', 'what is python ?') + self.answer1 = Answer(1, 'it is a programming language', 1) + self.question1.answers.append(self.answer1.__repr__()) + + def test_answerList_created_properly(self): + self.assertEqual(5, len(answersList)) + for answer in answersList: + self.assertIn('answerId', answer) + self.assertIn('body', answer) + self.assertIn('Qn_Id', answer) + + def test_questionsList_created_properly(self): + self.assertEqual(5, len(questionsList)) + for question in questionsList: + self.assertIn('questionId', question) + self.assertIn('topic', question) + self.assertIn('body', question) + + def test_questionObject_has_answers_attribute(self): + self.assertTrue(self.question1.answers) + self.assertTrue(type(self.question1.answers) == list) + self.assertTrue(type(self.question1.answers[0]) == dict) + + def test_repr_turnsObject_into_dict(self): + res1 = self.answer1.__repr__() + res2 = self.question1.__repr__() + self.assertTrue(type(res1)) + self.assertTrue(type(res2)) diff --git a/tests/test_route.py b/tests/test_route.py new file mode 100644 index 0000000..27f4d19 --- /dev/null +++ b/tests/test_route.py @@ -0,0 +1,55 @@ +from flask import json + +from app.models import answersList, questionsList +from tests import app + +from .base import APITestCase + + +class TestRoutes(APITestCase): + + def test_user_can_get_questions(self): + with self.client: + res = self.client.get('/api/v1/questions') + self.assertEqual(res.status_code, 200) + + def test_user_can_get_question(self): + res = self.client.get('/api/v1/questions/2') + self.assertEqual(res.status_code, 200) + + def test_user_can_post_question(self): + question = { + "questionId": 34, + "topic": "computer science", + "body": "what is software?" + } + res = self.client.post('/api/v1/questions', json=question) + self.assertEqual(res.status_code, 201) + + def test_user_post_answer(self): + answer = { + "answerId": 34, + "body": "what is software?", + "Qn_Id": 2 + } + res = self.client.post('/api/v1/questions/4/answers', json=answer) + self.assertEqual(res.status_code, 201) + + def test_user_can_update_question(self): + + new_question = { + "topic": "computer science", + "body": "what is software?" + } + res = self.client.patch('/api/v1/questions/4', json=new_question) + self.assertEqual(res.status_code, 204) + ids = [question['questionId'] for question in questionsList] + if 4 not in ids: + res = self.client.path('/api/v1/questions/4', json=new_question) + self.assertEqual(res.status_code, 404) + + def test_user_can_delete_question(self): + res = self.client.delete('/api/v1/questions/5') + ids = [question['questionId'] for question in questionsList] + if 5 in ids: + self.assertEqual(res.status_code, 200)