Skip to content

Commit

Permalink
Merge pull request #21 from R-Mielamud/dev
Browse files Browse the repository at this point in the history
Catalog + site admin release
  • Loading branch information
R-Mielamud authored Mar 7, 2021
2 parents 1ff0f70 + adb39cd commit 6449816
Show file tree
Hide file tree
Showing 135 changed files with 29,019 additions and 143 deletions.
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -127,3 +127,6 @@ dmypy.json

# Pyre type checker
.pyre/

# Redis
*.rdb
6 changes: 6 additions & 0 deletions Nicolaus/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
from __future__ import absolute_import

# Celery
from .celery import app as celery_app
import book_filters.celery
import books.celery
14 changes: 14 additions & 0 deletions Nicolaus/celery.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
from __future__ import absolute_import
import os
from celery import Celery
from Nicolaus import settings

os.environ.setdefault("DJANGO_SETTINGS_MODULE", "Nicolaus.settings")
app = Celery("Nicolaus")

app.config_from_object("django.conf:settings")
app.autodiscover_tasks(lambda: settings.INSTALLED_APPS)

@app.task(bind=True)
def debug_task(self):
print("Request: {0!r}".format(self.request))
50 changes: 45 additions & 5 deletions Nicolaus/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,8 @@
"rest_framework",
"api",
"authorization",
"book_filters",
"books",
]

MIDDLEWARE = [
Expand All @@ -56,7 +58,9 @@
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
"authorization.middleware.extract_user_from_jwt",
"authorization.middleware.extract_auth_token",
"authorization.middleware.extract_user",
"authorization.middleware.process_permissions",
]

ROOT_URLCONF = 'Nicolaus.urls'
Expand Down Expand Up @@ -160,10 +164,20 @@

JWT_PREFIX = "Bearer "

JWT_ROUTES_WHITELIST = [
"/api/user/register/",
"/api/user/login/",
]
ALLOW_ROUTES = {
"PUBLISH": [
r"^/api/user/register/$",
r"^/api/user/login/$",
],
"PUBLISH_GET": [
r"^/api/books/",
],
"FOR_ADMIN_MOD": [
r"^/api/books/",
r"^/api/books/filters/[a-zA-Z0-9]+/bulk/$",
r"^/api/books/filters/[a-zA-Z0-9]+/[a-zA-Z0-9]+/bulk/$",
],
}

# Cross-Origin Resource Sharing

Expand All @@ -182,3 +196,29 @@
"DELETE",
"OPTIONS",
]

# S3 File Uploading

AWS_ACCESS_KEY_ID = os.environ.get("AWS_ACCESS_KEY_ID", "")

AWS_SECRET_ACCESS_KEY = os.environ.get("AWS_SECRET_ACCESS_KEY", "")

AWS_S3_MEDIA_BUCKET = os.environ.get("AWS_S3_MEDIA_BUCKET", "")

AWS_S3_MEDIA_REGION = os.environ.get("AWS_S3_MEDIA_REGION", "")

AWS_S3_BOOK_IMAGE_KEY = "book_images"

# Celery Settings

BROKER_URL = "redis://localhost:6379"

CELERY_RESULT_URL = "redis://localhost:6379"

CELERY_ACCEPT_CONTENT = ["application/json"]

CELERY_TASK_SERIALIZER = "json"

CELERY_RESULT_SERIALIER = "json"

CELERY_TIMEZONE = "UTC"
1 change: 1 addition & 0 deletions api/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,5 @@

urlpatterns = [
path("user/", include("authorization.urls")),
path("books/", include("books.urls")),
]
74 changes: 62 additions & 12 deletions authorization/middleware.py
Original file line number Diff line number Diff line change
@@ -1,35 +1,85 @@
import re
from django.http import JsonResponse
from jwt import DecodeError
from Nicolaus import settings
from helpers import jwt
from .models import User

def extract_user_from_jwt(get_response):
def extract_auth_token(get_response):
def middleware(request):
def reject():
return JsonResponse({
"message": "Not authorized"
}, status=401)

if (not request.path.startswith("/api")) or (request.path in settings.JWT_ROUTES_WHITELIST):
if not request.path.startswith("/api"):
return get_response(request)

token = jwt.extract_token_from_request(request)
setattr(request, "auth_token", token)

return get_response(request)

return middleware

def extract_user(get_response):
def middleware(request):
if not request.path.startswith("/api"):
return get_response(request)

token = request.auth_token

if not token:
return reject()
request.user = None
return get_response(request)

try:
user_id = jwt.get_user_id(token)
except DecodeError:
return reject()
return JsonResponse({
"message": "Invalid JWT token",
}, status=401)

user = User.objects.filter(pk=user_id).first()
request.user = user

if not user:
return reject()
return get_response(request)

return middleware

def process_permissions(get_response):
def middleware(request):
path = request.path
is_get = request.method == "GET"

