Compare commits

...

14 Commits

Author SHA1 Message Date
fbd25db750 dont print
All checks were successful
continuous-integration/drone/push Build is passing
2020-11-29 19:15:12 +01:00
2e31e99aae final final final
All checks were successful
continuous-integration/drone/push Build is passing
2020-11-29 02:05:44 +01:00
c18dbb8d06 Update 'src/utils/healthchecks.py'
All checks were successful
continuous-integration/drone/push Build is passing
2020-11-29 01:04:08 +01:00
5f2f73c9df clean app.py
All checks were successful
continuous-integration/drone/push Build is passing
2020-11-29 01:00:45 +01:00
ea76463739 minor fix
All checks were successful
continuous-integration/drone/push Build is passing
2020-11-28 21:32:38 +01:00
73c1636063 minor redis adjustments
All checks were successful
continuous-integration/drone/push Build is passing
2020-11-28 20:17:17 +01:00
791003f89e expire token after 15 min
All checks were successful
continuous-integration/drone Build is passing
continuous-integration/drone/push Build is passing
2020-11-27 06:04:46 +01:00
aab6e3e3cd fix spotify query of albums
All checks were successful
continuous-integration/drone/push Build is passing
2020-11-27 02:48:11 +01:00
bf8759d176 increase performance
All checks were successful
continuous-integration/drone/push Build is passing
2020-11-27 02:34:06 +01:00
d62ad11de9 releases still dont have title
All checks were successful
continuous-integration/drone/push Build is passing
2020-11-27 02:14:40 +01:00
e81c50a4b1 releases do not have title
All checks were successful
continuous-integration/drone/push Build is passing
2020-11-27 02:09:01 +01:00
2b1650b36e it is a secret
All checks were successful
continuous-integration/drone/push Build is passing
2020-11-27 01:56:27 +01:00
6e1a283f2c fix commend
All checks were successful
continuous-integration/drone/push Build is passing
2020-11-27 00:32:28 +01:00
183ffadad6 even more generic
All checks were successful
continuous-integration/drone/push Build is passing
2020-11-27 00:28:31 +01:00
12 changed files with 70 additions and 76 deletions

View File

@ -16,4 +16,4 @@ COPY ./src .
EXPOSE 8080 EXPOSE 8080
ENTRYPOINT ["gunicorn", "-b", "0.0.0.0:8080", "--workers", "1", "--threads", "1", "app:app"] ENTRYPOINT ["gunicorn", "-b", "0.0.0.0:8080", "--workers", "4", "--threads", "1", "app:app"]

View File

@ -1,28 +0,0 @@
version: '3'
networks:
backend:
external: false
services:
backend:
image: registry.kmlabz.com/onspot/backend
restart: always
depends_on:
- db
environment:
- ONSPOT_REDIS_URL=redis://db:6379/0
- ONSPOT_ENCODED_SECRET_KEY=emdlc2RmYnZoa2xyYWl3ZmJkdmtzZ2Vhd2ZiaWx2a3M=
- ONSPOT_SPOTIFY_CLIENT_ID=CHANGEME
- ONSPOT_SPOTIFY_CLIENT_SECRET=KEEPMESECRET
ports:
- "127.0.0.1:8080:8080"
networks:
- backend
db:
image: redis
restart: always
ports:
- "127.0.0.1:6379:6379"
networks:
- backend

View File

