Initial commit

This commit is contained in:
2023-05-12 07:31:04 +03:00
commit 786a6a9abb
70 changed files with 32822 additions and 0 deletions

3
.gitignore vendored Normal file
View File

@ -0,0 +1,3 @@
**/node_modules
*.pyc
**/__pycache__

View File

16
backend/backend/asgi.py Normal file
View 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
View 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
View 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
View 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()

View File

View File

@ -0,0 +1,3 @@
from django.contrib import admin
# Register your models here.

View File

@ -0,0 +1,6 @@
from django.apps import AppConfig
class AuthConfig(AppConfig):
default_auto_field = "django.db.models.BigAutoField"
name = "custom_auth"

View File

@ -0,0 +1,3 @@
from django.db import models
# Create your models here.

View File

@ -0,0 +1,3 @@
from django.test import TestCase
# Create your tests here.

View 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())
]

View 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

Binary file not shown.

22
backend/manage.py Executable file
View 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()

View File

21
backend/snippets/admin.py Normal file
View 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
View File

@ -0,0 +1,6 @@
from django.apps import AppConfig
class SnippetsConfig(AppConfig):
default_auto_field = "django.db.models.BigAutoField"
name = "snippets"

View 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",
),
),
],
),
]

View File

View 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
)

View 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]

View 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"]

View File

@ -0,0 +1,3 @@
from django.test import TestCase
# Create your tests here.

9
backend/snippets/urls.py Normal file
View 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
View 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

View File

View 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)

View 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()

View 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",
),
),
],
),
]

View 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
)

View 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]

View 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"]

View 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"

View 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')),
]

View 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

View 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

Binary file not shown.

22
backend_legacy/manage.py Executable file
View 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
View File

23
frontend/.gitignore vendored Normal file
View 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
View 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

File diff suppressed because it is too large Load Diff

44
frontend/package.json Normal file
View 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

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

View 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

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.2 KiB

BIN
frontend/public/logo512.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.4 KiB

View 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"
}

View File

@ -0,0 +1,3 @@
# https://www.robotstxt.org/robotstxt.html
User-agent: *
Disallow:

38
frontend/src/App.css Normal file
View 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
View 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
View 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();
});

View 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>
);
}

View 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;

View 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;

View 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;

View 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
View 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
View 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
View 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

View File

@ -0,0 +1,12 @@
import LoginForm from '../components/LoginForm'
import BasicPage from './BasicPage'
const Page = () => {
return (
<BasicPage>
<LoginForm />
</BasicPage>
);
}
export default Page;

View 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;

View File

@ -0,0 +1,12 @@
import BasicPage from './BasicPage'
import MainCard from '../components/MainCard'
const Page = () => {
return (
<BasicPage>
<MainCard />
</BasicPage>
);
}
export default Page;

View 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;

View 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';

View 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;

View 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;