if request.GET.get("admin") == "1":
if not request.user:
return JsonResponse({
"message": "Not authorized",
}, status=401)
elif not request.user.is_admin:
return JsonResponse({
"message": "Permission denied",
}, status=403)

if not path.startswith("/api"):
return get_response(request)

for regex in settings.ALLOW_ROUTES["PUBLISH"]:
if re.match(regex, path):
return get_response(request)

if is_get:
for regex in settings.ALLOW_ROUTES["PUBLISH_GET"]:
if re.match(regex, path):
return get_response(request)

if not request.user:
return JsonResponse({
"message": "Not authorized",
}, status=401)
elif not request.user.is_admin:
for regex in settings.ALLOW_ROUTES["FOR_ADMIN_MOD"]:
if re.match(regex, path):
return JsonResponse({
"message": "Permission denied",
}, status=403)

setattr(request, "user", user)
return get_response(request)

return middleware
Empty file added book_filters/__init__.py
Empty file.
9 changes: 9 additions & 0 deletions book_filters/admin.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
from django.contrib import admin
from .models import TagGroup, Tag, Publishing, Author, Series, Status

admin.site.register(TagGroup)
admin.site.register(Tag)
admin.site.register(Publishing)
admin.site.register(Author)
admin.site.register(Series)
admin.site.register(Status)
5 changes: 5 additions & 0 deletions book_filters/apps.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
from django.apps import AppConfig


class BookFiltersConfig(AppConfig):
name = 'book_filters'
93 changes: 93 additions & 0 deletions book_filters/celery.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
from Nicolaus.celery import app

def bulk_update_model(Model, dataset, can_create=True):
fields = [f.name for f in Model._meta.get_fields()]
fetch_relations = None
fetch_m2m = None

if hasattr(Model, "id_to_relation"):
fetch_relations = getattr(Model, "id_to_relation")

if hasattr(Model, "id_to_m2m"):
fetch_m2m = getattr(Model, "id_to_m2m")

for datai in dataset:
f_id = datai.get("id")
change = datai.get("change")
copy = datai.copy()

if fetch_relations:
for name, Relation in fetch_relations.items():
pk = datai.get(name)

if pk is not None:
copy[name] = Relation.objects.filter(pk=pk).first()

for key in datai:
if key not in fields:
del copy[key]

datai = copy.copy()

if not f_id and can_create:
Model.objects.create(**datai)
continue

if change == 1:
try:
filter_obj = Model.objects.filter(pk=f_id)

if len(filter_obj) <= 0:
continue

update_data = datai.copy()

if fetch_m2m:
for key, Relation in fetch_m2m.items():
ids = datai.get(key)

if type(ids) == int:
ids = [ids]

if ids is not None:
objects = []

for pk in ids:
objects.append(Relation.objects.filter(pk=pk).first())

getattr(filter_obj.first(), key).set(objects)
del update_data[key]

filter_obj.update(**update_data)
except:
pass

@app.task()
def bulk_update_authors(dataset):
from .models import Author
bulk_update_model(Author, dataset)

@app.task()
def bulk_update_tag_groups(dataset):
from .models import TagGroup
bulk_update_model(TagGroup, dataset)

@app.task()
def bulk_update_publishings(dataset):
from .models import Publishing
bulk_update_model(Publishing, dataset)

@app.task()
def bulk_update_tags(dataset):
from .models import Tag
bulk_update_model(Tag, dataset)

@app.task()
def bulk_update_series(dataset):
from .models import Series
bulk_update_model(Series, dataset)

@app.task()
def bulk_update_statuses(dataset):
from .models import Status
bulk_update_model(Status, dataset)
30 changes: 30 additions & 0 deletions book_filters/migrations/0001_initial.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
# Generated by Django 3.1.5 on 2021-02-05 14:46

from django.db import migrations, models
import django.db.models.deletion


class Migration(migrations.Migration):

initial = True

dependencies = [
]

operations = [
migrations.CreateModel(
name='TagGroup',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('name', models.CharField(max_length=200)),
],
),
migrations.CreateModel(
name='Tag',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('name', models.CharField(max_length=200)),
('group', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='tags', to='book_filters.taggroup')),
],
),
]
36 changes: 36 additions & 0 deletions book_filters/migrations/0002_author_publishing_series.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
# Generated by Django 3.1.5 on 2021-02-06 13:56

from django.db import migrations, models
import django.db.models.deletion


class Migration(migrations.Migration):

dependencies = [
('book_filters', '0001_initial'),
]

operations = [
migrations.CreateModel(
name='Author',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('name', models.CharField(max_length=100)),
],
),
migrations.CreateModel(
name='Publishing',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('name', models.CharField(max_length=200)),
],
),
migrations.CreateModel(
name='Series',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('name', models.CharField(max_length=200)),
('publishing', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='series', to='book_filters.publishing')),
],
),
]
Loading

0 comments on commit 6449816

Please sign in to comment.