Skip to content

Commit 00111e7

Browse files
committed
Create video service
1 parent dac6332 commit 00111e7

File tree

13 files changed

+363
-0
lines changed

13 files changed

+363
-0
lines changed

video_service/requirements.txt

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
Flask==2.0.1
2+
Flask-And-Redis==1.0.0
3+
Flask-Cors==3.0.10
4+
Flask-JWT-Extended==3.24.0
5+
Flask-SQLAlchemy==2.5.1
6+
Flask-Migrate==3.1.0
7+
gunicorn==20.1.0
8+
Jinja2==3.0.1
9+
marshmallow==3.12.2
10+
greenlet==1.1.0
11+
SQLAlchemy==1.4.21
12+
mysqlclient==2.0.3
13+
Werkzeug==2.0.1
14+
pytz==2021.1
15+
MarkupSafe==2.0.1
16+
PyJWT==1.7.1

video_service/server.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
from video_app.app import create_app
2+
3+
app = create_app()
4+
if __name__ == '__main__':
5+
"""
6+
Main Video Application
7+
python manage.py
8+
"""
9+
app.run(host='0.0.0.0', port=5012)

video_service/video_app/__init__.py

Whitespace-only changes.
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
import os
2+
from flask import jsonify
3+
from video_app.settings import ProdConfig, StgConfig
4+
5+
CONFIG = ProdConfig if os.environ.get('ENV') == 'prd' else StgConfig
6+
7+
8+
def send_result(data: any = None, message: str = "OK", code: int = 200,
9+
status: str = 'success', show: bool = False, duration: int = 0):
10+
"""
11+
Args:
12+
:param data: whatever you want
13+
:param message: error message
14+
:param code: 200 is success
15+
:param status: error
16+
:param show: show popup or not (useful for Frontend team)
17+
:param duration: show popup for duration second
18+
:return:
19+
"""
20+
message_dict = {
21+
"text": message,
22+
"status": status,
23+
"show": show,
24+
"duration": duration,
25+
}
26+
res = {
27+
"code": code,
28+
"data": data,
29+
"message": message_dict,
30+
}
31+
32+
return jsonify(res), 200
33+
34+
35+
def send_error(data: any = None, message: str = "Error", code: int = 200,
36+
status: str = 'error', show: bool = False, duration: int = 0):
37+
"""
38+
Args:
39+
:param data: whatever you want
40+
:param message: error message
41+
:param code: you can use 4xx
42+
:param status: error
43+
:param show: show popup or not (useful for Frontend team)
44+
:param duration: show popup for duration second
45+
:return:
46+
"""
47+
message_dict = {
48+
"text": message,
49+
"status": status,
50+
"show": show,
51+
"duration": duration,
52+
}
53+
res = {
54+
"code": code,
55+
"data": data,
56+
"message": message_dict,
57+
}
58+
59+
return jsonify(res), code
60+
61+
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
from video_app.api.v1 import video
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
import json
2+
import uuid
3+
4+
from flask import Blueprint, request
5+
from video_app.utils import logged_input, get_timestamp_now
6+
from video_app.validator import CreateVideoSchema, VideoSchema
7+
from video_app.models import Video
8+
from video_app.api.helper import send_error, send_result
9+
from video_app.extensions import db
10+
11+
12+
api = Blueprint('videos', __name__)
13+
14+
15+
@api.route('', methods=['GET'])
16+
def search_videos():
17+
"""
18+
Search video api
19+
Requests params:
20+
keyword: string, optional
21+
Returns:
22+
list videos
23+
"""
24+
25+
keyword = request.args.get('keyword', '').strip()
26+
videos = Video.query.filter(Video.title.ilike(f'%{keyword}%')).all()
27+
videos_dumped = VideoSchema(many=True).dumps(videos)
28+
return send_result(data=json.loads(videos_dumped))
29+
30+
31+
@api.route('', methods=['POST'])
32+
def create_new_video():
33+
"""
34+
Create new video API.
35+
Requests Body:
36+
title: string, require
37+
url: string, optional
38+
thumbnail_url: string, optional
39+
Returns:
40+
id of new video
41+
"""
42+
43+
try:
44+
json_req = request.get_json()
45+
except Exception as ex:
46+
return send_error(message="Request Body incorrect json format: " + str(ex), code=442)
47+
48+
logged_input(json.dumps(json_req))
49+
if json_req is None:
50+
return send_error(message='Please check your json requests', code=442)
51+
52+
# trim input body
53+
json_body = {}
54+
for key, value in json_req.items():
55+
json_body.setdefault(key, str(value).strip())
56+
57+
# validate request body
58+
is_not_validate = CreateVideoSchema().validate(json_body) # Dictionary show detail error fields
59+
if is_not_validate:
60+
return send_error(data=is_not_validate, message="Invalid params")
61+
62+
title = json_body.get("title")
63+
url = json_body.get("url", "")
64+
thumbnail_url = json_body.get("thumbnail_url", "")
65+
_id = str(uuid.uuid4())
66+
# Store video to db
67+
new_video = Video(id=_id, title=title, url=url, thumbnail_url=thumbnail_url)
68+
db.session.add(new_video)
69+
db.session.commit()
70+
data = {
71+
"video_id": _id
72+
}
73+
return send_result(data)

