Initial commit
This commit is contained in:
3
.gitignore
vendored
Normal file
3
.gitignore
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
**/node_modules
|
||||
*.pyc
|
||||
**/__pycache__
|
||||
0
backend/backend/__init__.py
Normal file
0
backend/backend/__init__.py
Normal file
16
backend/backend/asgi.py
Normal file
16
backend/backend/asgi.py
Normal file
@ -0,0 +1,16 @@
|
||||
"""
|
||||
ASGI config for backend project.
|
||||
|
||||
It exposes the ASGI callable as a module-level variable named ``application``.
|
||||
|
||||
For more information on this file, see
|
||||
https://docs.djangoproject.com/en/4.1/howto/deployment/asgi/
|
||||
"""
|
||||
|
||||
import os
|
||||
|
||||
from django.core.asgi import get_asgi_application
|
||||
|
||||
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "backend.settings")
|
||||
|
||||
application = get_asgi_application()
|
||||
131
backend/backend/settings.py
Normal file
131
backend/backend/settings.py
Normal file
@ -0,0 +1,131 @@
|
||||
"""
|
||||
Django settings for backend project.
|
||||
|
||||
Generated by 'django-admin startproject' using Django 4.1.5.
|
||||
|
||||
For more information on this file, see
|
||||
https://docs.djangoproject.com/en/4.1/topics/settings/
|
||||
|
||||
For the full list of settings and their values, see
|
||||
https://docs.djangoproject.com/en/4.1/ref/settings/
|
||||
"""
|
||||
|
||||
from pathlib import Path
|
||||
|
||||
# Build paths inside the project like this: BASE_DIR / 'subdir'.
|
||||
BASE_DIR = Path(__file__).resolve().parent.parent
|
||||
|
||||
|
||||
# Quick-start development settings - unsuitable for production
|
||||
# See https://docs.djangoproject.com/en/4.1/howto/deployment/checklist/
|
||||
|
||||
# SECURITY WARNING: keep the secret key used in production secret!
|
||||
SECRET_KEY = "django-insecure-o27968vc7m@z*=+$ykqo!b2v+ycc)r2^d8u=)ee)gi5bas-+wm"
|
||||
|
||||
# SECURITY WARNING: don't run with debug turned on in production!
|
||||
DEBUG = True
|
||||
|
||||
ALLOWED_HOSTS = []
|
||||
|
||||
|
||||
# Application definition
|
||||
|
||||
INSTALLED_APPS = [
|
||||
"django.contrib.admin",
|
||||
"django.contrib.auth",
|
||||
"django.contrib.contenttypes",
|
||||
"django.contrib.sessions",
|
||||
"django.contrib.messages",
|
||||
"django.contrib.staticfiles",
|
||||
'rest_framework.authtoken',
|
||||
"rest_framework",
|
||||
"snippets",
|
||||
"custom_auth"
|
||||
]
|
||||
|
||||
MIDDLEWARE = [
|
||||
"django.middleware.security.SecurityMiddleware",
|
||||
"django.contrib.sessions.middleware.SessionMiddleware",
|
||||
"django.middleware.common.CommonMiddleware",
|
||||
"django.middleware.csrf.CsrfViewMiddleware",
|
||||
"django.contrib.auth.middleware.AuthenticationMiddleware",
|
||||
"django.contrib.messages.middleware.MessageMiddleware",
|
||||
"django.middleware.clickjacking.XFrameOptionsMiddleware",
|
||||
]
|
||||
|
||||
ROOT_URLCONF = "backend.urls"
|
||||
|
||||
TEMPLATES = [
|
||||
{
|
||||
"BACKEND": "django.template.backends.django.DjangoTemplates",
|
||||
"DIRS": [],
|
||||
"APP_DIRS": True,
|
||||
"OPTIONS": {
|
||||
"context_processors": [
|
||||
"django.template.context_processors.debug",
|
||||
"django.template.context_processors.request",
|
||||
"django.contrib.auth.context_processors.auth",
|
||||
"django.contrib.messages.context_processors.messages",
|
||||
],
|
||||
},
|
||||
},
|
||||
]
|
||||
|
||||
WSGI_APPLICATION = "backend.wsgi.application"
|
||||
|
||||
|
||||
# Database
|
||||
# https://docs.djangoproject.com/en/4.1/ref/settings/#databases
|
||||
|
||||
DATABASES = {
|
||||
"default": {
|
||||
"ENGINE": "django.db.backends.sqlite3",
|
||||
"NAME": BASE_DIR / "db.sqlite3",
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
# Password validation
|
||||
# https://docs.djangoproject.com/en/4.1/ref/settings/#auth-password-validators
|
||||
|
||||
AUTH_PASSWORD_VALIDATORS = [
|
||||
{
|
||||
"NAME": "django.contrib.auth.password_validation.UserAttributeSimilarityValidator",
|
||||
},
|
||||
{
|
||||
"NAME": "django.contrib.auth.password_validation.MinimumLengthValidator",
|
||||
},
|
||||
{
|
||||
"NAME": "django.contrib.auth.password_validation.CommonPasswordValidator",
|
||||
},
|
||||
{
|
||||
"NAME": "django.contrib.auth.password_validation.NumericPasswordValidator",
|
||||
},
|
||||
]
|
||||
|
||||
|
||||
# Internationalization
|
||||
# https://docs.djangoproject.com/en/4.1/topics/i18n/
|
||||
|
||||
LANGUAGE_CODE = "en-us"
|
||||
|
||||
TIME_ZONE = "UTC"
|
||||
|
||||
USE_I18N = True
|
||||
|
||||
USE_TZ = True
|
||||
|
||||
|
||||
# Static files (CSS, JavaScript, Images)
|
||||
# https://docs.djangoproject.com/en/4.1/howto/static-files/
|
||||
|
||||
STATIC_URL = "static/"
|
||||
|
||||
# Default primary key field type
|
||||
# https://docs.djangoproject.com/en/4.1/ref/settings/#default-auto-field
|
||||
|
||||
DEFAULT_AUTO_FIELD = "django.db.models.BigAutoField"
|
||||
|
||||
ACCOUNT_SIGNUP_PASSWORD_VERIFICATION = False
|
||||
|
||||
AUTH_PASSWORD_VALIDATORS = {}
|
||||
23
backend/backend/urls.py
Normal file
23
backend/backend/urls.py
Normal file
@ -0,0 +1,23 @@
|
||||
"""backend URL Configuration
|
||||
|
||||
The `urlpatterns` list routes URLs to views. For more information please see:
|
||||
https://docs.djangoproject.com/en/4.1/topics/http/urls/
|
||||
Examples:
|
||||
Function views
|
||||
1. Add an import: from my_app import views
|
||||
2. Add a URL to urlpatterns: path('', views.home, name='home')
|
||||
Class-based views
|
||||
1. Add an import: from other_app.views import Home
|
||||
2. Add a URL to urlpatterns: path('', Home.as_view(), name='home')
|
||||
Including another URLconf
|
||||
1. Import the include() function: from django.urls import include, path
|
||||
2. Add a URL to urlpatterns: path('blog/', include('blog.urls'))
|
||||
"""
|
||||
from django.contrib import admin
|
||||
from django.urls import path, include
|
||||
|
||||
urlpatterns = [
|
||||
path("api/admin/", admin.site.urls),
|
||||
path("api/", include('snippets.urls')),
|
||||
path("api/auth/", include('custom_auth.urls'))
|
||||
]
|
||||
16
backend/backend/wsgi.py
Normal file
16
backend/backend/wsgi.py
Normal file
@ -0,0 +1,16 @@
|
||||
"""
|
||||
WSGI config for backend project.
|
||||
|
||||
It exposes the WSGI callable as a module-level variable named ``application``.
|
||||
|
||||
For more information on this file, see
|
||||
https://docs.djangoproject.com/en/4.1/howto/deployment/wsgi/
|
||||
"""
|
||||
|
||||
import os
|
||||
|
||||
from django.core.wsgi import get_wsgi_application
|
||||
|
||||
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "backend.settings")
|
||||
|
||||
application = get_wsgi_application()
|
||||
0
backend/custom_auth/__init__.py
Normal file
0
backend/custom_auth/__init__.py
Normal file
3
backend/custom_auth/admin.py
Normal file
3
backend/custom_auth/admin.py
Normal file
@ -0,0 +1,3 @@
|
||||
from django.contrib import admin
|
||||
|
||||
# Register your models here.
|
||||
6
backend/custom_auth/apps.py
Normal file
6
backend/custom_auth/apps.py
Normal file
@ -0,0 +1,6 @@
|
||||
from django.apps import AppConfig
|
||||
|
||||
|
||||
class AuthConfig(AppConfig):
|
||||
default_auto_field = "django.db.models.BigAutoField"
|
||||
name = "custom_auth"
|
||||
0
backend/custom_auth/migrations/__init__.py
Normal file
0
backend/custom_auth/migrations/__init__.py
Normal file
3
backend/custom_auth/models.py
Normal file
3
backend/custom_auth/models.py
Normal file
@ -0,0 +1,3 @@
|
||||
from django.db import models
|
||||
|
||||
# Create your models here.
|
||||
3
backend/custom_auth/tests.py
Normal file
3
backend/custom_auth/tests.py
Normal file
@ -0,0 +1,3 @@
|
||||
from django.test import TestCase
|
||||
|
||||
# Create your tests here.
|
||||
7
backend/custom_auth/urls.py
Normal file
7
backend/custom_auth/urls.py
Normal file
@ -0,0 +1,7 @@
|
||||
from django.urls import path, include
|
||||
from custom_auth import views
|
||||
|
||||
urlpatterns = [
|
||||
path('', include('rest_framework.urls')),
|
||||
path('token/', views.CustomAuthToken.as_view())
|
||||
]
|
||||
17
backend/custom_auth/views.py
Normal file
17
backend/custom_auth/views.py
Normal file
@ -0,0 +1,17 @@
|
||||
from rest_framework.authtoken.views import ObtainAuthToken
|
||||
from rest_framework.authtoken.models import Token
|
||||
from rest_framework.response import Response
|
||||
|
||||
class CustomAuthToken(ObtainAuthToken):
|
||||
|
||||
def post(self, request, *args, **kwargs):
|
||||
serializer = self.serializer_class(data=request.data,
|
||||
context={'request': request})
|
||||
serializer.is_valid(raise_exception=True)
|
||||
user = serializer.validated_data['user']
|
||||
token, created = Token.objects.get_or_create(user=user)
|
||||
return Response({
|
||||
'token': token.key,
|
||||
'user_id': user.pk,
|
||||
'email': user.email
|
||||
})
|
||||
BIN
backend/db.sqlite3
Normal file
BIN
backend/db.sqlite3
Normal file
Binary file not shown.
22
backend/manage.py
Executable file
22
backend/manage.py
Executable file
@ -0,0 +1,22 @@
|
||||
#!/usr/bin/env python
|
||||
"""Django's command-line utility for administrative tasks."""
|
||||
import os
|
||||
import sys
|
||||
|
||||
|
||||
def main():
|
||||
"""Run administrative tasks."""
|
||||
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "backend.settings")
|
||||
try:
|
||||
from django.core.management import execute_from_command_line
|
||||
except ImportError as exc:
|
||||
raise ImportError(
|
||||
"Couldn't import Django. Are you sure it's installed and "
|
||||
"available on your PYTHONPATH environment variable? Did you "
|
||||
"forget to activate a virtual environment?"
|
||||
) from exc
|
||||
execute_from_command_line(sys.argv)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
0
backend/snippets/__init__.py
Normal file
0
backend/snippets/__init__.py
Normal file
21
backend/snippets/admin.py
Normal file
21
backend/snippets/admin.py
Normal file
@ -0,0 +1,21 @@
|
||||
from django.contrib import admin
|
||||
from snippets.models import Snippet, SnippetParticipant
|
||||
|
||||
class SnippetAdmin(admin.ModelAdmin):
|
||||
list_display = ('id', 'title', 'created')
|
||||
list_display_links = ('id', 'title')
|
||||
search_fields = ('title',)
|
||||
list_filter = ('created',)
|
||||
ordering = ('-created',)
|
||||
|
||||
|
||||
class SnippetParticipantAdmin(admin.ModelAdmin):
|
||||
list_display = ('id', 'user', "snippet")
|
||||
list_display_links = ('id', 'user', "snippet")
|
||||
search_fields = ('user', "snippet")
|
||||
list_filter = ('id',)
|
||||
ordering = ('-id',)
|
||||
|
||||
|
||||
admin.site.register(Snippet, SnippetAdmin)
|
||||
admin.site.register(SnippetParticipant, SnippetParticipantAdmin)
|
||||
6
backend/snippets/apps.py
Normal file
6
backend/snippets/apps.py
Normal file
@ -0,0 +1,6 @@
|
||||
from django.apps import AppConfig
|
||||
|
||||
|
||||
class SnippetsConfig(AppConfig):
|
||||
default_auto_field = "django.db.models.BigAutoField"
|
||||
name = "snippets"
|
||||
695
backend/snippets/migrations/0001_initial.py
Normal file
695
backend/snippets/migrations/0001_initial.py
Normal file
@ -0,0 +1,695 @@
|
||||
# Generated by Django 4.1.5 on 2023-05-01 12:57
|
||||
|
||||
from django.conf import settings
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
initial = True
|
||||
|
||||
dependencies = [
|
||||
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name="Snippet",
|
||||
fields=[
|
||||
(
|
||||
"id",
|
||||
models.BigAutoField(
|
||||
auto_created=True,
|
||||
primary_key=True,
|
||||
serialize=False,
|
||||
verbose_name="ID",
|
||||
),
|
||||
),
|
||||
("created", models.DateTimeField(auto_now_add=True)),
|
||||
("title", models.CharField(blank=True, default="", max_length=100)),
|
||||
("content", models.TextField()),
|
||||
("linenos", models.BooleanField(default=False)),
|
||||
(
|
||||
"language",
|
||||
models.CharField(
|
||||
choices=[
|
||||
("abap", "ABAP"),
|
||||
("abnf", "ABNF"),
|
||||
("actionscript", "ActionScript"),
|
||||
("actionscript3", "ActionScript 3"),
|
||||
("ada", "Ada"),
|
||||
("adl", "ADL"),
|
||||
("agda", "Agda"),
|
||||
("aheui", "Aheui"),
|
||||
("alloy", "Alloy"),
|
||||
("ambienttalk", "AmbientTalk"),
|
||||
("amdgpu", "AMDGPU"),
|
||||
("ampl", "Ampl"),
|
||||
("ansys", "ANSYS parametric design language"),
|
||||
("antlr", "ANTLR"),
|
||||
("antlr-actionscript", "ANTLR With ActionScript Target"),
|
||||
("antlr-cpp", "ANTLR With CPP Target"),
|
||||
("antlr-csharp", "ANTLR With C# Target"),
|
||||
("antlr-java", "ANTLR With Java Target"),
|
||||
("antlr-objc", "ANTLR With ObjectiveC Target"),
|
||||
("antlr-perl", "ANTLR With Perl Target"),
|
||||
("antlr-python", "ANTLR With Python Target"),
|
||||
("antlr-ruby", "ANTLR With Ruby Target"),
|
||||
("apacheconf", "ApacheConf"),
|
||||
("apl", "APL"),
|
||||
("applescript", "AppleScript"),
|
||||
("arduino", "Arduino"),
|
||||
("arrow", "Arrow"),
|
||||
("asc", "ASCII armored"),
|
||||
("aspectj", "AspectJ"),
|
||||
("aspx-cs", "aspx-cs"),
|
||||
("aspx-vb", "aspx-vb"),
|
||||
("asymptote", "Asymptote"),
|
||||
("augeas", "Augeas"),
|
||||
("autohotkey", "autohotkey"),
|
||||
("autoit", "AutoIt"),
|
||||
("awk", "Awk"),
|
||||
("bare", "BARE"),
|
||||
("basemake", "Base Makefile"),
|
||||
("bash", "Bash"),
|
||||
("batch", "Batchfile"),
|
||||
("bbcbasic", "BBC Basic"),
|
||||
("bbcode", "BBCode"),
|
||||
("bc", "BC"),
|
||||
("bdd", "Bdd"),
|
||||
("befunge", "Befunge"),
|
||||
("berry", "Berry"),
|
||||
("bibtex", "BibTeX"),
|
||||
("blitzbasic", "BlitzBasic"),
|
||||
("blitzmax", "BlitzMax"),
|
||||
("bnf", "BNF"),
|
||||
("boa", "Boa"),
|
||||
("boo", "Boo"),
|
||||
("boogie", "Boogie"),
|
||||
("brainfuck", "Brainfuck"),
|
||||
("bst", "BST"),
|
||||
("bugs", "BUGS"),
|
||||
("c", "C"),
|
||||
("c-objdump", "c-objdump"),
|
||||
("ca65", "ca65 assembler"),
|
||||
("cadl", "cADL"),
|
||||
("camkes", "CAmkES"),
|
||||
("capdl", "CapDL"),
|
||||
("capnp", "Cap'n Proto"),
|
||||
("cbmbas", "CBM BASIC V2"),
|
||||
("cddl", "CDDL"),
|
||||
("ceylon", "Ceylon"),
|
||||
("cfc", "Coldfusion CFC"),
|
||||
("cfengine3", "CFEngine3"),
|
||||
("cfm", "Coldfusion HTML"),
|
||||
("cfs", "cfstatement"),
|
||||
("chaiscript", "ChaiScript"),
|
||||
("chapel", "Chapel"),
|
||||
("charmci", "Charmci"),
|
||||
("cheetah", "Cheetah"),
|
||||
("cirru", "Cirru"),
|
||||
("clay", "Clay"),
|
||||
("clean", "Clean"),
|
||||
("clojure", "Clojure"),
|
||||
("clojurescript", "ClojureScript"),
|
||||
("cmake", "CMake"),
|
||||
("cobol", "COBOL"),
|
||||
("cobolfree", "COBOLFree"),
|
||||
("coffeescript", "CoffeeScript"),
|
||||
("comal", "COMAL-80"),
|
||||
("common-lisp", "Common Lisp"),
|
||||
("componentpascal", "Component Pascal"),
|
||||
("console", "Bash Session"),
|
||||
("coq", "Coq"),
|
||||
("cplint", "cplint"),
|
||||
("cpp", "C++"),
|
||||
("cpp-objdump", "cpp-objdump"),
|
||||
("cpsa", "CPSA"),
|
||||
("cr", "Crystal"),
|
||||
("crmsh", "Crmsh"),
|
||||
("croc", "Croc"),
|
||||
("cryptol", "Cryptol"),
|
||||
("csharp", "C#"),
|
||||
("csound", "Csound Orchestra"),
|
||||
("csound-document", "Csound Document"),
|
||||
("csound-score", "Csound Score"),
|
||||
("css", "CSS"),
|
||||
("css+django", "CSS+Django/Jinja"),
|
||||
("css+genshitext", "CSS+Genshi Text"),
|
||||
("css+lasso", "CSS+Lasso"),
|
||||
("css+mako", "CSS+Mako"),
|
||||
("css+mako", "CSS+Mako"),
|
||||
("css+mozpreproc", "CSS+mozpreproc"),
|
||||
("css+myghty", "CSS+Myghty"),
|
||||
("css+php", "CSS+PHP"),
|
||||
("css+ruby", "CSS+Ruby"),
|
||||
("css+smarty", "CSS+Smarty"),
|
||||
("css+ul4", "CSS+UL4"),
|
||||
("cuda", "CUDA"),
|
||||
("cypher", "Cypher"),
|
||||
("cython", "Cython"),
|
||||
("d", "D"),
|
||||
("d-objdump", "d-objdump"),
|
||||
("dart", "Dart"),
|
||||
("dasm16", "DASM16"),
|
||||
("debcontrol", "Debian Control file"),
|
||||
("debsources", "Debian Sourcelist"),
|
||||
("delphi", "Delphi"),
|
||||
("devicetree", "Devicetree"),
|
||||
("dg", "dg"),
|
||||
("diff", "Diff"),
|
||||
("django", "Django/Jinja"),
|
||||
("docker", "Docker"),
|
||||
("doscon", "MSDOS Session"),
|
||||
("dpatch", "Darcs Patch"),
|
||||
("dtd", "DTD"),
|
||||
("duel", "Duel"),
|
||||
("dylan", "Dylan"),
|
||||
("dylan-console", "Dylan session"),
|
||||
("dylan-lid", "DylanLID"),
|
||||
("earl-grey", "Earl Grey"),
|
||||
("easytrieve", "Easytrieve"),
|
||||
("ebnf", "EBNF"),
|
||||
("ec", "eC"),
|
||||
("ecl", "ECL"),
|
||||
("eiffel", "Eiffel"),
|
||||
("elixir", "Elixir"),
|
||||
("elm", "Elm"),
|
||||
("elpi", "Elpi"),
|
||||
("emacs-lisp", "EmacsLisp"),
|
||||
("email", "E-mail"),
|
||||
("erb", "ERB"),
|
||||
("erl", "Erlang erl session"),
|
||||
("erlang", "Erlang"),
|
||||
("evoque", "Evoque"),
|
||||
("execline", "execline"),
|
||||
("extempore", "xtlang"),
|
||||
("ezhil", "Ezhil"),
|
||||
("factor", "Factor"),
|
||||
("fan", "Fantom"),
|
||||
("fancy", "Fancy"),
|
||||
("felix", "Felix"),
|
||||
("fennel", "Fennel"),
|
||||
("fish", "Fish"),
|
||||
("flatline", "Flatline"),
|
||||
("floscript", "FloScript"),
|
||||
("forth", "Forth"),
|
||||
("fortran", "Fortran"),
|
||||
("fortranfixed", "FortranFixed"),
|
||||
("foxpro", "FoxPro"),
|
||||
("freefem", "Freefem"),
|
||||
("fsharp", "F#"),
|
||||
("fstar", "FStar"),
|
||||
("futhark", "Futhark"),
|
||||
("gap", "GAP"),
|
||||
("gas", "GAS"),
|
||||
("gcode", "g-code"),
|
||||
("gdscript", "GDScript"),
|
||||
("genshi", "Genshi"),
|
||||
("genshitext", "Genshi Text"),
|
||||
("gherkin", "Gherkin"),
|
||||
("glsl", "GLSL"),
|
||||
("gnuplot", "Gnuplot"),
|
||||
("go", "Go"),
|
||||
("golo", "Golo"),
|
||||
("gooddata-cl", "GoodData-CL"),
|
||||
("gosu", "Gosu"),
|
||||
("graphviz", "Graphviz"),
|
||||
("groff", "Groff"),
|
||||
("groovy", "Groovy"),
|
||||
("gsql", "GSQL"),
|
||||
("gst", "Gosu Template"),
|
||||
("haml", "Haml"),
|
||||
("handlebars", "Handlebars"),
|
||||
("haskell", "Haskell"),
|
||||
("haxe", "Haxe"),
|
||||
("haxeml", "Hxml"),
|
||||
("hexdump", "Hexdump"),
|
||||
("hlsl", "HLSL"),
|
||||
("hsail", "HSAIL"),
|
||||
("hspec", "Hspec"),
|
||||
("html", "HTML"),
|
||||
("html+cheetah", "HTML+Cheetah"),
|
||||
("html+django", "HTML+Django/Jinja"),
|
||||
("html+evoque", "HTML+Evoque"),
|
||||
("html+genshi", "HTML+Genshi"),
|
||||
("html+handlebars", "HTML+Handlebars"),
|
||||
("html+lasso", "HTML+Lasso"),
|
||||
("html+mako", "HTML+Mako"),
|
||||
("html+mako", "HTML+Mako"),
|
||||
("html+myghty", "HTML+Myghty"),
|
||||
("html+ng2", "HTML + Angular2"),
|
||||
("html+php", "HTML+PHP"),
|
||||
("html+smarty", "HTML+Smarty"),
|
||||
("html+twig", "HTML+Twig"),
|
||||
("html+ul4", "HTML+UL4"),
|
||||
("html+velocity", "HTML+Velocity"),
|
||||
("http", "HTTP"),
|
||||
("hybris", "Hybris"),
|
||||
("hylang", "Hy"),
|
||||
("i6t", "Inform 6 template"),
|
||||
("icon", "Icon"),
|
||||
("idl", "IDL"),
|
||||
("idris", "Idris"),
|
||||
("iex", "Elixir iex session"),
|
||||
("igor", "Igor"),
|
||||
("inform6", "Inform 6"),
|
||||
("inform7", "Inform 7"),
|
||||
("ini", "INI"),
|
||||
("io", "Io"),
|
||||
("ioke", "Ioke"),
|
||||
("ipython2", "IPython"),
|
||||
("ipython3", "IPython3"),
|
||||
("ipythonconsole", "IPython console session"),
|
||||
("irc", "IRC logs"),
|
||||
("isabelle", "Isabelle"),
|
||||
("j", "J"),
|
||||
("jags", "JAGS"),
|
||||
("jasmin", "Jasmin"),
|
||||
("java", "Java"),
|
||||
("javascript", "JavaScript"),
|
||||
("javascript+cheetah", "JavaScript+Cheetah"),
|
||||
("javascript+django", "JavaScript+Django/Jinja"),
|
||||
("javascript+lasso", "JavaScript+Lasso"),
|
||||
("javascript+mako", "JavaScript+Mako"),
|
||||
("javascript+mozpreproc", "Javascript+mozpreproc"),
|
||||
("javascript+myghty", "JavaScript+Myghty"),
|
||||
("javascript+php", "JavaScript+PHP"),
|
||||
("javascript+ruby", "JavaScript+Ruby"),
|
||||
("javascript+smarty", "JavaScript+Smarty"),
|
||||
("jcl", "JCL"),
|
||||
("jlcon", "Julia console"),
|
||||
("jmespath", "JMESPath"),
|
||||
("js+genshitext", "JavaScript+Genshi Text"),
|
||||
("js+mako", "JavaScript+Mako"),
|
||||
("js+ul4", "Javascript+UL4"),
|
||||
("jsgf", "JSGF"),
|
||||
("jslt", "JSLT"),
|
||||
("json", "JSON"),
|
||||
("jsonld", "JSON-LD"),
|
||||
("jsp", "Java Server Page"),
|
||||
("julia", "Julia"),
|
||||
("juttle", "Juttle"),
|
||||
("k", "K"),
|
||||
("kal", "Kal"),
|
||||
("kconfig", "Kconfig"),
|
||||
("kmsg", "Kernel log"),
|
||||
("koka", "Koka"),
|
||||
("kotlin", "Kotlin"),
|
||||
("kuin", "Kuin"),
|
||||
("lasso", "Lasso"),
|
||||
("lean", "Lean"),
|
||||
("less", "LessCss"),
|
||||
("lighttpd", "Lighttpd configuration file"),
|
||||
("lilypond", "LilyPond"),
|
||||
("limbo", "Limbo"),
|
||||
("liquid", "liquid"),
|
||||
("literate-agda", "Literate Agda"),
|
||||
("literate-cryptol", "Literate Cryptol"),
|
||||
("literate-haskell", "Literate Haskell"),
|
||||
("literate-idris", "Literate Idris"),
|
||||
("livescript", "LiveScript"),
|
||||
("llvm", "LLVM"),
|
||||
("llvm-mir", "LLVM-MIR"),
|
||||
("llvm-mir-body", "LLVM-MIR Body"),
|
||||
("logos", "Logos"),
|
||||
("logtalk", "Logtalk"),
|
||||
("lsl", "LSL"),
|
||||
("lua", "Lua"),
|
||||
("macaulay2", "Macaulay2"),
|
||||
("make", "Makefile"),
|
||||
("mako", "Mako"),
|
||||
("mako", "Mako"),
|
||||
("maql", "MAQL"),
|
||||
("markdown", "Markdown"),
|
||||
("mask", "Mask"),
|
||||
("mason", "Mason"),
|
||||
("mathematica", "Mathematica"),
|
||||
("matlab", "Matlab"),
|
||||
("matlabsession", "Matlab session"),
|
||||
("maxima", "Maxima"),
|
||||
("mcfunction", "MCFunction"),
|
||||
("meson", "Meson"),
|
||||
("mime", "MIME"),
|
||||
("minid", "MiniD"),
|
||||
("miniscript", "MiniScript"),
|
||||
("modelica", "Modelica"),
|
||||
("modula2", "Modula-2"),
|
||||
("monkey", "Monkey"),
|
||||
("monte", "Monte"),
|
||||
("moocode", "MOOCode"),
|
||||
("moonscript", "MoonScript"),
|
||||
("mosel", "Mosel"),
|
||||
("mozhashpreproc", "mozhashpreproc"),
|
||||
("mozpercentpreproc", "mozpercentpreproc"),
|
||||
("mql", "MQL"),
|
||||
("mscgen", "Mscgen"),
|
||||
("mupad", "MuPAD"),
|
||||
("mxml", "MXML"),
|
||||
("myghty", "Myghty"),
|
||||
("mysql", "MySQL"),
|
||||
("nasm", "NASM"),
|
||||
("ncl", "NCL"),
|
||||
("nemerle", "Nemerle"),
|
||||
("nesc", "nesC"),
|
||||
("nestedtext", "NestedText"),
|
||||
("newlisp", "NewLisp"),
|
||||
("newspeak", "Newspeak"),
|
||||
("ng2", "Angular2"),
|
||||
("nginx", "Nginx configuration file"),
|
||||
("nimrod", "Nimrod"),
|
||||
("nit", "Nit"),
|
||||
("nixos", "Nix"),
|
||||
("nodejsrepl", "Node.js REPL console session"),
|
||||
("notmuch", "Notmuch"),
|
||||
("nsis", "NSIS"),
|
||||
("numpy", "NumPy"),
|
||||
("nusmv", "NuSMV"),
|
||||
("objdump", "objdump"),
|
||||
("objdump-nasm", "objdump-nasm"),
|
||||
("objective-c", "Objective-C"),
|
||||
("objective-c++", "Objective-C++"),
|
||||
("objective-j", "Objective-J"),
|
||||
("ocaml", "OCaml"),
|
||||
("octave", "Octave"),
|
||||
("odin", "ODIN"),
|
||||
("omg-idl", "OMG Interface Definition Language"),
|
||||
("ooc", "Ooc"),
|
||||
("opa", "Opa"),
|
||||
("openedge", "OpenEdge ABL"),
|
||||
("output", "Text output"),
|
||||
("pacmanconf", "PacmanConf"),
|
||||
("pan", "Pan"),
|
||||
("parasail", "ParaSail"),
|
||||
("pawn", "Pawn"),
|
||||
("peg", "PEG"),
|
||||
("perl", "Perl"),
|
||||
("perl6", "Perl6"),
|
||||
("php", "PHP"),
|
||||
("pig", "Pig"),
|
||||
("pike", "Pike"),
|
||||
("pkgconfig", "PkgConfig"),
|
||||
("plpgsql", "PL/pgSQL"),
|
||||
("pointless", "Pointless"),
|
||||
("pony", "Pony"),
|
||||
("postgresql", "PostgreSQL SQL dialect"),
|
||||
("postscript", "PostScript"),
|
||||
("pot", "Gettext Catalog"),
|
||||
("pov", "POVRay"),
|
||||
("powershell", "PowerShell"),
|
||||
("praat", "Praat"),
|
||||
("procfile", "Procfile"),
|
||||
("prolog", "Prolog"),
|
||||
("promql", "PromQL"),
|
||||
("properties", "Properties"),
|
||||
("protobuf", "Protocol Buffer"),
|
||||
("psql", "PostgreSQL console (psql)"),
|
||||
("psysh", "PsySH console session for PHP"),
|
||||
("pug", "Pug"),
|
||||
("puppet", "Puppet"),
|
||||
("pwsh-session", "PowerShell Session"),
|
||||
("py+ul4", "Python+UL4"),
|
||||
("py2tb", "Python 2.x Traceback"),
|
||||
("pycon", "Python console session"),
|
||||
("pypylog", "PyPy Log"),
|
||||
("pytb", "Python Traceback"),
|
||||
("python", "Python"),
|
||||
("python2", "Python 2.x"),
|
||||
("q", "Q"),
|
||||
("qbasic", "QBasic"),
|
||||
("qlik", "Qlik"),
|
||||
("qml", "QML"),
|
||||
("qvto", "QVTO"),
|
||||
("racket", "Racket"),
|
||||
("ragel", "Ragel"),
|
||||
("ragel-c", "Ragel in C Host"),
|
||||
("ragel-cpp", "Ragel in CPP Host"),
|
||||
("ragel-d", "Ragel in D Host"),
|
||||
("ragel-em", "Embedded Ragel"),
|
||||
("ragel-java", "Ragel in Java Host"),
|
||||
("ragel-objc", "Ragel in Objective C Host"),
|
||||
("ragel-ruby", "Ragel in Ruby Host"),
|
||||
("rbcon", "Ruby irb session"),
|
||||
("rconsole", "RConsole"),
|
||||
("rd", "Rd"),
|
||||
("reasonml", "ReasonML"),
|
||||
("rebol", "REBOL"),
|
||||
("red", "Red"),
|
||||
("redcode", "Redcode"),
|
||||
("registry", "reg"),
|
||||
("resourcebundle", "ResourceBundle"),
|
||||
("restructuredtext", "reStructuredText"),
|
||||
("rexx", "Rexx"),
|
||||
("rhtml", "RHTML"),
|
||||
("ride", "Ride"),
|
||||
("rita", "Rita"),
|
||||
("rng-compact", "Relax-NG Compact"),
|
||||
("roboconf-graph", "Roboconf Graph"),
|
||||
("roboconf-instances", "Roboconf Instances"),
|
||||
("robotframework", "RobotFramework"),
|
||||
("rql", "RQL"),
|
||||
("rsl", "RSL"),
|
||||
("ruby", "Ruby"),
|
||||
("rust", "Rust"),
|
||||
("sarl", "SARL"),
|
||||
("sas", "SAS"),
|
||||
("sass", "Sass"),
|
||||
("savi", "Savi"),
|
||||
("scala", "Scala"),
|
||||
("scaml", "Scaml"),
|
||||
("scdoc", "scdoc"),
|
||||
("scheme", "Scheme"),
|
||||
("scilab", "Scilab"),
|
||||
("scss", "SCSS"),
|
||||
("sed", "Sed"),
|
||||
("sgf", "SmartGameFormat"),
|
||||
("shen", "Shen"),
|
||||
("shexc", "ShExC"),
|
||||
("sieve", "Sieve"),
|
||||
("silver", "Silver"),
|
||||
("singularity", "Singularity"),
|
||||
("slash", "Slash"),
|
||||
("slim", "Slim"),
|
||||
("slurm", "Slurm"),
|
||||
("smali", "Smali"),
|
||||
("smalltalk", "Smalltalk"),
|
||||
("smarty", "Smarty"),
|
||||
("smithy", "Smithy"),
|
||||
("sml", "Standard ML"),
|
||||
("snbt", "SNBT"),
|
||||
("snobol", "Snobol"),
|
||||
("snowball", "Snowball"),
|
||||
("solidity", "Solidity"),
|
||||
("sophia", "Sophia"),
|
||||
("sp", "SourcePawn"),
|
||||
("sparql", "SPARQL"),
|
||||
("spec", "RPMSpec"),
|
||||
("spice", "Spice"),
|
||||
("splus", "S"),
|
||||
("sql", "SQL"),
|
||||
("sql+jinja", "SQL+Jinja"),
|
||||
("sqlite3", "sqlite3con"),
|
||||
("squidconf", "SquidConf"),
|
||||
("srcinfo", "Srcinfo"),
|
||||
("ssp", "Scalate Server Page"),
|
||||
("stan", "Stan"),
|
||||
("stata", "Stata"),
|
||||
("supercollider", "SuperCollider"),
|
||||
("swift", "Swift"),
|
||||
("swig", "SWIG"),
|
||||
("systemverilog", "systemverilog"),
|
||||
("tads3", "TADS 3"),
|
||||
("tal", "Tal"),
|
||||
("tap", "TAP"),
|
||||
("tasm", "TASM"),
|
||||
("tcl", "Tcl"),
|
||||
("tcsh", "Tcsh"),
|
||||
("tcshcon", "Tcsh Session"),
|
||||
("tea", "Tea"),
|
||||
("teal", "teal"),
|
||||
("teratermmacro", "Tera Term macro"),
|
||||
("termcap", "Termcap"),
|
||||
("terminfo", "Terminfo"),
|
||||
("terraform", "Terraform"),
|
||||
("tex", "TeX"),
|
||||
("text", "Text only"),
|
||||
("thrift", "Thrift"),
|
||||
("ti", "ThingsDB"),
|
||||
("tid", "tiddler"),
|
||||
("tnt", "Typographic Number Theory"),
|
||||
("todotxt", "Todotxt"),
|
||||
("toml", "TOML"),
|
||||
("trac-wiki", "MoinMoin/Trac Wiki markup"),
|
||||
("trafficscript", "TrafficScript"),
|
||||
("treetop", "Treetop"),
|
||||
("tsql", "Transact-SQL"),
|
||||
("turtle", "Turtle"),
|
||||
("twig", "Twig"),
|
||||
("typescript", "TypeScript"),
|
||||
("typoscript", "TypoScript"),
|
||||
("typoscriptcssdata", "TypoScriptCssData"),
|
||||
("typoscripthtmldata", "TypoScriptHtmlData"),
|
||||
("ucode", "ucode"),
|
||||
("ul4", "UL4"),
|
||||
("unicon", "Unicon"),
|
||||
("unixconfig", "Unix/Linux config files"),
|
||||
("urbiscript", "UrbiScript"),
|
||||
("usd", "USD"),
|
||||
("vala", "Vala"),
|
||||
("vb.net", "VB.net"),
|
||||
("vbscript", "VBScript"),
|
||||
("vcl", "VCL"),
|
||||
("vclsnippets", "VCLSnippets"),
|
||||
("vctreestatus", "VCTreeStatus"),
|
||||
("velocity", "Velocity"),
|
||||
("verilog", "verilog"),
|
||||
("vgl", "VGL"),
|
||||
("vhdl", "vhdl"),
|
||||
("vim", "VimL"),
|
||||
("wast", "WebAssembly"),
|
||||
("wdiff", "WDiff"),
|
||||
("webidl", "Web IDL"),
|
||||
("whiley", "Whiley"),
|
||||
("x10", "X10"),
|
||||
("xml", "XML"),
|
||||
("xml+cheetah", "XML+Cheetah"),
|
||||
("xml+django", "XML+Django/Jinja"),
|
||||
("xml+evoque", "XML+Evoque"),
|
||||
("xml+lasso", "XML+Lasso"),
|
||||
("xml+mako", "XML+Mako"),
|
||||
("xml+mako", "XML+Mako"),
|
||||
("xml+myghty", "XML+Myghty"),
|
||||
("xml+php", "XML+PHP"),
|
||||
("xml+ruby", "XML+Ruby"),
|
||||
("xml+smarty", "XML+Smarty"),
|
||||
("xml+ul4", "XML+UL4"),
|
||||
("xml+velocity", "XML+Velocity"),
|
||||
("xorg.conf", "Xorg"),
|
||||
("xquery", "XQuery"),
|
||||
("xslt", "XSLT"),
|
||||
("xtend", "Xtend"),
|
||||
("xul+mozpreproc", "XUL+mozpreproc"),
|
||||
("yaml", "YAML"),
|
||||
("yaml+jinja", "YAML+Jinja"),
|
||||
("yang", "YANG"),
|
||||
("zeek", "Zeek"),
|
||||
("zephir", "Zephir"),
|
||||
("zig", "Zig"),
|
||||
],
|
||||
default="python",
|
||||
max_length=100,
|
||||
),
|
||||
),
|
||||
(
|
||||
"style",
|
||||
models.CharField(
|
||||
choices=[
|
||||
("abap", "abap"),
|
||||
("algol", "algol"),
|
||||
("algol_nu", "algol_nu"),
|
||||
("arduino", "arduino"),
|
||||
("autumn", "autumn"),
|
||||
("borland", "borland"),
|
||||
("bw", "bw"),
|
||||
("colorful", "colorful"),
|
||||
("default", "default"),
|
||||
("dracula", "dracula"),
|
||||
("emacs", "emacs"),
|
||||
("friendly", "friendly"),
|
||||
("friendly_grayscale", "friendly_grayscale"),
|
||||
("fruity", "fruity"),
|
||||
("github-dark", "github-dark"),
|
||||
("gruvbox-dark", "gruvbox-dark"),
|
||||
("gruvbox-light", "gruvbox-light"),
|
||||
("igor", "igor"),
|
||||
("inkpot", "inkpot"),
|
||||
("lilypond", "lilypond"),
|
||||
("lovelace", "lovelace"),
|
||||
("manni", "manni"),
|
||||
("material", "material"),
|
||||
("monokai", "monokai"),
|
||||
("murphy", "murphy"),
|
||||
("native", "native"),
|
||||
("nord", "nord"),
|
||||
("nord-darker", "nord-darker"),
|
||||
("one-dark", "one-dark"),
|
||||
("paraiso-dark", "paraiso-dark"),
|
||||
("paraiso-light", "paraiso-light"),
|
||||
("pastie", "pastie"),
|
||||
("perldoc", "perldoc"),
|
||||
("rainbow_dash", "rainbow_dash"),
|
||||
("rrt", "rrt"),
|
||||
("sas", "sas"),
|
||||
("solarized-dark", "solarized-dark"),
|
||||
("solarized-light", "solarized-light"),
|
||||
("staroffice", "staroffice"),
|
||||
("stata", "stata"),
|
||||
("stata-dark", "stata-dark"),
|
||||
("stata-light", "stata-light"),
|
||||
("tango", "tango"),
|
||||
("trac", "trac"),
|
||||
("vim", "vim"),
|
||||
("vs", "vs"),
|
||||
("xcode", "xcode"),
|
||||
("zenburn", "zenburn"),
|
||||
],
|
||||
default="friendly",
|
||||
max_length=100,
|
||||
),
|
||||
),
|
||||
("highlighted", models.TextField()),
|
||||
(
|
||||
"access",
|
||||
models.CharField(
|
||||
choices=[
|
||||
("public", "Public"),
|
||||
("private", "Private"),
|
||||
("owner-only", "Owner only"),
|
||||
],
|
||||
default="private",
|
||||
max_length=20,
|
||||
verbose_name="Access type",
|
||||
),
|
||||
),
|
||||
(
|
||||
"owner",
|
||||
models.ForeignKey(
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
to=settings.AUTH_USER_MODEL,
|
||||
verbose_name="Snippet owner",
|
||||
),
|
||||
),
|
||||
],
|
||||
options={
|
||||
"ordering": ["created"],
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name="SnippetParticipant",
|
||||
fields=[
|
||||
(
|
||||
"id",
|
||||
models.IntegerField(
|
||||
primary_key=True, serialize=False, verbose_name="ID"
|
||||
),
|
||||
),
|
||||
(
|
||||
"snippet",
|
||||
models.ForeignKey(
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
to="snippets.snippet",
|
||||
verbose_name="Associated Snippet",
|
||||
),
|
||||
),
|
||||
(
|
||||
"user",
|
||||
models.ForeignKey(
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
to=settings.AUTH_USER_MODEL,
|
||||
verbose_name="Associated User",
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
]
|
||||
0
backend/snippets/migrations/__init__.py
Normal file
0
backend/snippets/migrations/__init__.py
Normal file
69
backend/snippets/models.py
Normal file
69
backend/snippets/models.py
Normal file
@ -0,0 +1,69 @@
|
||||
from django.db import models
|
||||
from pygments.lexers import get_all_lexers
|
||||
from pygments.styles import get_all_styles
|
||||
from pygments.lexers import get_lexer_by_name
|
||||
from pygments.formatters.html import HtmlFormatter
|
||||
from pygments import highlight
|
||||
|
||||
LEXERS = [item for item in get_all_lexers() if item[1]]
|
||||
LANGUAGE_CHOICES = sorted([(item[1][0], item[0]) for item in LEXERS])
|
||||
STYLE_CHOICES = sorted([(item, item) for item in get_all_styles()])
|
||||
ACCESS_TYPES = (("public", "Public"), ("private", "Private"), ("owner-only", "Owner only"))
|
||||
|
||||
|
||||
class Snippet(models.Model):
|
||||
created = models.DateTimeField(auto_now_add=True)
|
||||
title = models.CharField(max_length=100, blank=True, default='')
|
||||
content = models.TextField()
|
||||
linenos = models.BooleanField(default=False)
|
||||
language = models.CharField(choices=LANGUAGE_CHOICES, default='python', max_length=100)
|
||||
style = models.CharField(choices=STYLE_CHOICES, default='friendly', max_length=100)
|
||||
highlighted = models.TextField()
|
||||
owner = models.ForeignKey(
|
||||
verbose_name="Snippet owner",
|
||||
to="auth.User",
|
||||
on_delete=models.CASCADE
|
||||
)
|
||||
access = models.CharField(
|
||||
verbose_name="Access type",
|
||||
choices=ACCESS_TYPES,
|
||||
default="private",
|
||||
max_length=20
|
||||
)
|
||||
|
||||
def save(self, *args, **kwargs):
|
||||
"""
|
||||
Use the `pygments` library to create a highlighted HTML
|
||||
representation of the code snippet.
|
||||
"""
|
||||
lexer = get_lexer_by_name(self.language)
|
||||
linenos = 'table' if self.linenos else False
|
||||
options = {'title': self.title} if self.title else {}
|
||||
formatter = HtmlFormatter(
|
||||
style=self.style,
|
||||
linenos=linenos,
|
||||
full=True,
|
||||
**options
|
||||
)
|
||||
self.highlighted = highlight(self.content, lexer, formatter)
|
||||
super().save(*args, **kwargs)
|
||||
|
||||
class Meta:
|
||||
ordering = ['created']
|
||||
|
||||
|
||||
class SnippetParticipant(models.Model):
|
||||
id = models.IntegerField(
|
||||
verbose_name="ID",
|
||||
primary_key=True
|
||||
)
|
||||
user = models.ForeignKey(
|
||||
verbose_name="Associated User",
|
||||
to="auth.User",
|
||||
on_delete=models.CASCADE
|
||||
)
|
||||
snippet = models.ForeignKey(
|
||||
verbose_name="Associated Snippet",
|
||||
to=Snippet,
|
||||
on_delete=models.CASCADE
|
||||
)
|
||||
26
backend/snippets/permissions.py
Normal file
26
backend/snippets/permissions.py
Normal file
@ -0,0 +1,26 @@
|
||||
from rest_framework import permissions
|
||||
from snippets.models import SnippetParticipant
|
||||
|
||||
|
||||
class IsOwnerOrReadOnly(permissions.BasePermission):
|
||||
"""
|
||||
Custom permission to only allow owners of an object to edit it.
|
||||
"""
|
||||
|
||||
def has_object_permission(self, request, view, obj):
|
||||
# Read permissions are allowed to any request,
|
||||
# so we'll always allow GET, HEAD or OPTIONS requests.
|
||||
if request.method in permissions.SAFE_METHODS:
|
||||
return True
|
||||
|
||||
# Write permissions are only allowed to the owner of the snippet.
|
||||
return obj.owner == request.user
|
||||
|
||||
|
||||
class IsAccessedOrDeny(permissions.BasePermission):
|
||||
|
||||
def has_object_permission(self, request, view, obj):
|
||||
if obj.owner == request.user:
|
||||
return True
|
||||
allowed_users = SnippetParticipant.objects.filter(snippet=obj)
|
||||
return request.user in [i.user for i in allowed_users]
|
||||
45
backend/snippets/serializers.py
Normal file
45
backend/snippets/serializers.py
Normal file
@ -0,0 +1,45 @@
|
||||
from rest_framework import serializers
|
||||
from snippets.models import Snippet, SnippetParticipant
|
||||
from django.contrib.auth.models import User
|
||||
|
||||
|
||||
class UserSerializer(serializers.ModelSerializer):
|
||||
class Meta:
|
||||
model = User
|
||||
fields = ['id', 'username']
|
||||
|
||||
|
||||
class SnippetSerializer(serializers.ModelSerializer):
|
||||
|
||||
|
||||
|
||||
def get_allowed_users(self, obj) -> list[str]:
|
||||
query = SnippetParticipant.objects.filter(snippet=obj)
|
||||
return [ele.username for ele in query]
|
||||
|
||||
class Meta:
|
||||
model = Snippet
|
||||
fields = [
|
||||
"id",
|
||||
"created",
|
||||
"title",
|
||||
"linenos",
|
||||
"language",
|
||||
"style",
|
||||
"owner",
|
||||
"access",
|
||||
]
|
||||
read_only_fields = ["created", "owner"]
|
||||
owner = serializers.ReadOnlyField(source='owner.username')
|
||||
allowed_users = serializers.SerializerMethodField(read_only=True)
|
||||
|
||||
#
|
||||
# class SnippetParticipantSerializer(serializers.ModelSerializer):
|
||||
# class Meta:
|
||||
# model = SnippetParticipant
|
||||
# fields = [
|
||||
# "id",
|
||||
# "user",
|
||||
# "snippet"
|
||||
# ]
|
||||
# read_only_fields = ["id"]
|
||||
3
backend/snippets/tests.py
Normal file
3
backend/snippets/tests.py
Normal file
@ -0,0 +1,3 @@
|
||||
from django.test import TestCase
|
||||
|
||||
# Create your tests here.
|
||||
9
backend/snippets/urls.py
Normal file
9
backend/snippets/urls.py
Normal file
@ -0,0 +1,9 @@
|
||||
from django.urls import path
|
||||
from snippets import views
|
||||
|
||||
urlpatterns = [
|
||||
path('users/', views.UserList.as_view()),
|
||||
path('users/<int:pk>/', views.UserDetail.as_view()),
|
||||
path("snippets/", views.SnippetList.as_view()),
|
||||
path("snippets/<int:pk>", views.SnippetDetail.as_view()),
|
||||
]
|
||||
41
backend/snippets/views.py
Normal file
41
backend/snippets/views.py
Normal file
@ -0,0 +1,41 @@
|
||||
from snippets.models import Snippet, SnippetParticipant
|
||||
from snippets.serializers import SnippetSerializer, UserSerializer
|
||||
from rest_framework import generics
|
||||
from django.contrib.auth.models import User
|
||||
from rest_framework import permissions
|
||||
from snippets.permissions import IsAccessedOrDeny
|
||||
|
||||
|
||||
class UserList(generics.ListAPIView):
|
||||
queryset = User.objects.all()
|
||||
serializer_class = UserSerializer
|
||||
|
||||
|
||||
class UserDetail(generics.RetrieveAPIView):
|
||||
queryset = User.objects.all()
|
||||
serializer_class = UserSerializer
|
||||
|
||||
|
||||
class SnippetList(generics.ListCreateAPIView):
|
||||
queryset = Snippet.objects.all()
|
||||
serializer_class = SnippetSerializer
|
||||
permission_classes = [permissions.IsAuthenticatedOrReadOnly]
|
||||
|
||||
def perform_create(self, serializer):
|
||||
serializer.save(owner=self.request.user)
|
||||
|
||||
|
||||
class SnippetDetail(generics.RetrieveUpdateDestroyAPIView):
|
||||
queryset = Snippet.objects.all()
|
||||
serializer_class = SnippetSerializer
|
||||
permission_classes = [permissions.IsAuthenticatedOrReadOnly, IsAccessedOrDeny]
|
||||
|
||||
|
||||
class SnippetParticipantList(generics.ListCreateAPIView):
|
||||
queryset = SnippetParticipant.objects.all()
|
||||
serializer_class = SnippetSerializer
|
||||
|
||||
|
||||
class SnippetParticipantDetail(generics.RetrieveUpdateDestroyAPIView):
|
||||
queryset = SnippetParticipant.objects.all()
|
||||
serializer_class = SnippetSerializer
|
||||
0
backend_legacy/backend/__init__.py
Normal file
0
backend_legacy/backend/__init__.py
Normal file
21
backend_legacy/backend/admin.py
Normal file
21
backend_legacy/backend/admin.py
Normal file
@ -0,0 +1,21 @@
|
||||
from django.contrib import admin
|
||||
from backend.models import Snippet, SnippetParticipant
|
||||
|
||||
class SnippetAdmin(admin.ModelAdmin):
|
||||
list_display = ('id', 'title', 'created')
|
||||
list_display_links = ('id', 'title')
|
||||
search_fields = ('title',)
|
||||
list_filter = ('created',)
|
||||
ordering = ('-created',)
|
||||
|
||||
|
||||
class SnippetParticipantAdmin(admin.ModelAdmin):
|
||||
list_display = ('id', 'user', "snippet")
|
||||
list_display_links = ('id', 'user', "snippet")
|
||||
search_fields = ('user', "snippet")
|
||||
list_filter = ('id',)
|
||||
ordering = ('-id',)
|
||||
|
||||
|
||||
admin.site.register(Snippet, SnippetAdmin)
|
||||
admin.site.register(SnippetParticipant, SnippetParticipantAdmin)
|
||||
16
backend_legacy/backend/asgi.py
Normal file
16
backend_legacy/backend/asgi.py
Normal file
@ -0,0 +1,16 @@
|
||||
"""
|
||||
ASGI config for backend project.
|
||||
|
||||
It exposes the ASGI callable as a module-level variable named ``application``.
|
||||
|
||||
For more information on this file, see
|
||||
https://docs.djangoproject.com/en/4.1/howto/deployment/asgi/
|
||||
"""
|
||||
|
||||
import os
|
||||
|
||||
from django.core.asgi import get_asgi_application
|
||||
|
||||
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "backend.settings")
|
||||
|
||||
application = get_asgi_application()
|
||||
695
backend_legacy/backend/migrations/0001_initial.py
Normal file
695
backend_legacy/backend/migrations/0001_initial.py
Normal file
@ -0,0 +1,695 @@
|
||||
# Generated by Django 4.1.5 on 2023-05-01 12:33
|
||||
|
||||
from django.conf import settings
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
initial = True
|
||||
|
||||
dependencies = [
|
||||
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name="Snippet",
|
||||
fields=[
|
||||
(
|
||||
"id",
|
||||
models.BigAutoField(
|
||||
auto_created=True,
|
||||
primary_key=True,
|
||||
serialize=False,
|
||||
verbose_name="ID",
|
||||
),
|
||||
),
|
||||
("created", models.DateTimeField(auto_now_add=True)),
|
||||
("title", models.CharField(blank=True, default="", max_length=100)),
|
||||
("content", models.TextField()),
|
||||
("linenos", models.BooleanField(default=False)),
|
||||
(
|
||||
"language",
|
||||
models.CharField(
|
||||
choices=[
|
||||
("abap", "ABAP"),
|
||||
("abnf", "ABNF"),
|
||||
("actionscript", "ActionScript"),
|
||||
("actionscript3", "ActionScript 3"),
|
||||
("ada", "Ada"),
|
||||
("adl", "ADL"),
|
||||
("agda", "Agda"),
|
||||
("aheui", "Aheui"),
|
||||
("alloy", "Alloy"),
|
||||
("ambienttalk", "AmbientTalk"),
|
||||
("amdgpu", "AMDGPU"),
|
||||
("ampl", "Ampl"),
|
||||
("ansys", "ANSYS parametric design language"),
|
||||
("antlr", "ANTLR"),
|
||||
("antlr-actionscript", "ANTLR With ActionScript Target"),
|
||||
("antlr-cpp", "ANTLR With CPP Target"),
|
||||
("antlr-csharp", "ANTLR With C# Target"),
|
||||
("antlr-java", "ANTLR With Java Target"),
|
||||
("antlr-objc", "ANTLR With ObjectiveC Target"),
|
||||
("antlr-perl", "ANTLR With Perl Target"),
|
||||
("antlr-python", "ANTLR With Python Target"),
|
||||
("antlr-ruby", "ANTLR With Ruby Target"),
|
||||
("apacheconf", "ApacheConf"),
|
||||
("apl", "APL"),
|
||||
("applescript", "AppleScript"),
|
||||
("arduino", "Arduino"),
|
||||
("arrow", "Arrow"),
|
||||
("asc", "ASCII armored"),
|
||||
("aspectj", "AspectJ"),
|
||||
("aspx-cs", "aspx-cs"),
|
||||
("aspx-vb", "aspx-vb"),
|
||||
("asymptote", "Asymptote"),
|
||||
("augeas", "Augeas"),
|
||||
("autohotkey", "autohotkey"),
|
||||
("autoit", "AutoIt"),
|
||||
("awk", "Awk"),
|
||||
("bare", "BARE"),
|
||||
("basemake", "Base Makefile"),
|
||||
("bash", "Bash"),
|
||||
("batch", "Batchfile"),
|
||||
("bbcbasic", "BBC Basic"),
|
||||
("bbcode", "BBCode"),
|
||||
("bc", "BC"),
|
||||
("bdd", "Bdd"),
|
||||
("befunge", "Befunge"),
|
||||
("berry", "Berry"),
|
||||
("bibtex", "BibTeX"),
|
||||
("blitzbasic", "BlitzBasic"),
|
||||
("blitzmax", "BlitzMax"),
|
||||
("bnf", "BNF"),
|
||||
("boa", "Boa"),
|
||||
("boo", "Boo"),
|
||||
("boogie", "Boogie"),
|
||||
("brainfuck", "Brainfuck"),
|
||||
("bst", "BST"),
|
||||
("bugs", "BUGS"),
|
||||
("c", "C"),
|
||||
("c-objdump", "c-objdump"),
|
||||
("ca65", "ca65 assembler"),
|
||||
("cadl", "cADL"),
|
||||
("camkes", "CAmkES"),
|
||||
("capdl", "CapDL"),
|
||||
("capnp", "Cap'n Proto"),
|
||||
("cbmbas", "CBM BASIC V2"),
|
||||
("cddl", "CDDL"),
|
||||
("ceylon", "Ceylon"),
|
||||
("cfc", "Coldfusion CFC"),
|
||||
("cfengine3", "CFEngine3"),
|
||||
("cfm", "Coldfusion HTML"),
|
||||
("cfs", "cfstatement"),
|
||||
("chaiscript", "ChaiScript"),
|
||||
("chapel", "Chapel"),
|
||||
("charmci", "Charmci"),
|
||||
("cheetah", "Cheetah"),
|
||||
("cirru", "Cirru"),
|
||||
("clay", "Clay"),
|
||||
("clean", "Clean"),
|
||||
("clojure", "Clojure"),
|
||||
("clojurescript", "ClojureScript"),
|
||||
("cmake", "CMake"),
|
||||
("cobol", "COBOL"),
|
||||
("cobolfree", "COBOLFree"),
|
||||
("coffeescript", "CoffeeScript"),
|
||||
("comal", "COMAL-80"),
|
||||
("common-lisp", "Common Lisp"),
|
||||
("componentpascal", "Component Pascal"),
|
||||
("console", "Bash Session"),
|
||||
("coq", "Coq"),
|
||||
("cplint", "cplint"),
|
||||
("cpp", "C++"),
|
||||
("cpp-objdump", "cpp-objdump"),
|
||||
("cpsa", "CPSA"),
|
||||
("cr", "Crystal"),
|
||||
("crmsh", "Crmsh"),
|
||||
("croc", "Croc"),
|
||||
("cryptol", "Cryptol"),
|
||||
("csharp", "C#"),
|
||||
("csound", "Csound Orchestra"),
|
||||
("csound-document", "Csound Document"),
|
||||
("csound-score", "Csound Score"),
|
||||
("css", "CSS"),
|
||||
("css+django", "CSS+Django/Jinja"),
|
||||
("css+genshitext", "CSS+Genshi Text"),
|
||||
("css+lasso", "CSS+Lasso"),
|
||||
("css+mako", "CSS+Mako"),
|
||||
("css+mako", "CSS+Mako"),
|
||||
("css+mozpreproc", "CSS+mozpreproc"),
|
||||
("css+myghty", "CSS+Myghty"),
|
||||
("css+php", "CSS+PHP"),
|
||||
("css+ruby", "CSS+Ruby"),
|
||||
("css+smarty", "CSS+Smarty"),
|
||||
("css+ul4", "CSS+UL4"),
|
||||
("cuda", "CUDA"),
|
||||
("cypher", "Cypher"),
|
||||
("cython", "Cython"),
|
||||
("d", "D"),
|
||||
("d-objdump", "d-objdump"),
|
||||
("dart", "Dart"),
|
||||
("dasm16", "DASM16"),
|
||||
("debcontrol", "Debian Control file"),
|
||||
("debsources", "Debian Sourcelist"),
|
||||
("delphi", "Delphi"),
|
||||
("devicetree", "Devicetree"),
|
||||
("dg", "dg"),
|
||||
("diff", "Diff"),
|
||||
("django", "Django/Jinja"),
|
||||
("docker", "Docker"),
|
||||
("doscon", "MSDOS Session"),
|
||||
("dpatch", "Darcs Patch"),
|
||||
("dtd", "DTD"),
|
||||
("duel", "Duel"),
|
||||
("dylan", "Dylan"),
|
||||
("dylan-console", "Dylan session"),
|
||||
("dylan-lid", "DylanLID"),
|
||||
("earl-grey", "Earl Grey"),
|
||||
("easytrieve", "Easytrieve"),
|
||||
("ebnf", "EBNF"),
|
||||
("ec", "eC"),
|
||||
("ecl", "ECL"),
|
||||
("eiffel", "Eiffel"),
|
||||
("elixir", "Elixir"),
|
||||
("elm", "Elm"),
|
||||
("elpi", "Elpi"),
|
||||
("emacs-lisp", "EmacsLisp"),
|
||||
("email", "E-mail"),
|
||||
("erb", "ERB"),
|
||||
("erl", "Erlang erl session"),
|
||||
("erlang", "Erlang"),
|
||||
("evoque", "Evoque"),
|
||||
("execline", "execline"),
|
||||
("extempore", "xtlang"),
|
||||
("ezhil", "Ezhil"),
|
||||
("factor", "Factor"),
|
||||
("fan", "Fantom"),
|
||||
("fancy", "Fancy"),
|
||||
("felix", "Felix"),
|
||||
("fennel", "Fennel"),
|
||||
("fish", "Fish"),
|
||||
("flatline", "Flatline"),
|
||||
("floscript", "FloScript"),
|
||||
("forth", "Forth"),
|
||||
("fortran", "Fortran"),
|
||||
("fortranfixed", "FortranFixed"),
|
||||
("foxpro", "FoxPro"),
|
||||
("freefem", "Freefem"),
|
||||
("fsharp", "F#"),
|
||||
("fstar", "FStar"),
|
||||
("futhark", "Futhark"),
|
||||
("gap", "GAP"),
|
||||
("gas", "GAS"),
|
||||
("gcode", "g-code"),
|
||||
("gdscript", "GDScript"),
|
||||
("genshi", "Genshi"),
|
||||
("genshitext", "Genshi Text"),
|
||||
("gherkin", "Gherkin"),
|
||||
("glsl", "GLSL"),
|
||||
("gnuplot", "Gnuplot"),
|
||||
("go", "Go"),
|
||||
("golo", "Golo"),
|
||||
("gooddata-cl", "GoodData-CL"),
|
||||
("gosu", "Gosu"),
|
||||
("graphviz", "Graphviz"),
|
||||
("groff", "Groff"),
|
||||
("groovy", "Groovy"),
|
||||
("gsql", "GSQL"),
|
||||
("gst", "Gosu Template"),
|
||||
("haml", "Haml"),
|
||||
("handlebars", "Handlebars"),
|
||||
("haskell", "Haskell"),
|
||||
("haxe", "Haxe"),
|
||||
("haxeml", "Hxml"),
|
||||
("hexdump", "Hexdump"),
|
||||
("hlsl", "HLSL"),
|
||||
("hsail", "HSAIL"),
|
||||
("hspec", "Hspec"),
|
||||
("html", "HTML"),
|
||||
("html+cheetah", "HTML+Cheetah"),
|
||||
("html+django", "HTML+Django/Jinja"),
|
||||
("html+evoque", "HTML+Evoque"),
|
||||
("html+genshi", "HTML+Genshi"),
|
||||
("html+handlebars", "HTML+Handlebars"),
|
||||
("html+lasso", "HTML+Lasso"),
|
||||
("html+mako", "HTML+Mako"),
|
||||
("html+mako", "HTML+Mako"),
|
||||
("html+myghty", "HTML+Myghty"),
|
||||
("html+ng2", "HTML + Angular2"),
|
||||
("html+php", "HTML+PHP"),
|
||||
("html+smarty", "HTML+Smarty"),
|
||||
("html+twig", "HTML+Twig"),
|
||||
("html+ul4", "HTML+UL4"),
|
||||
("html+velocity", "HTML+Velocity"),
|
||||
("http", "HTTP"),
|
||||
("hybris", "Hybris"),
|
||||
("hylang", "Hy"),
|
||||
("i6t", "Inform 6 template"),
|
||||
("icon", "Icon"),
|
||||
("idl", "IDL"),
|
||||
("idris", "Idris"),
|
||||
("iex", "Elixir iex session"),
|
||||
("igor", "Igor"),
|
||||
("inform6", "Inform 6"),
|
||||
("inform7", "Inform 7"),
|
||||
("ini", "INI"),
|
||||
("io", "Io"),
|
||||
("ioke", "Ioke"),
|
||||
("ipython2", "IPython"),
|
||||
("ipython3", "IPython3"),
|
||||
("ipythonconsole", "IPython console session"),
|
||||
("irc", "IRC logs"),
|
||||
("isabelle", "Isabelle"),
|
||||
("j", "J"),
|
||||
("jags", "JAGS"),
|
||||
("jasmin", "Jasmin"),
|
||||
("java", "Java"),
|
||||
("javascript", "JavaScript"),
|
||||
("javascript+cheetah", "JavaScript+Cheetah"),
|
||||
("javascript+django", "JavaScript+Django/Jinja"),
|
||||
("javascript+lasso", "JavaScript+Lasso"),
|
||||
("javascript+mako", "JavaScript+Mako"),
|
||||
("javascript+mozpreproc", "Javascript+mozpreproc"),
|
||||
("javascript+myghty", "JavaScript+Myghty"),
|
||||
("javascript+php", "JavaScript+PHP"),
|
||||
("javascript+ruby", "JavaScript+Ruby"),
|
||||
("javascript+smarty", "JavaScript+Smarty"),
|
||||
("jcl", "JCL"),
|
||||
("jlcon", "Julia console"),
|
||||
("jmespath", "JMESPath"),
|
||||
("js+genshitext", "JavaScript+Genshi Text"),
|
||||
("js+mako", "JavaScript+Mako"),
|
||||
("js+ul4", "Javascript+UL4"),
|
||||
("jsgf", "JSGF"),
|
||||
("jslt", "JSLT"),
|
||||
("json", "JSON"),
|
||||
("jsonld", "JSON-LD"),
|
||||
("jsp", "Java Server Page"),
|
||||
("julia", "Julia"),
|
||||
("juttle", "Juttle"),
|
||||
("k", "K"),
|
||||
("kal", "Kal"),
|
||||
("kconfig", "Kconfig"),
|
||||
("kmsg", "Kernel log"),
|
||||
("koka", "Koka"),
|
||||
("kotlin", "Kotlin"),
|
||||
("kuin", "Kuin"),
|
||||
("lasso", "Lasso"),
|
||||
("lean", "Lean"),
|
||||
("less", "LessCss"),
|
||||
("lighttpd", "Lighttpd configuration file"),
|
||||
("lilypond", "LilyPond"),
|
||||
("limbo", "Limbo"),
|
||||
("liquid", "liquid"),
|
||||
("literate-agda", "Literate Agda"),
|
||||
("literate-cryptol", "Literate Cryptol"),
|
||||
("literate-haskell", "Literate Haskell"),
|
||||
("literate-idris", "Literate Idris"),
|
||||
("livescript", "LiveScript"),
|
||||
("llvm", "LLVM"),
|
||||
("llvm-mir", "LLVM-MIR"),
|
||||
("llvm-mir-body", "LLVM-MIR Body"),
|
||||
("logos", "Logos"),
|
||||
("logtalk", "Logtalk"),
|
||||
("lsl", "LSL"),
|
||||
("lua", "Lua"),
|
||||
("macaulay2", "Macaulay2"),
|
||||
("make", "Makefile"),
|
||||
("mako", "Mako"),
|
||||
("mako", "Mako"),
|
||||
("maql", "MAQL"),
|
||||
("markdown", "Markdown"),
|
||||
("mask", "Mask"),
|
||||
("mason", "Mason"),
|
||||
("mathematica", "Mathematica"),
|
||||
("matlab", "Matlab"),
|
||||
("matlabsession", "Matlab session"),
|
||||
("maxima", "Maxima"),
|
||||
("mcfunction", "MCFunction"),
|
||||
("meson", "Meson"),
|
||||
("mime", "MIME"),
|
||||
("minid", "MiniD"),
|
||||
("miniscript", "MiniScript"),
|
||||
("modelica", "Modelica"),
|
||||
("modula2", "Modula-2"),
|
||||
("monkey", "Monkey"),
|
||||
("monte", "Monte"),
|
||||
("moocode", "MOOCode"),
|
||||
("moonscript", "MoonScript"),
|
||||
("mosel", "Mosel"),
|
||||
("mozhashpreproc", "mozhashpreproc"),
|
||||
("mozpercentpreproc", "mozpercentpreproc"),
|
||||
("mql", "MQL"),
|
||||
("mscgen", "Mscgen"),
|
||||
("mupad", "MuPAD"),
|
||||
("mxml", "MXML"),
|
||||
("myghty", "Myghty"),
|
||||
("mysql", "MySQL"),
|
||||
("nasm", "NASM"),
|
||||
("ncl", "NCL"),
|
||||
("nemerle", "Nemerle"),
|
||||
("nesc", "nesC"),
|
||||
("nestedtext", "NestedText"),
|
||||
("newlisp", "NewLisp"),
|
||||
("newspeak", "Newspeak"),
|
||||
("ng2", "Angular2"),
|
||||
("nginx", "Nginx configuration file"),
|
||||
("nimrod", "Nimrod"),
|
||||
("nit", "Nit"),
|
||||
("nixos", "Nix"),
|
||||
("nodejsrepl", "Node.js REPL console session"),
|
||||
("notmuch", "Notmuch"),
|
||||
("nsis", "NSIS"),
|
||||
("numpy", "NumPy"),
|
||||
("nusmv", "NuSMV"),
|
||||
("objdump", "objdump"),
|
||||
("objdump-nasm", "objdump-nasm"),
|
||||
("objective-c", "Objective-C"),
|
||||
("objective-c++", "Objective-C++"),
|
||||
("objective-j", "Objective-J"),
|
||||
("ocaml", "OCaml"),
|
||||
("octave", "Octave"),
|
||||
("odin", "ODIN"),
|
||||
("omg-idl", "OMG Interface Definition Language"),
|
||||
("ooc", "Ooc"),
|
||||
("opa", "Opa"),
|
||||
("openedge", "OpenEdge ABL"),
|
||||
("output", "Text output"),
|
||||
("pacmanconf", "PacmanConf"),
|
||||
("pan", "Pan"),
|
||||
("parasail", "ParaSail"),
|
||||
("pawn", "Pawn"),
|
||||
("peg", "PEG"),
|
||||
("perl", "Perl"),
|
||||
("perl6", "Perl6"),
|
||||
("php", "PHP"),
|
||||
("pig", "Pig"),
|
||||
("pike", "Pike"),
|
||||
("pkgconfig", "PkgConfig"),
|
||||
("plpgsql", "PL/pgSQL"),
|
||||
("pointless", "Pointless"),
|
||||
("pony", "Pony"),
|
||||
("postgresql", "PostgreSQL SQL dialect"),
|
||||
("postscript", "PostScript"),
|
||||
("pot", "Gettext Catalog"),
|
||||
("pov", "POVRay"),
|
||||
("powershell", "PowerShell"),
|
||||
("praat", "Praat"),
|
||||
("procfile", "Procfile"),
|
||||
("prolog", "Prolog"),
|
||||
("promql", "PromQL"),
|
||||
("properties", "Properties"),
|
||||
("protobuf", "Protocol Buffer"),
|
||||
("psql", "PostgreSQL console (psql)"),
|
||||
("psysh", "PsySH console session for PHP"),
|
||||
("pug", "Pug"),
|
||||
("puppet", "Puppet"),
|
||||
("pwsh-session", "PowerShell Session"),
|
||||
("py+ul4", "Python+UL4"),
|
||||
("py2tb", "Python 2.x Traceback"),
|
||||
("pycon", "Python console session"),
|
||||
("pypylog", "PyPy Log"),
|
||||
("pytb", "Python Traceback"),
|
||||
("python", "Python"),
|
||||
("python2", "Python 2.x"),
|
||||
("q", "Q"),
|
||||
("qbasic", "QBasic"),
|
||||
("qlik", "Qlik"),
|
||||
("qml", "QML"),
|
||||
("qvto", "QVTO"),
|
||||
("racket", "Racket"),
|
||||
("ragel", "Ragel"),
|
||||
("ragel-c", "Ragel in C Host"),
|
||||
("ragel-cpp", "Ragel in CPP Host"),
|
||||
("ragel-d", "Ragel in D Host"),
|
||||
("ragel-em", "Embedded Ragel"),
|
||||
("ragel-java", "Ragel in Java Host"),
|
||||
("ragel-objc", "Ragel in Objective C Host"),
|
||||
("ragel-ruby", "Ragel in Ruby Host"),
|
||||
("rbcon", "Ruby irb session"),
|
||||
("rconsole", "RConsole"),
|
||||
("rd", "Rd"),
|
||||
("reasonml", "ReasonML"),
|
||||
("rebol", "REBOL"),
|
||||
("red", "Red"),
|
||||
("redcode", "Redcode"),
|
||||
("registry", "reg"),
|
||||
("resourcebundle", "ResourceBundle"),
|
||||
("restructuredtext", "reStructuredText"),
|
||||
("rexx", "Rexx"),
|
||||
("rhtml", "RHTML"),
|
||||
("ride", "Ride"),
|
||||
("rita", "Rita"),
|
||||
("rng-compact", "Relax-NG Compact"),
|
||||
("roboconf-graph", "Roboconf Graph"),
|
||||
("roboconf-instances", "Roboconf Instances"),
|
||||
("robotframework", "RobotFramework"),
|
||||
("rql", "RQL"),
|
||||
("rsl", "RSL"),
|
||||
("ruby", "Ruby"),
|
||||
("rust", "Rust"),
|
||||
("sarl", "SARL"),
|
||||
("sas", "SAS"),
|
||||
("sass", "Sass"),
|
||||
("savi", "Savi"),
|
||||
("scala", "Scala"),
|
||||
("scaml", "Scaml"),
|
||||
("scdoc", "scdoc"),
|
||||
("scheme", "Scheme"),
|
||||
("scilab", "Scilab"),
|
||||
("scss", "SCSS"),
|
||||
("sed", "Sed"),
|
||||
("sgf", "SmartGameFormat"),
|
||||
("shen", "Shen"),
|
||||
("shexc", "ShExC"),
|
||||
("sieve", "Sieve"),
|
||||
("silver", "Silver"),
|
||||
("singularity", "Singularity"),
|
||||
("slash", "Slash"),
|
||||
("slim", "Slim"),
|
||||
("slurm", "Slurm"),
|
||||
("smali", "Smali"),
|
||||
("smalltalk", "Smalltalk"),
|
||||
("smarty", "Smarty"),
|
||||
("smithy", "Smithy"),
|
||||
("sml", "Standard ML"),
|
||||
("snbt", "SNBT"),
|
||||
("snobol", "Snobol"),
|
||||
("snowball", "Snowball"),
|
||||
("solidity", "Solidity"),
|
||||
("sophia", "Sophia"),
|
||||
("sp", "SourcePawn"),
|
||||
("sparql", "SPARQL"),
|
||||
("spec", "RPMSpec"),
|
||||
("spice", "Spice"),
|
||||
("splus", "S"),
|
||||
("sql", "SQL"),
|
||||
("sql+jinja", "SQL+Jinja"),
|
||||
("sqlite3", "sqlite3con"),
|
||||
("squidconf", "SquidConf"),
|
||||
("srcinfo", "Srcinfo"),
|
||||
("ssp", "Scalate Server Page"),
|
||||
("stan", "Stan"),
|
||||
("stata", "Stata"),
|
||||
("supercollider", "SuperCollider"),
|
||||
("swift", "Swift"),
|
||||
("swig", "SWIG"),
|
||||
("systemverilog", "systemverilog"),
|
||||
("tads3", "TADS 3"),
|
||||
("tal", "Tal"),
|
||||
("tap", "TAP"),
|
||||
("tasm", "TASM"),
|
||||
("tcl", "Tcl"),
|
||||
("tcsh", "Tcsh"),
|
||||
("tcshcon", "Tcsh Session"),
|
||||
("tea", "Tea"),
|
||||
("teal", "teal"),
|
||||
("teratermmacro", "Tera Term macro"),
|
||||
("termcap", "Termcap"),
|
||||
("terminfo", "Terminfo"),
|
||||
("terraform", "Terraform"),
|
||||
("tex", "TeX"),
|
||||
("text", "Text only"),
|
||||
("thrift", "Thrift"),
|
||||
("ti", "ThingsDB"),
|
||||
("tid", "tiddler"),
|
||||
("tnt", "Typographic Number Theory"),
|
||||
("todotxt", "Todotxt"),
|
||||
("toml", "TOML"),
|
||||
("trac-wiki", "MoinMoin/Trac Wiki markup"),
|
||||
("trafficscript", "TrafficScript"),
|
||||
("treetop", "Treetop"),
|
||||
("tsql", "Transact-SQL"),
|
||||
("turtle", "Turtle"),
|
||||
("twig", "Twig"),
|
||||
("typescript", "TypeScript"),
|
||||
("typoscript", "TypoScript"),
|
||||
("typoscriptcssdata", "TypoScriptCssData"),
|
||||
("typoscripthtmldata", "TypoScriptHtmlData"),
|
||||
("ucode", "ucode"),
|
||||
("ul4", "UL4"),
|
||||
("unicon", "Unicon"),
|
||||
("unixconfig", "Unix/Linux config files"),
|
||||
("urbiscript", "UrbiScript"),
|
||||
("usd", "USD"),
|
||||
("vala", "Vala"),
|
||||
("vb.net", "VB.net"),
|
||||
("vbscript", "VBScript"),
|
||||
("vcl", "VCL"),
|
||||
("vclsnippets", "VCLSnippets"),
|
||||
("vctreestatus", "VCTreeStatus"),
|
||||
("velocity", "Velocity"),
|
||||
("verilog", "verilog"),
|
||||
("vgl", "VGL"),
|
||||
("vhdl", "vhdl"),
|
||||
("vim", "VimL"),
|
||||
("wast", "WebAssembly"),
|
||||
("wdiff", "WDiff"),
|
||||
("webidl", "Web IDL"),
|
||||
("whiley", "Whiley"),
|
||||
("x10", "X10"),
|
||||
("xml", "XML"),
|
||||
("xml+cheetah", "XML+Cheetah"),
|
||||
("xml+django", "XML+Django/Jinja"),
|
||||
("xml+evoque", "XML+Evoque"),
|
||||
("xml+lasso", "XML+Lasso"),
|
||||
("xml+mako", "XML+Mako"),
|
||||
("xml+mako", "XML+Mako"),
|
||||
("xml+myghty", "XML+Myghty"),
|
||||
("xml+php", "XML+PHP"),
|
||||
("xml+ruby", "XML+Ruby"),
|
||||
("xml+smarty", "XML+Smarty"),
|
||||
("xml+ul4", "XML+UL4"),
|
||||
("xml+velocity", "XML+Velocity"),
|
||||
("xorg.conf", "Xorg"),
|
||||
("xquery", "XQuery"),
|
||||
("xslt", "XSLT"),
|
||||
("xtend", "Xtend"),
|
||||
("xul+mozpreproc", "XUL+mozpreproc"),
|
||||
("yaml", "YAML"),
|
||||
("yaml+jinja", "YAML+Jinja"),
|
||||
("yang", "YANG"),
|
||||
("zeek", "Zeek"),
|
||||
("zephir", "Zephir"),
|
||||
("zig", "Zig"),
|
||||
],
|
||||
default="python",
|
||||
max_length=100,
|
||||
),
|
||||
),
|
||||
(
|
||||
"style",
|
||||
models.CharField(
|
||||
choices=[
|
||||
("abap", "abap"),
|
||||
("algol", "algol"),
|
||||
("algol_nu", "algol_nu"),
|
||||
("arduino", "arduino"),
|
||||
("autumn", "autumn"),
|
||||
("borland", "borland"),
|
||||
("bw", "bw"),
|
||||
("colorful", "colorful"),
|
||||
("default", "default"),
|
||||
("dracula", "dracula"),
|
||||
("emacs", "emacs"),
|
||||
("friendly", "friendly"),
|
||||
("friendly_grayscale", "friendly_grayscale"),
|
||||
("fruity", "fruity"),
|
||||
("github-dark", "github-dark"),
|
||||
("gruvbox-dark", "gruvbox-dark"),
|
||||
("gruvbox-light", "gruvbox-light"),
|
||||
("igor", "igor"),
|
||||
("inkpot", "inkpot"),
|
||||
("lilypond", "lilypond"),
|
||||
("lovelace", "lovelace"),
|
||||
("manni", "manni"),
|
||||
("material", "material"),
|
||||
("monokai", "monokai"),
|
||||
("murphy", "murphy"),
|
||||
("native", "native"),
|
||||
("nord", "nord"),
|
||||
("nord-darker", "nord-darker"),
|
||||
("one-dark", "one-dark"),
|
||||
("paraiso-dark", "paraiso-dark"),
|
||||
("paraiso-light", "paraiso-light"),
|
||||
("pastie", "pastie"),
|
||||
("perldoc", "perldoc"),
|
||||
("rainbow_dash", "rainbow_dash"),
|
||||
("rrt", "rrt"),
|
||||
("sas", "sas"),
|
||||
("solarized-dark", "solarized-dark"),
|
||||
("solarized-light", "solarized-light"),
|
||||
("staroffice", "staroffice"),
|
||||
("stata", "stata"),
|
||||
("stata-dark", "stata-dark"),
|
||||
("stata-light", "stata-light"),
|
||||
("tango", "tango"),
|
||||
("trac", "trac"),
|
||||
("vim", "vim"),
|
||||
("vs", "vs"),
|
||||
("xcode", "xcode"),
|
||||
("zenburn", "zenburn"),
|
||||
],
|
||||
default="friendly",
|
||||
max_length=100,
|
||||
),
|
||||
),
|
||||
("highlighted", models.TextField()),
|
||||
(
|
||||
"access",
|
||||
models.CharField(
|
||||
choices=[
|
||||
("public", "Public"),
|
||||
("private", "Private"),
|
||||
("owner-only", "Owner only"),
|
||||
],
|
||||
default="private",
|
||||
max_length=20,
|
||||
verbose_name="Access type",
|
||||
),
|
||||
),
|
||||
(
|
||||
"owner",
|
||||
models.ForeignKey(
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
to=settings.AUTH_USER_MODEL,
|
||||
verbose_name="Snippet owner",
|
||||
),
|
||||
),
|
||||
],
|
||||
options={
|
||||
"ordering": ["created"],
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name="SnippetParticipant",
|
||||
fields=[
|
||||
(
|
||||
"id",
|
||||
models.IntegerField(
|
||||
primary_key=True, serialize=False, verbose_name="ID"
|
||||
),
|
||||
),
|
||||
(
|
||||
"snippet",
|
||||
models.ForeignKey(
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
to="backend.snippet",
|
||||
verbose_name="Associated Snippet",
|
||||
),
|
||||
),
|
||||
(
|
||||
"user",
|
||||
models.ForeignKey(
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
to=settings.AUTH_USER_MODEL,
|
||||
verbose_name="Associated User",
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
]
|
||||
0
backend_legacy/backend/migrations/__init__.py
Normal file
0
backend_legacy/backend/migrations/__init__.py
Normal file
69
backend_legacy/backend/models.py
Normal file
69
backend_legacy/backend/models.py
Normal file
@ -0,0 +1,69 @@
|
||||
from django.db import models
|
||||
from pygments.lexers import get_all_lexers
|
||||
from pygments.styles import get_all_styles
|
||||
from pygments.lexers import get_lexer_by_name
|
||||
from pygments.formatters.html import HtmlFormatter
|
||||
from pygments import highlight
|
||||
|
||||
LEXERS = [item for item in get_all_lexers() if item[1]]
|
||||
LANGUAGE_CHOICES = sorted([(item[1][0], item[0]) for item in LEXERS])
|
||||
STYLE_CHOICES = sorted([(item, item) for item in get_all_styles()])
|
||||
ACCESS_TYPES = (("public", "Public"), ("private", "Private"), ("owner-only", "Owner only"))
|
||||
|
||||
|
||||
class Snippet(models.Model):
|
||||
created = models.DateTimeField(auto_now_add=True)
|
||||
title = models.CharField(max_length=100, blank=True, default='')
|
||||
content = models.TextField()
|
||||
linenos = models.BooleanField(default=False)
|
||||
language = models.CharField(choices=LANGUAGE_CHOICES, default='python', max_length=100)
|
||||
style = models.CharField(choices=STYLE_CHOICES, default='friendly', max_length=100)
|
||||
highlighted = models.TextField()
|
||||
owner = models.ForeignKey(
|
||||
verbose_name="Snippet owner",
|
||||
to="auth.User",
|
||||
on_delete=models.CASCADE
|
||||
)
|
||||
access = models.CharField(
|
||||
verbose_name="Access type",
|
||||
choices=ACCESS_TYPES,
|
||||
default="private",
|
||||
max_length=20
|
||||
)
|
||||
|
||||
def save(self, *args, **kwargs):
|
||||
"""
|
||||
Use the `pygments` library to create a highlighted HTML
|
||||
representation of the code snippet.
|
||||
"""
|
||||
lexer = get_lexer_by_name(self.language)
|
||||
linenos = 'table' if self.linenos else False
|
||||
options = {'title': self.title} if self.title else {}
|
||||
formatter = HtmlFormatter(
|
||||
style=self.style,
|
||||
linenos=linenos,
|
||||
full=True,
|
||||
**options
|
||||
)
|
||||
self.highlighted = highlight(self.content, lexer, formatter)
|
||||
super().save(*args, **kwargs)
|
||||
|
||||
class Meta:
|
||||
ordering = ['created']
|
||||
|
||||
|
||||
class SnippetParticipant(models.Model):
|
||||
id = models.IntegerField(
|
||||
verbose_name="ID",
|
||||
primary_key=True
|
||||
)
|
||||
user = models.ForeignKey(
|
||||
verbose_name="Associated User",
|
||||
to="auth.User",
|
||||
on_delete=models.CASCADE
|
||||
)
|
||||
snippet = models.ForeignKey(
|
||||
verbose_name="Associated Snippet",
|
||||
to=Snippet,
|
||||
on_delete=models.CASCADE
|
||||
)
|
||||
26
backend_legacy/backend/permissions.py
Normal file
26
backend_legacy/backend/permissions.py
Normal file
@ -0,0 +1,26 @@
|
||||
from rest_framework import permissions
|
||||
from backend.models import SnippetParticipant
|
||||
|
||||
|
||||
class IsOwnerOrReadOnly(permissions.BasePermission):
|
||||
"""
|
||||
Custom permission to only allow owners of an object to edit it.
|
||||
"""
|
||||
|
||||
def has_object_permission(self, request, view, obj):
|
||||
# Read permissions are allowed to any request,
|
||||
# so we'll always allow GET, HEAD or OPTIONS requests.
|
||||
if request.method in permissions.SAFE_METHODS:
|
||||
return True
|
||||
|
||||
# Write permissions are only allowed to the owner of the snippet.
|
||||
return obj.owner == request.user
|
||||
|
||||
|
||||
class IsAccessedOrDeny(permissions.BasePermission):
|
||||
|
||||
def has_object_permission(self, request, view, obj):
|
||||
if obj.owner == request.user:
|
||||
return True
|
||||
allowed_users = SnippetParticipant.objects.filter(snippet=obj)
|
||||
return request.user in [i.user for i in allowed_users]
|
||||
39
backend_legacy/backend/serializers.py
Normal file
39
backend_legacy/backend/serializers.py
Normal file
@ -0,0 +1,39 @@
|
||||
from rest_framework import serializers
|
||||
from backend.models import Snippet, SnippetParticipant
|
||||
from django.contrib.auth.models import User
|
||||
|
||||
|
||||
class UserSerializer(serializers.ModelSerializer):
|
||||
snippets = serializers.PrimaryKeyRelatedField(many=True, queryset=Snippet.objects.all())
|
||||
|
||||
class Meta:
|
||||
model = User
|
||||
fields = ['id', 'username', 'snippets']
|
||||
|
||||
|
||||
class SnippetSerializer(serializers.ModelSerializer):
|
||||
class Meta:
|
||||
model = Snippet
|
||||
fields = [
|
||||
"id",
|
||||
"created",
|
||||
"title",
|
||||
"linenos",
|
||||
"language",
|
||||
"style",
|
||||
"owner",
|
||||
"access"
|
||||
]
|
||||
read_only_fields = ["created", "owner"]
|
||||
owner = serializers.ReadOnlyField(source='owner.username')
|
||||
|
||||
|
||||
class SnippetParticipantSerializer(serializers.ModelSerializer):
|
||||
class Meta:
|
||||
model = SnippetParticipant
|
||||
fields = [
|
||||
"id",
|
||||
"user",
|
||||
"snippet"
|
||||
]
|
||||
read_only_fields = ["id"]
|
||||
125
backend_legacy/backend/settings.py
Normal file
125
backend_legacy/backend/settings.py
Normal file
@ -0,0 +1,125 @@
|
||||
"""
|
||||
Django settings for backend project.
|
||||
|
||||
Generated by 'django-admin startproject' using Django 4.1.5.
|
||||
|
||||
For more information on this file, see
|
||||
https://docs.djangoproject.com/en/4.1/topics/settings/
|
||||
|
||||
For the full list of settings and their values, see
|
||||
https://docs.djangoproject.com/en/4.1/ref/settings/
|
||||
"""
|
||||
|
||||
from pathlib import Path
|
||||
|
||||
# Build paths inside the project like this: BASE_DIR / 'subdir'.
|
||||
BASE_DIR = Path(__file__).resolve().parent.parent
|
||||
|
||||
|
||||
# Quick-start development settings - unsuitable for production
|
||||
# See https://docs.djangoproject.com/en/4.1/howto/deployment/checklist/
|
||||
|
||||
# SECURITY WARNING: keep the secret key used in production secret!
|
||||
SECRET_KEY = "django-insecure--d$%ho@_=xo$zrj&k2=#$o&p!b6ll*vi_$l5%pv$d%du0%gh%@"
|
||||
|
||||
# SECURITY WARNING: don't run with debug turned on in production!
|
||||
DEBUG = True
|
||||
|
||||
ALLOWED_HOSTS = []
|
||||
|
||||
|
||||
# Application definition
|
||||
|
||||
INSTALLED_APPS = [
|
||||
"django.contrib.admin",
|
||||
"django.contrib.auth",
|
||||
"django.contrib.contenttypes",
|
||||
"django.contrib.sessions",
|
||||
"django.contrib.messages",
|
||||
"django.contrib.staticfiles",
|
||||
"rest_framework",
|
||||
"backend"
|
||||
]
|
||||
|
||||
MIDDLEWARE = [
|
||||
"django.middleware.security.SecurityMiddleware",
|
||||
"django.contrib.sessions.middleware.SessionMiddleware",
|
||||
"django.middleware.common.CommonMiddleware",
|
||||
"django.middleware.csrf.CsrfViewMiddleware",
|
||||
"django.contrib.auth.middleware.AuthenticationMiddleware",
|
||||
"django.contrib.messages.middleware.MessageMiddleware",
|
||||
"django.middleware.clickjacking.XFrameOptionsMiddleware",
|
||||
]
|
||||
|
||||
ROOT_URLCONF = "backend.urls"
|
||||
|
||||
TEMPLATES = [
|
||||
{
|
||||
"BACKEND": "django.template.backends.django.DjangoTemplates",
|
||||
"DIRS": [],
|
||||
"APP_DIRS": True,
|
||||
"OPTIONS": {
|
||||
"context_processors": [
|
||||
"django.template.context_processors.debug",
|
||||
"django.template.context_processors.request",
|
||||
"django.contrib.auth.context_processors.auth",
|
||||
"django.contrib.messages.context_processors.messages",
|
||||
],
|
||||
},
|
||||
},
|
||||
]
|
||||
|
||||
WSGI_APPLICATION = "backend.wsgi.application"
|
||||
|
||||
|
||||
# Database
|
||||
# https://docs.djangoproject.com/en/4.1/ref/settings/#databases
|
||||
|
||||
DATABASES = {
|
||||
"default": {
|
||||
"ENGINE": "django.db.backends.sqlite3",
|
||||
"NAME": BASE_DIR / "db.sqlite3",
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
# Password validation
|
||||
# https://docs.djangoproject.com/en/4.1/ref/settings/#auth-password-validators
|
||||
|
||||
AUTH_PASSWORD_VALIDATORS = [
|
||||
{
|
||||
"NAME": "django.contrib.auth.password_validation.UserAttributeSimilarityValidator",
|
||||
},
|
||||
{
|
||||
"NAME": "django.contrib.auth.password_validation.MinimumLengthValidator",
|
||||
},
|
||||
{
|
||||
"NAME": "django.contrib.auth.password_validation.CommonPasswordValidator",
|
||||
},
|
||||
{
|
||||
"NAME": "django.contrib.auth.password_validation.NumericPasswordValidator",
|
||||
},
|
||||
]
|
||||
|
||||
|
||||
# Internationalization
|
||||
# https://docs.djangoproject.com/en/4.1/topics/i18n/
|
||||
|
||||
LANGUAGE_CODE = "en-us"
|
||||
|
||||
TIME_ZONE = "UTC"
|
||||
|
||||
USE_I18N = True
|
||||
|
||||
USE_TZ = True
|
||||
|
||||
|
||||
# Static files (CSS, JavaScript, Images)
|
||||
# https://docs.djangoproject.com/en/4.1/howto/static-files/
|
||||
|
||||
STATIC_URL = "static/"
|
||||
|
||||
# Default primary key field type
|
||||
# https://docs.djangoproject.com/en/4.1/ref/settings/#default-auto-field
|
||||
|
||||
DEFAULT_AUTO_FIELD = "django.db.models.BigAutoField"
|
||||
12
backend_legacy/backend/urls.py
Normal file
12
backend_legacy/backend/urls.py
Normal file
@ -0,0 +1,12 @@
|
||||
from django.contrib import admin
|
||||
from django.urls import path, include
|
||||
from backend import views
|
||||
|
||||
urlpatterns = [
|
||||
path("admin/", admin.site.urls),
|
||||
path('users/', views.UserList.as_view()),
|
||||
path('users/<int:pk>/', views.UserDetail.as_view()),
|
||||
path("snippets/", views.SnippetList.as_view()),
|
||||
path("snippet/<int:pk>", views.SnippetDetail.as_view()),
|
||||
path('api-auth/', include('rest_framework.urls')),
|
||||
]
|
||||
41
backend_legacy/backend/views.py
Normal file
41
backend_legacy/backend/views.py
Normal file
@ -0,0 +1,41 @@
|
||||
from backend.models import Snippet, SnippetParticipant
|
||||
from backend.serializers import SnippetSerializer, UserSerializer
|
||||
from rest_framework import generics
|
||||
from django.contrib.auth.models import User
|
||||
from rest_framework import permissions
|
||||
from backend.permissions import IsAccessedOrDeny
|
||||
|
||||
|
||||
class UserList(generics.ListAPIView):
|
||||
queryset = User.objects.all()
|
||||
serializer_class = UserSerializer
|
||||
|
||||
|
||||
class UserDetail(generics.RetrieveAPIView):
|
||||
queryset = User.objects.all()
|
||||
serializer_class = UserSerializer
|
||||
|
||||
|
||||
class SnippetList(generics.ListCreateAPIView):
|
||||
queryset = Snippet.objects.all()
|
||||
serializer_class = SnippetSerializer
|
||||
permission_classes = [permissions.IsAuthenticatedOrReadOnly]
|
||||
|
||||
def perform_create(self, serializer):
|
||||
serializer.save(owner=self.request.user)
|
||||
|
||||
|
||||
class SnippetDetail(generics.RetrieveUpdateDestroyAPIView):
|
||||
queryset = Snippet.objects.all()
|
||||
serializer_class = SnippetSerializer
|
||||
permission_classes = [permissions.IsAuthenticatedOrReadOnly, IsAccessedOrDeny]
|
||||
|
||||
|
||||
class SnippetParticipantList(generics.ListCreateAPIView):
|
||||
queryset = SnippetParticipant.objects.all()
|
||||
serializer_class = SnippetSerializer
|
||||
|
||||
|
||||
class SnippetParticipantDetail(generics.RetrieveUpdateDestroyAPIView):
|
||||
queryset = SnippetParticipant.objects.all()
|
||||
serializer_class = SnippetSerializer
|
||||
16
backend_legacy/backend/wsgi.py
Normal file
16
backend_legacy/backend/wsgi.py
Normal file
@ -0,0 +1,16 @@
|
||||
"""
|
||||
WSGI config for backend project.
|
||||
|
||||
It exposes the WSGI callable as a module-level variable named ``application``.
|
||||
|
||||
For more information on this file, see
|
||||
https://docs.djangoproject.com/en/4.1/howto/deployment/wsgi/
|
||||
"""
|
||||
|
||||
import os
|
||||
|
||||
from django.core.wsgi import get_wsgi_application
|
||||
|
||||
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "backend.settings")
|
||||
|
||||
application = get_wsgi_application()
|
||||
BIN
backend_legacy/db.sqlite3
Normal file
BIN
backend_legacy/db.sqlite3
Normal file
Binary file not shown.
22
backend_legacy/manage.py
Executable file
22
backend_legacy/manage.py
Executable file
@ -0,0 +1,22 @@
|
||||
#!/usr/bin/env python
|
||||
"""Django's command-line utility for administrative tasks."""
|
||||
import os
|
||||
import sys
|
||||
|
||||
|
||||
def main():
|
||||
"""Run administrative tasks."""
|
||||
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "backend.settings")
|
||||
try:
|
||||
from django.core.management import execute_from_command_line
|
||||
except ImportError as exc:
|
||||
raise ImportError(
|
||||
"Couldn't import Django. Are you sure it's installed and "
|
||||
"available on your PYTHONPATH environment variable? Did you "
|
||||
"forget to activate a virtual environment?"
|
||||
) from exc
|
||||
execute_from_command_line(sys.argv)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
0
docker-compose.yml
Normal file
0
docker-compose.yml
Normal file
23
frontend/.gitignore
vendored
Normal file
23
frontend/.gitignore
vendored
Normal file
@ -0,0 +1,23 @@
|
||||
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
|
||||
|
||||
# dependencies
|
||||
/node_modules
|
||||
/.pnp
|
||||
.pnp.js
|
||||
|
||||
# testing
|
||||
/coverage
|
||||
|
||||
# production
|
||||
/build
|
||||
|
||||
# misc
|
||||
.DS_Store
|
||||
.env.local
|
||||
.env.development.local
|
||||
.env.test.local
|
||||
.env.production.local
|
||||
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
70
frontend/README.md
Normal file
70
frontend/README.md
Normal file
@ -0,0 +1,70 @@
|
||||
# Getting Started with Create React App
|
||||
|
||||
This project was bootstrapped with [Create React App](https://github.com/facebook/create-react-app).
|
||||
|
||||
## Available Scripts
|
||||
|
||||
In the project directory, you can run:
|
||||
|
||||
### `npm start`
|
||||
|
||||
Runs the app in the development mode.\
|
||||
Open [http://localhost:3000](http://localhost:3000) to view it in your browser.
|
||||
|
||||
The page will reload when you make changes.\
|
||||
You may also see any lint errors in the console.
|
||||
|
||||
### `npm test`
|
||||
|
||||
Launches the test runner in the interactive watch mode.\
|
||||
See the section about [running tests](https://facebook.github.io/create-react-app/docs/running-tests) for more information.
|
||||
|
||||
### `npm run build`
|
||||
|
||||
Builds the app for production to the `build` folder.\
|
||||
It correctly bundles React in production mode and optimizes the build for the best performance.
|
||||
|
||||
The build is minified and the filenames include the hashes.\
|
||||
Your app is ready to be deployed!
|
||||
|
||||
See the section about [deployment](https://facebook.github.io/create-react-app/docs/deployment) for more information.
|
||||
|
||||
### `npm run eject`
|
||||
|
||||
**Note: this is a one-way operation. Once you `eject`, you can't go back!**
|
||||
|
||||
If you aren't satisfied with the build tool and configuration choices, you can `eject` at any time. This command will remove the single build dependency from your project.
|
||||
|
||||
Instead, it will copy all the configuration files and the transitive dependencies (webpack, Babel, ESLint, etc) right into your project so you have full control over them. All of the commands except `eject` will still work, but they will point to the copied scripts so you can tweak them. At this point you're on your own.
|
||||
|
||||
You don't have to ever use `eject`. The curated feature set is suitable for small and middle deployments, and you shouldn't feel obligated to use this feature. However we understand that this tool wouldn't be useful if you couldn't customize it when you are ready for it.
|
||||
|
||||
## Learn More
|
||||
|
||||
You can learn more in the [Create React App documentation](https://facebook.github.io/create-react-app/docs/getting-started).
|
||||
|
||||
To learn React, check out the [React documentation](https://reactjs.org/).
|
||||
|
||||
### Code Splitting
|
||||
|
||||
This section has moved here: [https://facebook.github.io/create-react-app/docs/code-splitting](https://facebook.github.io/create-react-app/docs/code-splitting)
|
||||
|
||||
### Analyzing the Bundle Size
|
||||
|
||||
This section has moved here: [https://facebook.github.io/create-react-app/docs/analyzing-the-bundle-size](https://facebook.github.io/create-react-app/docs/analyzing-the-bundle-size)
|
||||
|
||||
### Making a Progressive Web App
|
||||
|
||||
This section has moved here: [https://facebook.github.io/create-react-app/docs/making-a-progressive-web-app](https://facebook.github.io/create-react-app/docs/making-a-progressive-web-app)
|
||||
|
||||
### Advanced Configuration
|
||||
|
||||
This section has moved here: [https://facebook.github.io/create-react-app/docs/advanced-configuration](https://facebook.github.io/create-react-app/docs/advanced-configuration)
|
||||
|
||||
### Deployment
|
||||
|
||||
This section has moved here: [https://facebook.github.io/create-react-app/docs/deployment](https://facebook.github.io/create-react-app/docs/deployment)
|
||||
|
||||
### `npm run build` fails to minify
|
||||
|
||||
This section has moved here: [https://facebook.github.io/create-react-app/docs/troubleshooting#npm-run-build-fails-to-minify](https://facebook.github.io/create-react-app/docs/troubleshooting#npm-run-build-fails-to-minify)
|
||||
29860
frontend/package-lock.json
generated
Normal file
29860
frontend/package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
44
frontend/package.json
Normal file
44
frontend/package.json
Normal file
@ -0,0 +1,44 @@
|
||||
{
|
||||
"name": "frontend",
|
||||
"version": "0.1.0",
|
||||
"private": true,
|
||||
"dependencies": {
|
||||
"@fortawesome/fontawesome-free": "^6.4.0",
|
||||
"@testing-library/jest-dom": "^5.16.5",
|
||||
"@testing-library/react": "^13.4.0",
|
||||
"@testing-library/user-event": "^13.5.0",
|
||||
"axios": "^1.4.0",
|
||||
"dayjs": "^1.11.7",
|
||||
"jwt-decode": "^3.1.2",
|
||||
"mdb-react-ui-kit": "^6.0.0",
|
||||
"react": "^18.2.0",
|
||||
"react-dom": "^18.2.0",
|
||||
"react-router-dom": "^6.11.1",
|
||||
"react-scripts": "5.0.1",
|
||||
"web-vitals": "^2.1.4"
|
||||
},
|
||||
"scripts": {
|
||||
"start": "react-scripts start",
|
||||
"build": "react-scripts build",
|
||||
"test": "react-scripts test",
|
||||
"eject": "react-scripts eject"
|
||||
},
|
||||
"eslintConfig": {
|
||||
"extends": [
|
||||
"react-app",
|
||||
"react-app/jest"
|
||||
]
|
||||
},
|
||||
"browserslist": {
|
||||
"production": [
|
||||
">0.2%",
|
||||
"not dead",
|
||||
"not op_mini all"
|
||||
],
|
||||
"development": [
|
||||
"last 1 chrome version",
|
||||
"last 1 firefox version",
|
||||
"last 1 safari version"
|
||||
]
|
||||
}
|
||||
}
|
||||
BIN
frontend/public/favicon.ico
Normal file
BIN
frontend/public/favicon.ico
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 3.8 KiB |
43
frontend/public/index.html
Normal file
43
frontend/public/index.html
Normal file
@ -0,0 +1,43 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<meta name="theme-color" content="#000000" />
|
||||
<meta
|
||||
name="description"
|
||||
content="Web site created using create-react-app"
|
||||
/>
|
||||
<link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png" />
|
||||
<!--
|
||||
manifest.json provides metadata used when your web app is installed on a
|
||||
user's mobile device or desktop. See https://developers.google.com/web/fundamentals/web-app-manifest/
|
||||
-->
|
||||
<link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
|
||||
<!--
|
||||
Notice the use of %PUBLIC_URL% in the tags above.
|
||||
It will be replaced with the URL of the `public` folder during the build.
|
||||
Only files inside the `public` folder can be referenced from the HTML.
|
||||
|
||||
Unlike "/favicon.ico" or "favicon.ico", "%PUBLIC_URL%/favicon.ico" will
|
||||
work correctly both with client-side routing and a non-root public URL.
|
||||
Learn how to configure a non-root public URL by running `npm run build`.
|
||||
-->
|
||||
<title>React App</title>
|
||||
</head>
|
||||
<body>
|
||||
<noscript>You need to enable JavaScript to run this app.</noscript>
|
||||
<div id="root"></div>
|
||||
<!--
|
||||
This HTML file is a template.
|
||||
If you open it directly in the browser, you will see an empty page.
|
||||
|
||||
You can add webfonts, meta tags, or analytics to this file.
|
||||
The build step will place the bundled scripts into the <body> tag.
|
||||
|
||||
To begin the development, run `npm start` or `yarn start`.
|
||||
To create a production bundle, use `npm run build` or `yarn build`.
|
||||
-->
|
||||
</body>
|
||||
</html>
|
||||
BIN
frontend/public/logo192.png
Normal file
BIN
frontend/public/logo192.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 5.2 KiB |
BIN
frontend/public/logo512.png
Normal file
BIN
frontend/public/logo512.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 9.4 KiB |
25
frontend/public/manifest.json
Normal file
25
frontend/public/manifest.json
Normal file
@ -0,0 +1,25 @@
|
||||
{
|
||||
"short_name": "React App",
|
||||
"name": "Create React App Sample",
|
||||
"icons": [
|
||||
{
|
||||
"src": "favicon.ico",
|
||||
"sizes": "64x64 32x32 24x24 16x16",
|
||||
"type": "image/x-icon"
|
||||
},
|
||||
{
|
||||
"src": "logo192.png",
|
||||
"type": "image/png",
|
||||
"sizes": "192x192"
|
||||
},
|
||||
{
|
||||
"src": "logo512.png",
|
||||
"type": "image/png",
|
||||
"sizes": "512x512"
|
||||
}
|
||||
],
|
||||
"start_url": ".",
|
||||
"display": "standalone",
|
||||
"theme_color": "#000000",
|
||||
"background_color": "#ffffff"
|
||||
}
|
||||
3
frontend/public/robots.txt
Normal file
3
frontend/public/robots.txt
Normal file
@ -0,0 +1,3 @@
|
||||
# https://www.robotstxt.org/robotstxt.html
|
||||
User-agent: *
|
||||
Disallow:
|
||||
38
frontend/src/App.css
Normal file
38
frontend/src/App.css
Normal file
@ -0,0 +1,38 @@
|
||||
.App {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.App-logo {
|
||||
height: 40vmin;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
@media (prefers-reduced-motion: no-preference) {
|
||||
.App-logo {
|
||||
animation: App-logo-spin infinite 20s linear;
|
||||
}
|
||||
}
|
||||
|
||||
.App-header {
|
||||
background-color: #282c34;
|
||||
min-height: 100vh;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: calc(10px + 2vmin);
|
||||
color: white;
|
||||
}
|
||||
|
||||
.App-link {
|
||||
color: #61dafb;
|
||||
}
|
||||
|
||||
@keyframes App-logo-spin {
|
||||
from {
|
||||
transform: rotate(0deg);
|
||||
}
|
||||
to {
|
||||
transform: rotate(360deg);
|
||||
}
|
||||
}
|
||||
20
frontend/src/App.js
Normal file
20
frontend/src/App.js
Normal file
@ -0,0 +1,20 @@
|
||||
import './App.css';
|
||||
import HomePage from './pages/HomePage'
|
||||
import { BrowserRouter as Router} from "react-router-dom";
|
||||
import AuthPage from './pages/AuthPage'
|
||||
import { Switch, Route } from 'react-router-dom';
|
||||
|
||||
function App() {
|
||||
return (
|
||||
<Router>
|
||||
<div className="App">
|
||||
<Switch>
|
||||
<Route path="/auth" component={AuthPage} />
|
||||
</Switch>
|
||||
<HomePage />
|
||||
</div>
|
||||
</Router>
|
||||
);
|
||||
}
|
||||
|
||||
export default App;
|
||||
8
frontend/src/App.test.js
Normal file
8
frontend/src/App.test.js
Normal file
@ -0,0 +1,8 @@
|
||||
import { render, screen } from '@testing-library/react';
|
||||
import App from './App';
|
||||
|
||||
test('renders learn react link', () => {
|
||||
render(<App />);
|
||||
const linkElement = screen.getByText(/learn react/i);
|
||||
expect(linkElement).toBeInTheDocument();
|
||||
});
|
||||
72
frontend/src/components/Header.jsx
Normal file
72
frontend/src/components/Header.jsx
Normal file
@ -0,0 +1,72 @@
|
||||
import React, { useState } from 'react';
|
||||
import {
|
||||
MDBContainer,
|
||||
MDBNavbar,
|
||||
MDBNavbarBrand,
|
||||
MDBNavbarToggler,
|
||||
MDBIcon,
|
||||
MDBNavbarNav,
|
||||
MDBNavbarItem,
|
||||
MDBNavbarLink,
|
||||
MDBBtn,
|
||||
MDBDropdown,
|
||||
MDBDropdownToggle,
|
||||
MDBDropdownMenu,
|
||||
MDBDropdownItem,
|
||||
MDBCollapse,
|
||||
} from 'mdb-react-ui-kit';
|
||||
import 'mdb-react-ui-kit/dist/css/mdb.min.css';
|
||||
import "@fortawesome/fontawesome-free/css/all.min.css";
|
||||
|
||||
export default function App() {
|
||||
const [showBasic, setShowBasic] = useState(false);
|
||||
|
||||
return (
|
||||
<MDBNavbar expand='lg' light bgColor='light'>
|
||||
<MDBContainer fluid>
|
||||
<MDBNavbarBrand href='#'>CodeBox</MDBNavbarBrand>
|
||||
|
||||
<MDBNavbarToggler
|
||||
aria-controls='navbarSupportedContent'
|
||||
aria-expanded='false'
|
||||
aria-label='Toggle navigation'
|
||||
onClick={() => setShowBasic(!showBasic)}
|
||||
>
|
||||
<MDBIcon icon='bars' fas />
|
||||
</MDBNavbarToggler>
|
||||
|
||||
<MDBCollapse navbar show={showBasic}>
|
||||
<MDBNavbarNav className='mr-auto mb-2 mb-lg-0'>
|
||||
<MDBNavbarItem>
|
||||
<MDBNavbarLink active aria-current='page' href='#'>
|
||||
Home
|
||||
</MDBNavbarLink>
|
||||
</MDBNavbarItem>
|
||||
<MDBNavbarItem>
|
||||
<MDBNavbarLink href='#'>Link</MDBNavbarLink>
|
||||
</MDBNavbarItem>
|
||||
|
||||
<MDBNavbarItem>
|
||||
<MDBDropdown>
|
||||
<MDBDropdownToggle tag='a' className='nav-link' role='button'>
|
||||
Snippets
|
||||
</MDBDropdownToggle>
|
||||
<MDBDropdownMenu>
|
||||
<MDBDropdownItem link>Public snippets</MDBDropdownItem>
|
||||
<MDBDropdownItem link>My snippets</MDBDropdownItem>
|
||||
<MDBDropdownItem link>Something else here</MDBDropdownItem>
|
||||
</MDBDropdownMenu>
|
||||
</MDBDropdown>
|
||||
</MDBNavbarItem>
|
||||
|
||||
<MDBNavbarItem>
|
||||
<MDBNavbarLink disabled href='#' tabIndex={-1} aria-disabled='true' background='#3b71ca'>
|
||||
New snippet
|
||||
</MDBNavbarLink>
|
||||
</MDBNavbarItem>
|
||||
</MDBNavbarNav>
|
||||
</MDBCollapse>
|
||||
</MDBContainer>
|
||||
</MDBNavbar>
|
||||
);
|
||||
}
|
||||
78
frontend/src/components/LoginForm.jsx
Normal file
78
frontend/src/components/LoginForm.jsx
Normal file
@ -0,0 +1,78 @@
|
||||
import React, { useState } from 'react';
|
||||
import {
|
||||
MDBContainer,
|
||||
MDBTabs,
|
||||
MDBTabsItem,
|
||||
MDBTabsLink,
|
||||
MDBTabsContent,
|
||||
MDBTabsPane,
|
||||
MDBBtn,
|
||||
MDBIcon,
|
||||
MDBInput,
|
||||
MDBCheckbox
|
||||
}
|
||||
from 'mdb-react-ui-kit';
|
||||
import 'mdb-react-ui-kit/dist/css/mdb.min.css';
|
||||
import "@fortawesome/fontawesome-free/css/all.min.css";
|
||||
|
||||
const LoginForm = () => {
|
||||
|
||||
const [justifyActive, setJustifyActive] = useState('tab1');;
|
||||
|
||||
const handleJustifyClick = (value) => {
|
||||
if (value === justifyActive) {
|
||||
return;
|
||||
}
|
||||
|
||||
setJustifyActive(value);
|
||||
};
|
||||
|
||||
return (
|
||||
<MDBContainer className="p-3 my-5 d-flex flex-column w-50">
|
||||
|
||||
<MDBTabs pills justify className='mb-3 d-flex flex-row justify-content-between'>
|
||||
<MDBTabsItem>
|
||||
<MDBTabsLink onClick={() => handleJustifyClick('tab1')} active={justifyActive === 'tab1'}>
|
||||
Login
|
||||
</MDBTabsLink>
|
||||
</MDBTabsItem>
|
||||
<MDBTabsItem>
|
||||
<MDBTabsLink onClick={() => handleJustifyClick('tab2')} active={justifyActive === 'tab2'}>
|
||||
Register
|
||||
</MDBTabsLink>
|
||||
</MDBTabsItem>
|
||||
</MDBTabs>
|
||||
|
||||
<MDBTabsContent>
|
||||
|
||||
<MDBTabsPane show={justifyActive === 'tab1'}>
|
||||
|
||||
<MDBInput wrapperClass='mb-4' label='Username' id='form1' type='email'/>
|
||||
<MDBInput wrapperClass='mb-4' label='Password' id='form2' type='password'/>
|
||||
|
||||
<div className="d-flex justify-content-between mx-4 mb-4">
|
||||
<MDBCheckbox name='flexCheck' value='' id='flexCheckDefault' label='Remember me' />
|
||||
</div>
|
||||
|
||||
<MDBBtn className="mb-4 w-100">Sign in</MDBBtn>
|
||||
<p className="text-center">Not a member? <a href="#!" onClick={() => handleJustifyClick('tab2')} active={justifyActive === 'tab2'}>Register</a></p>
|
||||
|
||||
</MDBTabsPane>
|
||||
|
||||
<MDBTabsPane show={justifyActive === 'tab2'}>
|
||||
|
||||
<MDBInput wrapperClass='mb-4' label='Username' id='form1' type='text'/>
|
||||
<MDBInput wrapperClass='mb-4' label='Password' id='form1' type='password'/>
|
||||
|
||||
<MDBBtn className="mb-4 w-100">Sign up</MDBBtn>
|
||||
<p className="text-center">Already have an account? <a href="#!" onClick={() => handleJustifyClick('tab1')} active={justifyActive === 'tab1'}>Login</a></p>
|
||||
|
||||
</MDBTabsPane>
|
||||
|
||||
</MDBTabsContent>
|
||||
|
||||
</MDBContainer>
|
||||
);
|
||||
}
|
||||
|
||||
export default LoginForm;
|
||||
35
frontend/src/components/MainCard.jsx
Normal file
35
frontend/src/components/MainCard.jsx
Normal file
@ -0,0 +1,35 @@
|
||||
import React from 'react';
|
||||
import {
|
||||
MDBCard,
|
||||
MDBCardBody,
|
||||
MDBCardTitle,
|
||||
MDBCardText,
|
||||
MDBCardImage,
|
||||
MDBBtn,
|
||||
MDBRipple
|
||||
} from 'mdb-react-ui-kit';
|
||||
import 'mdb-react-ui-kit/dist/css/mdb.min.css';
|
||||
import "@fortawesome/fontawesome-free/css/all.min.css";
|
||||
import { Link } from 'react-router-dom';
|
||||
|
||||
const MainCard = () => {
|
||||
return (
|
||||
<>
|
||||
<MDBCard>
|
||||
<MDBCardBody>
|
||||
<MDBCardTitle>Welcome to CodeBox!</MDBCardTitle>
|
||||
<MDBCardText>
|
||||
CodeBox is a snippet service to let you securely store your code snippets and share them with your friends, colleagues and others! Register and start sharing your code for free!
|
||||
</MDBCardText>
|
||||
|
||||
<Link to='/auth'>Register</Link>
|
||||
|
||||
</MDBCardBody>
|
||||
</MDBCard>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
|
||||
export default MainCard;
|
||||
25
frontend/src/components/Snippet.jsx
Normal file
25
frontend/src/components/Snippet.jsx
Normal file
@ -0,0 +1,25 @@
|
||||
import React from 'react';
|
||||
import {
|
||||
MDBCard,
|
||||
MDBCardBody,
|
||||
MDBCardTitle,
|
||||
MDBCardText,
|
||||
} from 'mdb-react-ui-kit';
|
||||
import 'mdb-react-ui-kit/dist/css/mdb.min.css';
|
||||
import "@fortawesome/fontawesome-free/css/all.min.css";
|
||||
|
||||
const Snippet = ({title, text}) => {
|
||||
return (
|
||||
<MDBCard>
|
||||
<MDBCardBody>
|
||||
<MDBCardTitle>{title}</MDBCardTitle>
|
||||
<MDBCardText>
|
||||
{text}
|
||||
</MDBCardText>
|
||||
</MDBCardBody>
|
||||
</MDBCard>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
export default Snippet;
|
||||
95
frontend/src/context/AuthContext.jsx
Normal file
95
frontend/src/context/AuthContext.jsx
Normal file
@ -0,0 +1,95 @@
|
||||
import { createContext, useState, useEffect } from "react";
|
||||
import jwt_decode from "jwt-decode";
|
||||
import { useHistory } from "react-router-dom";
|
||||
|
||||
const AuthContext = createContext();
|
||||
|
||||
export default AuthContext;
|
||||
|
||||
export const AuthProvider = ({ children }) => {
|
||||
const [authTokens, setAuthTokens] = useState(() =>
|
||||
localStorage.getItem("authTokens")
|
||||
? JSON.parse(localStorage.getItem("authTokens"))
|
||||
: null
|
||||
);
|
||||
const [user, setUser] = useState(() =>
|
||||
localStorage.getItem("authTokens")
|
||||
? jwt_decode(localStorage.getItem("authTokens"))
|
||||
: null
|
||||
);
|
||||
const [loading, setLoading] = useState(true);
|
||||
|
||||
const history = useHistory();
|
||||
|
||||
const loginUser = async (username, password) => {
|
||||
const response = await fetch("http://127.0.0.1:8000/api/auth/token/", {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json"
|
||||
},
|
||||
body: JSON.stringify({
|
||||
username,
|
||||
password
|
||||
})
|
||||
});
|
||||
const data = await response.json();
|
||||
|
||||
if (response.status === 200) {
|
||||
setAuthTokens(data);
|
||||
setUser(jwt_decode(data.access));
|
||||
localStorage.setItem("authTokens", JSON.stringify(data));
|
||||
history.push("/");
|
||||
} else {
|
||||
alert("Something went wrong!");
|
||||
}
|
||||
};
|
||||
|
||||
const registerUser = async (username, password, password2) => {
|
||||
const response = await fetch("http://127.0.0.1:8000/api/auth/register/", {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json"
|
||||
},
|
||||
body: JSON.stringify({
|
||||
username,
|
||||
password,
|
||||
password2
|
||||
})
|
||||
});
|
||||
if (response.status === 201) {
|
||||
history.push("/login");
|
||||
} else {
|
||||
alert("Something went wrong!");
|
||||
}
|
||||
};
|
||||
|
||||
const logoutUser = () => {
|
||||
setAuthTokens(null);
|
||||
setUser(null);
|
||||
localStorage.removeItem("authTokens");
|
||||
history.push("/");
|
||||
};
|
||||
|
||||
const contextData = {
|
||||
user,
|
||||
setUser,
|
||||
authTokens,
|
||||
setAuthTokens,
|
||||
registerUser,
|
||||
loginUser,
|
||||
logoutUser
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (authTokens) {
|
||||
setUser(jwt_decode(authTokens.access));
|
||||
}
|
||||
setLoading(false);
|
||||
}, [authTokens, loading]);
|
||||
|
||||
return (
|
||||
<AuthContext.Provider value={contextData}>
|
||||
{loading ? null : children}
|
||||
</AuthContext.Provider>
|
||||
);
|
||||
};
|
||||
14
frontend/src/index.css
Normal file
14
frontend/src/index.css
Normal file
@ -0,0 +1,14 @@
|
||||
body {
|
||||
margin: 0;
|
||||
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen',
|
||||
'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue',
|
||||
sans-serif;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
background: #d8d8d8;
|
||||
}
|
||||
|
||||
code {
|
||||
font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New',
|
||||
monospace;
|
||||
}
|
||||
17
frontend/src/index.js
Normal file
17
frontend/src/index.js
Normal file
@ -0,0 +1,17 @@
|
||||
import React from 'react';
|
||||
import ReactDOM from 'react-dom/client';
|
||||
import './index.css';
|
||||
import App from './App';
|
||||
import reportWebVitals from './reportWebVitals';
|
||||
|
||||
const root = ReactDOM.createRoot(document.getElementById('root'));
|
||||
root.render(
|
||||
<React.StrictMode>
|
||||
<App />
|
||||
</React.StrictMode>
|
||||
);
|
||||
|
||||
// If you want to start measuring performance in your app, pass a function
|
||||
// to log results (for example: reportWebVitals(console.log))
|
||||
// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals
|
||||
reportWebVitals();
|
||||
1
frontend/src/logo.svg
Normal file
1
frontend/src/logo.svg
Normal file
@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 841.9 595.3"><g fill="#61DAFB"><path d="M666.3 296.5c0-32.5-40.7-63.3-103.1-82.4 14.4-63.6 8-114.2-20.2-130.4-6.5-3.8-14.1-5.6-22.4-5.6v22.3c4.6 0 8.3.9 11.4 2.6 13.6 7.8 19.5 37.5 14.9 75.7-1.1 9.4-2.9 19.3-5.1 29.4-19.6-4.8-41-8.5-63.5-10.9-13.5-18.5-27.5-35.3-41.6-50 32.6-30.3 63.2-46.9 84-46.9V78c-27.5 0-63.5 19.6-99.9 53.6-36.4-33.8-72.4-53.2-99.9-53.2v22.3c20.7 0 51.4 16.5 84 46.6-14 14.7-28 31.4-41.3 49.9-22.6 2.4-44 6.1-63.6 11-2.3-10-4-19.7-5.2-29-4.7-38.2 1.1-67.9 14.6-75.8 3-1.8 6.9-2.6 11.5-2.6V78.5c-8.4 0-16 1.8-22.6 5.6-28.1 16.2-34.4 66.7-19.9 130.1-62.2 19.2-102.7 49.9-102.7 82.3 0 32.5 40.7 63.3 103.1 82.4-14.4 63.6-8 114.2 20.2 130.4 6.5 3.8 14.1 5.6 22.5 5.6 27.5 0 63.5-19.6 99.9-53.6 36.4 33.8 72.4 53.2 99.9 53.2 8.4 0 16-1.8 22.6-5.6 28.1-16.2 34.4-66.7 19.9-130.1 62-19.1 102.5-49.9 102.5-82.3zm-130.2-66.7c-3.7 12.9-8.3 26.2-13.5 39.5-4.1-8-8.4-16-13.1-24-4.6-8-9.5-15.8-14.4-23.4 14.2 2.1 27.9 4.7 41 7.9zm-45.8 106.5c-7.8 13.5-15.8 26.3-24.1 38.2-14.9 1.3-30 2-45.2 2-15.1 0-30.2-.7-45-1.9-8.3-11.9-16.4-24.6-24.2-38-7.6-13.1-14.5-26.4-20.8-39.8 6.2-13.4 13.2-26.8 20.7-39.9 7.8-13.5 15.8-26.3 24.1-38.2 14.9-1.3 30-2 45.2-2 15.1 0 30.2.7 45 1.9 8.3 11.9 16.4 24.6 24.2 38 7.6 13.1 14.5 26.4 20.8 39.8-6.3 13.4-13.2 26.8-20.7 39.9zm32.3-13c5.4 13.4 10 26.8 13.8 39.8-13.1 3.2-26.9 5.9-41.2 8 4.9-7.7 9.8-15.6 14.4-23.7 4.6-8 8.9-16.1 13-24.1zM421.2 430c-9.3-9.6-18.6-20.3-27.8-32 9 .4 18.2.7 27.5.7 9.4 0 18.7-.2 27.8-.7-9 11.7-18.3 22.4-27.5 32zm-74.4-58.9c-14.2-2.1-27.9-4.7-41-7.9 3.7-12.9 8.3-26.2 13.5-39.5 4.1 8 8.4 16 13.1 24 4.7 8 9.5 15.8 14.4 23.4zM420.7 163c9.3 9.6 18.6 20.3 27.8 32-9-.4-18.2-.7-27.5-.7-9.4 0-18.7.2-27.8.7 9-11.7 18.3-22.4 27.5-32zm-74 58.9c-4.9 7.7-9.8 15.6-14.4 23.7-4.6 8-8.9 16-13 24-5.4-13.4-10-26.8-13.8-39.8 13.1-3.1 26.9-5.8 41.2-7.9zm-90.5 125.2c-35.4-15.1-58.3-34.9-58.3-50.6 0-15.7 22.9-35.6 58.3-50.6 8.6-3.7 18-7 27.7-10.1 5.7 19.6 13.2 40 22.5 60.9-9.2 20.8-16.6 41.1-22.2 60.6-9.9-3.1-19.3-6.5-28-10.2zM310 490c-13.6-7.8-19.5-37.5-14.9-75.7 1.1-9.4 2.9-19.3 5.1-29.4 19.6 4.8 41 8.5 63.5 10.9 13.5 18.5 27.5 35.3 41.6 50-32.6 30.3-63.2 46.9-84 46.9-4.5-.1-8.3-1-11.3-2.7zm237.2-76.2c4.7 38.2-1.1 67.9-14.6 75.8-3 1.8-6.9 2.6-11.5 2.6-20.7 0-51.4-16.5-84-46.6 14-14.7 28-31.4 41.3-49.9 22.6-2.4 44-6.1 63.6-11 2.3 10.1 4.1 19.8 5.2 29.1zm38.5-66.7c-8.6 3.7-18 7-27.7 10.1-5.7-19.6-13.2-40-22.5-60.9 9.2-20.8 16.6-41.1 22.2-60.6 9.9 3.1 19.3 6.5 28.1 10.2 35.4 15.1 58.3 34.9 58.3 50.6-.1 15.7-23 35.6-58.4 50.6zM320.8 78.4z"/><circle cx="420.9" cy="296.5" r="45.7"/><path d="M520.5 78.1z"/></g></svg>
|
||||
|
After Width: | Height: | Size: 2.6 KiB |
12
frontend/src/pages/AuthPage.jsx
Normal file
12
frontend/src/pages/AuthPage.jsx
Normal file
@ -0,0 +1,12 @@
|
||||
import LoginForm from '../components/LoginForm'
|
||||
import BasicPage from './BasicPage'
|
||||
|
||||
const Page = () => {
|
||||
return (
|
||||
<BasicPage>
|
||||
<LoginForm />
|
||||
</BasicPage>
|
||||
);
|
||||
}
|
||||
|
||||
export default Page;
|
||||
13
frontend/src/pages/BasicPage.jsx
Normal file
13
frontend/src/pages/BasicPage.jsx
Normal file
@ -0,0 +1,13 @@
|
||||
import Header from '../components/Header'
|
||||
import { BrowserRouter as Router, Route } from 'react-router-dom';
|
||||
|
||||
function BasicPage(props){
|
||||
return (
|
||||
<>
|
||||
<Header />
|
||||
{props.children}
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
export default BasicPage;
|
||||
12
frontend/src/pages/HomePage.jsx
Normal file
12
frontend/src/pages/HomePage.jsx
Normal file
@ -0,0 +1,12 @@
|
||||
import BasicPage from './BasicPage'
|
||||
import MainCard from '../components/MainCard'
|
||||
|
||||
const Page = () => {
|
||||
return (
|
||||
<BasicPage>
|
||||
<MainCard />
|
||||
</BasicPage>
|
||||
);
|
||||
}
|
||||
|
||||
export default Page;
|
||||
13
frontend/src/reportWebVitals.js
Normal file
13
frontend/src/reportWebVitals.js
Normal file
@ -0,0 +1,13 @@
|
||||
const reportWebVitals = onPerfEntry => {
|
||||
if (onPerfEntry && onPerfEntry instanceof Function) {
|
||||
import('web-vitals').then(({ getCLS, getFID, getFCP, getLCP, getTTFB }) => {
|
||||
getCLS(onPerfEntry);
|
||||
getFID(onPerfEntry);
|
||||
getFCP(onPerfEntry);
|
||||
getLCP(onPerfEntry);
|
||||
getTTFB(onPerfEntry);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
export default reportWebVitals;
|
||||
5
frontend/src/setupTests.js
Normal file
5
frontend/src/setupTests.js
Normal file
@ -0,0 +1,5 @@
|
||||
// jest-dom adds custom jest matchers for asserting on DOM nodes.
|
||||
// allows you to do things like:
|
||||
// expect(element).toHaveTextContent(/react/i)
|
||||
// learn more: https://github.com/testing-library/jest-dom
|
||||
import '@testing-library/jest-dom';
|
||||
10
frontend/src/utils/PrivateRoute.jsx
Normal file
10
frontend/src/utils/PrivateRoute.jsx
Normal file
@ -0,0 +1,10 @@
|
||||
import { Route, Redirect } from "react-router-dom";
|
||||
import { useContext } from "react";
|
||||
import AuthContext from "../context/AuthContext";
|
||||
|
||||
const PrivateRoute = ({ children, ...rest }) => {
|
||||
let { user } = useContext(AuthContext);
|
||||
return <Route {...rest}>{!user ? <Redirect to="/login" /> : children}</Route>;
|
||||
};
|
||||
|
||||
export default PrivateRoute;
|
||||
39
frontend/src/utils/useAxios.jsx
Normal file
39
frontend/src/utils/useAxios.jsx
Normal file
@ -0,0 +1,39 @@
|
||||
import axios from "axios";
|
||||
import jwt_decode from "jwt-decode";
|
||||
import dayjs from "dayjs";
|
||||
import { useContext } from "react";
|
||||
import AuthContext from "../context/AuthContext";
|
||||
|
||||
const baseURL = "http://127.0.0.1:8000/api/auth";
|
||||
|
||||
const useAxios = () => {
|
||||
const { authTokens, setUser, setAuthTokens } = useContext(AuthContext);
|
||||
|
||||
const axiosInstance = axios.create({
|
||||
baseURL,
|
||||
headers: { Authorization: `Bearer ${authTokens?.access}` }
|
||||
});
|
||||
|
||||
axiosInstance.interceptors.request.use(async req => {
|
||||
const user = jwt_decode(authTokens.access);
|
||||
const isExpired = dayjs.unix(user.exp).diff(dayjs()) < 1;
|
||||
|
||||
if (!isExpired) return req;
|
||||
|
||||
const response = await axios.post(`${baseURL}/token/`, {
|
||||
refresh: authTokens.refresh
|
||||
});
|
||||
|
||||
localStorage.setItem("authTokens", JSON.stringify(response.data));
|
||||
|
||||
setAuthTokens(response.data);
|
||||
setUser(jwt_decode(response.data.access));
|
||||
|
||||
req.headers.Authorization = `Bearer ${response.data.access}`;
|
||||
return req;
|
||||
});
|
||||
|
||||
return axiosInstance;
|
||||
};
|
||||
|
||||
export default useAxios;
|
||||
Reference in New Issue
Block a user