@ -1,18 +1,18 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
import logging
import musicbrainzngs import musicbrainzngs
from flask import Flask from flask import Flask
from flask_restful import Api from flask_restful import Api
from flask_cors import CORS from flask_cors import CORS
import sentry_sdk import sentry_sdk
from sentry_sdk.integrations.flask import FlaskIntegration from sentry_sdk.integrations.flask import FlaskIntegration
from sentry_sdk.integrations.redis import RedisIntegration
from healthcheck import HealthCheck from healthcheck import HealthCheck
from flaskaddons.marshm import ma from flaskaddons.marshm import ma
from flaskaddons.fred import flaskred from flaskaddons.fred import flaskred
from utils.config import SENTRY_DSN, RELEASEMODE, RELEASE_ID, PORT, DEBUG, REDIS_URL, ALLOWED_ORIGINS from utils.config import SENTRY_DSN, RELEASEMODE, RELEASE_ID, REDIS_URL, ALLOWED_ORIGINS
from utils.errorhandlers import register_all_error_handlers from utils import register_all_error_handlers, redis_available
from resources import LoginApi, ListsApi, MeApi, SingleListApi, ItemApi from resources import LoginApi, ListsApi, MeApi, SingleListApi, ItemApi
""" """
@ -27,7 +27,7 @@ __version__text__ = "1"
if SENTRY_DSN: if SENTRY_DSN:
sentry_sdk.init( sentry_sdk.init(
dsn=SENTRY_DSN, dsn=SENTRY_DSN,
integrations=[FlaskIntegration()], integrations=[FlaskIntegration(), RedisIntegration()],
traces_sample_rate=1.0, traces_sample_rate=1.0,
send_default_pii=True, send_default_pii=True,
release=RELEASE_ID, release=RELEASE_ID,
@ -36,8 +36,6 @@ if SENTRY_DSN:
) )
app = Flask(__name__) app = Flask(__name__)
app.config['JWT_BLACKLIST_ENABLED'] = True
app.config['JWT_BLACKLIST_TOKEN_CHECKS'] = ['access', 'refresh']
app.config['REDIS_URL'] = REDIS_URL app.config['REDIS_URL'] = REDIS_URL
api = Api(app) api = Api(app)
health = HealthCheck() health = HealthCheck()
@ -45,10 +43,6 @@ ma.init_app(app)
flaskred.init_app(app) flaskred.init_app(app)
CORS(app, origins=ALLOWED_ORIGINS) CORS(app, origins=ALLOWED_ORIGINS)
formatter = logging.Formatter(
fmt="%(asctime)s - %(levelname)s - %(module)s - %(message)s"
)
@app.before_first_request @app.before_first_request
def before_first_request(): def before_first_request():
@ -57,26 +51,13 @@ def before_first_request():
musicbrainzngs.https = True musicbrainzngs.https = True
handler = logging.StreamHandler()
handler.setFormatter(formatter)
logger = logging.getLogger(__name__)
logger.setLevel(logging.DEBUG)
logger.addHandler(handler)
api.add_resource(LoginApi, '/api/auth/login') api.add_resource(LoginApi, '/api/auth/login')
api.add_resource(MeApi, '/api/auth/me') api.add_resource(MeApi, '/api/auth/me')
api.add_resource(ListsApi, '/api/lists') api.add_resource(ListsApi, '/api/lists')
api.add_resource(SingleListApi, '/api/lists/<listid>') api.add_resource(SingleListApi, '/api/lists/<listid>')
api.add_resource(ItemApi, '/api/items/<itemid>') api.add_resource(ItemApi, '/api/items/<itemid>')
health.add_check(redis_available)
app.add_url_rule("/healthz", "healthcheck", view_func=lambda: health.run()) app.add_url_rule("/healthz", "healthcheck", view_func=lambda: health.run())
register_all_error_handlers(app) register_all_error_handlers(app)
if __name__ == "__main__":
app.run(
debug=bool(DEBUG),
host="0.0.0.0",
port=int(PORT),
)

View File