video_service/video_app/app.py

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
# -*- coding: utf-8 -*-
2+
3+
from flask import Flask
4+
from video_app.api.helper import CONFIG
5+
from video_app.extensions import db, migrate
6+
from .api import v1 as api_v1
7+
from video_app.models import Video # Must have to migrate db
8+
9+
10+
def create_app(config_object=CONFIG):
11+
"""
12+
Init App
13+
:param config_object:
14+
:return:
15+
"""
16+
app = Flask(__name__, static_url_path="", static_folder="./static-files")
17+
app.config.from_object(config_object)
18+
register_extensions(app)
19+
register_blueprints(app)
20+
return app
21+
22+
23+
def register_extensions(app):
24+
"""
25+
Init extension
26+
:param app:
27+
:return:
28+
"""
29+
30+
db.app = app
31+
db.init_app(app) # SQLAlchemy
32+
migrate.init_app(app, db)
33+
34+
35+
def register_blueprints(app):
36+
"""
37+
Init blueprint for api url
38+
:param app:
39+
:return:
40+
"""
41+
app.register_blueprint(api_v1.video.api, url_prefix='/api/v1/videos')

video_service/video_app/enums.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
# coding: utf-8
2+
TIME_FORMAT_LOG = "[%Y-%b-%d %H:%M]"
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
import logging
2+
import os
3+
from flask_sqlalchemy import SQLAlchemy
4+
from flask_migrate import Migrate
5+
from logging.handlers import RotatingFileHandler
6+
7+
8+
# init SQLAlchemy
9+
db = SQLAlchemy()
10+
migrate = Migrate()
11+
12+
os.makedirs("logs", exist_ok=True)
13+
app_log_handler = RotatingFileHandler('logs/app.log', maxBytes=1000000, backupCount=30, encoding="UTF-8")
14+
15+
# logger
16+
logger = logging.getLogger('api')
17+
logger.setLevel(logging.DEBUG)
18+
logger.addHandler(app_log_handler)

video_service/video_app/models.py

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
# coding: utf-8
2+
from sqlalchemy.dialects.mysql import INTEGER
3+
from video_app.extensions import db
4+
from video_app.utils import get_timestamp_now
5+
6+
7+
class Video(db.Model):
8+
__tablename__ = 'video'
9+
10+
id = db.Column(db.String(50), primary_key=True)
11+
title = db.Column(db.String(500), primary_key=True)
12+
url = db.Column(db.String(1000))
13+
thumbnail_url = db.Column(db.String(1000))
14+
created_date = db.Column(INTEGER(unsigned=True), default=get_timestamp_now(), index=True)
15+
modified_date = db.Column(INTEGER(unsigned=True), default=0)
16+
is_deleted = db.Column(db.Boolean, default=0)
17+
is_active = db.Column(db.Boolean, default=1)

0 commit comments

Comments
 (0)