forked from dead-repos/op-api
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathapp.py
170 lines (140 loc) · 4.71 KB
/
app.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
from sanic import Sanic
from sanic import response as res
from sanic import exceptions as exc
import argon2
import random, string, json
app = Sanic('codeecho')
ph = argon2.PasswordHasher()
config = {}
with open("config.json") as data:
config = json.loads(data.read())
data.close()
@app.listener('before_server_start')
def init(sanic, loop):
"""Initialize database before server starts"""
global db
from motor.motor_asyncio import AsyncIOMotorClient
db = AsyncIOMotorClient(
host=config.get('mongo_host', 'localhost'),
port=config.get('mongo_port', 27017)
)[config.get('mongo_db_name', 'codeecho')]
@app.route('/api/auth', methods=['POST'])
async def auth_handler(request):
"""Handles authentication requests"""
req = request.json
if not req:
raise exc.InvalidUsage("Bad request")
# Ensure required data is included in the request
username = req.get('username')
password = req.get('password')
if not (username and password):
raise exc.InvalidUsage("Bad request")
# Ensure user exists in database
user = await db['users'].find_one({ "username": username })
if not user:
raise exc.Forbidden("Invalid credentials")
# Ensure password is correct
try:
ph.verify(user['password'], password)
except argon2.exceptions.VerifyMismatchError:
raise exc.Forbidden("Invalid credentials")
except argon2.exceptions.VerificationError:
raise exc.ServerError("Password verification failed")
return res.json({
"id": str(user['_id']),
"username": user['username'],
"email": user['email'],
"token": user['token']
})
@app.route('/api/user', methods=['POST'])
async def new_user_handler(request):
"""Handles requests for new users"""
req = request.json
if not req:
raise exc.InvalidUsage("Bad request")
# Ensure required data is included in the request
username = req.get('username')
email = req.get('email')
password = req.get('password')
if not (username and email and password):
raise exc.InvalidUsage("Bad request")
# Ensure user does not already exist in database
user = await db['users'].find_one({ "username": username })
if user is not None:
return res.json({ "message": "A user with this username already exists", "status": 409 })
user = await db['users'].find_one({ "email": email })
if user is not None:
return res.json({ "message": "A user with this email already exists", "status": 409 })
# Hash password
hashed_pass = ph.hash(password)
# Generate new token
token = ''.join(random.SystemRandom().choice(string.ascii_letters + string.digits) for i in range(25))
# Insert user into database
user = await db['users'].insert_one({
"username": username,
"email": email,
"password": hashed_pass,
"token": token
})
# Send response
return res.json({
"id": str(user.inserted_id),
"username": username,
"email": email,
"token": token
})
@app.route('/api/user/<user_id:int>', methods=['GET', 'POST'])
async def user_handler(req, user_id):
"""TODO Handles requests for existing users"""
if not user_id:
raise exc.InvalidUsage("Bad request")
#if req.method == 'GET':
raise exc.NotFound("Soon™")
# Create new repo
@app.route('/api/repositories', methods=['POST'])
async def create_repo(req):
"""TODO New repo"""
raise exc.NotFound("Soon™")
# Get repo
@app.route('/api/repositories/<repo_id:int>', methods=['GET'])
async def get_repo(req, repo_id):
"""Handles requests for existing repositories"""
if not repo_id:
raise exc.InvalidUsage("Bad request")
repo = await db['repos'].find_one({ "_id": repo_id })
if not repo:
raise exc.NotFound("Resource not found")
# Temporary confirmation
return res.json({ "message": f"You've requested repository ID {repo_id}" })
# Update repo
@app.route('/api/repositories/<repo_id:int>/update', methods=['POST'])
async def update_repo(req, repo_id):
if not repo_id:
raise exc.InvalidUsage("Bad request")
# TODO auth check
repo = await db['repos'].find_one({ "_id": repo_id })
if not repo:
raise exc.Forbidden("Repository doesn't exist")
else:
# TODO Update repo
pass
# Temporary
return res.json({ "message": "TODO" })
# Delete repo
@app.route('/api/repositories/<repo_id:int>/delete', methods=['DELETE'])
async def delete_repo(req, repo_id):
if not repo_id:
raise exc.InvalidUsage("Bad request")
# TODO auth check
repo = await db['repos'].find_one({ "_id": repo_id })
if not repo:
raise exc.Forbidden("Repository doesn't exist")
else:
# TODO delete repo
pass
# Temporary
return res.json({ "message": "TODO" })
@app.exception(exc.SanicException)
def errors(request, exception):
"""Handles errors"""
return res.json({ "error": exception.args[0], "status": exception.status_code })