@ -1,5 +1,5 @@
""" """
Base resource with user handling and Spotify integration Base resource with user handling, Spotify and MusicBrains integration
""" """
__author__ = '@tormakris' __author__ = '@tormakris'
@ -30,10 +30,9 @@ class APIInteractionResource(UserStoreResource):
spotify_uri += "artist:" spotify_uri += "artist:"
imagedata = spot_data[0]['images'] imagedata = spot_data[0]['images']
elif mb_type == "release": elif mb_type == "release":
spot_data = self.spotify.search(q=querystring, type="artist", limit=1).get('albums') spot_data = self.spotify.search(q=querystring, type="album", limit=1)['albums']['items']
if not spot_data: if not spot_data:
return None, None, None return None, None, None
spot_data = spot_data['items']
spotify_uri += "album:" spotify_uri += "album:"
imagedata = spot_data[0]['images'] imagedata = spot_data[0]['images']
elif mb_type == "work" or mb_type == "recording": elif mb_type == "work" or mb_type == "recording":
@ -51,13 +50,29 @@ class APIInteractionResource(UserStoreResource):
else: else:
return spotify_uri, None, None return spotify_uri, None, None
def getcoverimage(self, releaseid: str, itemtype: str, artist: str, title: str = "",
album: str = "") -> tuple:
if itemtype != "recording" and itemtype != "release":
return None, None
try:
musicbimgurl = musicbrainzngs.get_image_list(releaseid)['images']
imgurl = musicbimgurl[0]['thumbnails']['large']
smallimgurl = musicbimgurl[0]['thumbnails']['small']
except Exception as e:
_, imgurl, smallimgurl = self.queryspotifyinfo(itemtype, title=title, album=album, artist=artist)
current_app.logger.info(e)
return imgurl, smallimgurl
def getreleaseinfo(self, itemid: str) -> dict: def getreleaseinfo(self, itemid: str) -> dict:
currrelease = musicbrainzngs.get_release_by_id(itemid, includes=['artists'])['release'] currrelease = musicbrainzngs.get_release_by_id(itemid, includes=['artists'])['release']
retdata = {"id": itemid, "album": currrelease['title'], "type": "release"} retdata = {"id": itemid, "album": currrelease['title'], "type": "release"}
if 'artist-credit' in currrelease and currrelease['artist-credit']: if 'artist-credit' in currrelease and currrelease['artist-credit']:
retdata['artist'] = currrelease['artist-credit'][0]['artist']['name'] retdata['artist'] = currrelease['artist-credit'][0]['artist']['name']
retdata['spotify_id'], retdata['cover_url'], retdata['cover_url_small'] = \ retdata['cover_url'], retdata['cover_url_small'] = self.getcoverimage(
self.queryspotifyinfo('release', artist=retdata['artist'], album=retdata['album']) itemid, 'release', album=retdata.get('album'),
artist=retdata.get('artist'))
retdata['spotify_id'], _, _ = \
self.queryspotifyinfo('release', album=currrelease['title'])
return retdata return retdata
def getartistinfo(self, itemid: str) -> dict: def getartistinfo(self, itemid: str) -> dict:
@ -83,17 +98,12 @@ class APIInteractionResource(UserStoreResource):
if 'release-list' in currrecording and currrecording['release-list']: if 'release-list' in currrecording and currrecording['release-list']:
currrlease = currrecording['release-list'][0] currrlease = currrecording['release-list'][0]
retdata['album'] = currrlease['title'] retdata['album'] = currrlease['title']
try: imageid = currrlease['id']
imgurl = musicbrainzngs.get_image_list(currrlease['id'])['images'] else:
if imgurl: imageid = itemid
retdata['cover_url_small'] = imgurl[0]['thumbnails']['small'] retdata['cover_url'], retdata['cover_url_small'] = self.getcoverimage(
retdata['cover_url'] = imgurl[0]['thumbnails']['large'] imageid, 'release', title=retdata['title'],
artist=retdata.get('artist'))
retdata['spotify_id'], _, _ = \ retdata['spotify_id'], _, _ = \
self.queryspotifyinfo('recording', title=retdata['title'], album=retdata.get('album'), self.queryspotifyinfo('recording', title=retdata['title'])
artist=retdata.get('artist'))
except Exception as e:
retdata['spotify_id'], retdata['cover_url'], retdata['cover_url_small'] = \
self.queryspotifyinfo('recording', title=retdata['title'], album=retdata.get('album'),
artist=retdata.get('artist'))
current_app.logger.info(e)
return retdata return retdata

View File

@ -7,6 +7,8 @@ __copyright__ = "Copyright 2020, onSpot Team"
__module_name__ = "itemapi" __module_name__ = "itemapi"
__version__text__ = "1" __version__text__ = "1"
from datetime import timedelta
from flask import request, current_app, abort from flask import request, current_app, abort
from flaskaddons.fred import flaskred from flaskaddons.fred import flaskred
@ -24,6 +26,8 @@ class ItemApi(APIInteractionResource):
except Exception as e: except Exception as e:
current_app.logger.info(e) current_app.logger.info(e)
abort(401, "unauthorized") abort(401, "unauthorized")
flaskred.expire(request.headers.get('Authorization'), timedelta(minutes=15))
try: try:
itemtype = flaskred.get(itemid).decode('UTF-8') itemtype = flaskred.get(itemid).decode('UTF-8')
except Exception as e: except Exception as e:

View File

@ -7,6 +7,8 @@ __copyright__ = "Copyright 2020, onSpot Team"
__module_name__ = "listsapi" __module_name__ = "listsapi"
__version__text__ = "1" __version__text__ = "1"
from datetime import timedelta
import musicbrainzngs import musicbrainzngs
from flask import current_app, abort, request from flask import current_app, abort, request
@ -26,6 +28,8 @@ class ListsApi(UserStoreResource):
current_app.logger.info(e) current_app.logger.info(e)
abort(401, "unauthorized") abort(401, "unauthorized")
flaskred.expire(request.headers.get('Authorization'), timedelta(minutes=15))
musicbrainzngs.auth(currcreds['name'], currcreds['password']) musicbrainzngs.auth(currcreds['name'], currcreds['password'])
collections = musicbrainzngs.get_collections() collections = musicbrainzngs.get_collections()
musicbrainzngs.auth(None, None) musicbrainzngs.auth(None, None)

View File

@ -8,6 +8,7 @@ __module_name__ = "loginapi"
__version__text__ = "1" __version__text__ = "1"
import uuid import uuid
from datetime import timedelta
import musicbrainzngs import musicbrainzngs
from flask import request, current_app, abort from flask import request, current_app, abort
@ -43,7 +44,7 @@ class LoginApi(UserStoreResource):
self.encryptor.store(body) self.encryptor.store(body)
token = str(uuid.uuid4()) token = str(uuid.uuid4())
flaskred.set(token, userobj['name'].encode('UTF-8')) flaskred.set(token, userobj['name'].encode('UTF-8'))
flaskred.expire(token, timedelta(minutes=15))
return { return {
'token': token 'token': token
}, 200 }, 200

View File

@ -7,6 +7,8 @@ __copyright__ = "Copyright 2020, onSpot Team"
__module_name__ = "meapi" __module_name__ = "meapi"
__version__text__ = "1" __version__text__ = "1"
from datetime import timedelta
from flask import request, current_app, abort from flask import request, current_app, abort
from flask_restful import Resource from flask_restful import Resource
@ -24,4 +26,5 @@ class MeApi(Resource):
except Exception as e: except Exception as e:
current_app.logger.info(e) current_app.logger.info(e)
abort(401, "unauthorized") abort(401, "unauthorized")
flaskred.expire(request.headers.get('Authorization'), timedelta(minutes=15))
return {"name": currusername}, 200 return {"name": currusername}, 200

View File

@ -7,6 +7,8 @@ __copyright__ = "Copyright 2020, onSpot Team"
__module_name__ = "singlelistapi" __module_name__ = "singlelistapi"
__version__text__ = "1" __version__text__ = "1"
from datetime import timedelta
import musicbrainzngs import musicbrainzngs
from flask import request, current_app, abort from flask import request, current_app, abort
@ -25,6 +27,7 @@ class SingleListApi(APIInteractionResource):
except Exception as e: except Exception as e:
current_app.logger.info(e) current_app.logger.info(e)
abort(401, "unauthorized") abort(401, "unauthorized")
flaskred.expire(request.headers.get('Authorization'), timedelta(minutes=15))
try: try:
list_type = flaskred.get(listid).decode('UTF-8') list_type = flaskred.get(listid).decode('UTF-8')
except Exception as e: except Exception as e:

View File

@ -1 +1,3 @@
from .aes_encrypt import AESCrypto from .aes_encrypt import AESCrypto
from .healthchecks import redis_available
from .errorhandlers import register_all_error_handlers

View File

@ -5,15 +5,11 @@ import os
Configuration Configuration
""" """
__author__ = "@tormakris" __author__ = "@tormakris"
__copyright__ = "Copyright 2020, onSpot Team" __copyright__ = "Copyright 2020, onSpot Team"
__module_name__ = "config" __module_name__ = "config"
__version__text__ = "1" __version__text__ = "1"
PORT = os.environ.get("ONSPOT_PORT", 8080)
DEBUG = os.environ.get("ONSPOT_DEBUG", True)
ALLOWED_ORIGINS = os.environ.get('ALLOWED_ORIGINS', '*') ALLOWED_ORIGINS = os.environ.get('ALLOWED_ORIGINS', '*')
SENTRY_DSN = os.environ.get("SENTRY_DSN") SENTRY_DSN = os.environ.get("SENTRY_DSN")

18
src/utils/healthchecks.py Normal file
View File

@ -0,0 +1,18 @@
#!/usr/bin/env python3
from flaskaddons import flaskred
"""
Healthchek functions
"""
__author__ = "@tormakris"
__copyright__ = "Copyright 2020, onSpot Team"
__module_name__ = "healthchecks"
__version__text__ = "1"
def redis_available():
redisstatus=flaskred.info()
return True, redisstatus