diff --git a/.env.example b/.env.example
index a33b168..adff822 100644
--- a/.env.example
+++ b/.env.example
@@ -6,5 +6,4 @@ UID=1000
GID=1000
DATABASE_ENGINE= postgresql_psycopg2
-DATABASE_HOST=db
DATABASE_PORT=5432
diff --git a/.idea/misc.xml b/.idea/misc.xml
index 57e400f..3684797 100644
--- a/.idea/misc.xml
+++ b/.idea/misc.xml
@@ -5,5 +5,5 @@
-
+
\ No newline at end of file
diff --git a/.idea/movie-night-py.iml b/.idea/movie-night-py.iml
index 9a3d6b8..cdbb1e7 100644
--- a/.idea/movie-night-py.iml
+++ b/.idea/movie-night-py.iml
@@ -16,7 +16,7 @@
-
+
diff --git a/Dockerfile b/Dockerfile
index f369ba7..e94a7e1 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -35,4 +35,4 @@ USER web
EXPOSE 8000
-CMD ["gunicorn", "--bind", "0.0.0.0:8000", "--workers", "3", "djangodocker.wsgi:application"]
+CMD ["gunicorn", "--bind", "0.0.0.0:8000", "--workers", "3", "movienight.wsgi:application"]
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..b427bda
--- /dev/null
+++ b/README.md
@@ -0,0 +1,5 @@
+Movie Night API
+=
+
+Requirements:
+- Docker
\ No newline at end of file
diff --git a/docker-compose.yml b/docker-compose.yml
index 7ef1e00..34ef508 100644
--- a/docker-compose.yml
+++ b/docker-compose.yml
@@ -1,6 +1,7 @@
services:
db:
image: postgres:17
+ container_name: movienight-db
environment:
POSTGRES_DB: ${DATABASE_NAME}
POSTGRES_USER: ${DATABASE_USERNAME}
@@ -10,16 +11,23 @@ services:
ports:
- "5432:5432"
volumes:
- - djangodocker_data:/var/lib/postgresql/data
+ - movienight_data:/var/lib/postgresql/data
+ healthcheck:
+ test: ["CMD-SHELL", "pg_isready", "-d", "$DATABASE_NAME"]
+ interval: 30s
+ timeout: 60s
+ retries: 5
+ start_period: 80s
api:
build: .
user: ${UID}:${GID}
- container_name: djangodocker-api
+ container_name: movienight-api
ports:
- "8000:8000"
depends_on:
- - db
+ db:
+ condition: service_healthy
environment:
DJANGO_SECRET_KEY: ${DJANGO_SECRET_KEY}
DEBUG: ${DEBUG}
@@ -40,4 +48,4 @@ services:
- /etc/group:/etc/group:ro
volumes:
- djangodocker_data:
+ movienight_data:
diff --git a/firstRun.sh b/firstRun.sh
index 25960c6..a3d2fa8 100755
--- a/firstRun.sh
+++ b/firstRun.sh
@@ -5,16 +5,16 @@ set -e
read -p "What is the project's name? " -r PROJECT_NAME
if [ -z "$PROJECT_NAME" ]
then
- PROJECT_NAME="djangodocker"
+ PROJECT_NAME="movienight"
fi
echo "===== UPDATING PROJECT NAME ====="
-git ls-files | xargs sed -i "s/djangodocker/${PROJECT_NAME}/g"
+git ls-files | xargs sed -i "s/movienight/${PROJECT_NAME}/g"
echo "Done!"
echo "===== UPDATING ENVIRONMENT ====="
cp .env.example .env
-sed -i "s/djangodocker/${PROJECT_NAME}/g" ./.env
+sed -i "s/movienight/${PROJECT_NAME}/g" ./.env
# SET DATABASE USERNAME
read -p "Enter a username for the database: " -r DATABASE_USERNAME
@@ -30,8 +30,10 @@ then
DATABASE_PASSWORD=$(tr -dc 'A-Za-z0-9' < /dev/urandom | head -c 15)
fi
+# WRITE VARIABLES TO .ENV FILE
SECRET_KEY=$(tr -dc 'A-Za-z0-9' < /dev/urandom | head -c 50)
{
+ echo "DATABASE_HOST=${PROJECT_NAME}-db"
echo "DATABASE_NAME=${PROJECT_NAME}"
echo "DATABASE_USERNAME=${DATABASE_USERNAME}"
echo "DATABASE_PASSWORD=${DATABASE_PASSWORD}"
@@ -39,15 +41,26 @@ SECRET_KEY=$(tr -dc 'A-Za-z0-9' < /dev/urandom | head -c 50)
echo "DJANGO_SECRET_KEY=${SECRET_KEY}"
} >> .env
-mv djangodocker "$PROJECT_NAME"
+# RENAME PROJECT DIRECTORY
+if [ "$PROJECT_NAME" != "movienight" ]; then
+ mv movienight "$PROJECT_NAME"
+fi
echo "===== STARTING DOCKER ====="
docker compose up -d --build
echo "===== MIGRATING DATABASE ====="
-docker exec -ti "${PROJECT_NAME}-api" ./manage.py migrate
+docker exec -ti "${PROJECT_NAME}-api" ./manage.py migrate
-echo "===== CREATE SUPERUSER ====="
-docker exec -ti "${PROJECT_NAME}-api" ./manage.py createsuperuser
+echo "===== CREATING SUPERUSER ====="
+docker exec -ti "${PROJECT_NAME}-api" ./manage.py createsuperuser
+
+echo "===== COLLECTING STATIC FILES ====="
+docker exec -ti "${PROJECT_NAME}-api" ./manage.py collectstatic
+
+echo "===== RESTARTING DOCKER CONTAINERS ====="
+docker compose restart
echo "Success! Go to http://localhost:8000 to see API documentation."
+
+git remote remove origin
diff --git a/manage.py b/manage.py
index 40ad188..e62d946 100755
--- a/manage.py
+++ b/manage.py
@@ -6,7 +6,7 @@ import sys
def main():
"""Run administrative tasks."""
- os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'djangodocker.settings')
+ os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'movienight.settings')
try:
from django.core.management import execute_from_command_line
except ImportError as exc:
diff --git a/djangodocker/__init__.py b/movie_manager/__init__.py
similarity index 100%
rename from djangodocker/__init__.py
rename to movie_manager/__init__.py
diff --git a/movie_manager/admin.py b/movie_manager/admin.py
new file mode 100644
index 0000000..8c38f3f
--- /dev/null
+++ b/movie_manager/admin.py
@@ -0,0 +1,3 @@
+from django.contrib import admin
+
+# Register your models here.
diff --git a/movie_manager/apps.py b/movie_manager/apps.py
new file mode 100644
index 0000000..4061dde
--- /dev/null
+++ b/movie_manager/apps.py
@@ -0,0 +1,6 @@
+from django.apps import AppConfig
+
+
+class MovieManagerConfig(AppConfig):
+ default_auto_field = 'django.db.models.BigAutoField'
+ name = 'movie_manager'
diff --git a/movie_manager/migrations/0001_initial.py b/movie_manager/migrations/0001_initial.py
new file mode 100644
index 0000000..8b7d822
--- /dev/null
+++ b/movie_manager/migrations/0001_initial.py
@@ -0,0 +1,48 @@
+# Generated by Django 5.1.4 on 2025-03-31 04:04
+
+import django.db.models.deletion
+from django.conf import settings
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ initial = True
+
+ dependencies = [
+ migrations.swappable_dependency(settings.AUTH_USER_MODEL),
+ ]
+
+ operations = [
+ migrations.CreateModel(
+ name='Movie',
+ fields=[
+ ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+ ('title', models.CharField(max_length=100)),
+ ('imdb_id', models.CharField(max_length=100)),
+ ('year', models.IntegerField()),
+ ('critic_score', models.CharField(max_length=500)),
+ ('genre', models.CharField(max_length=100)),
+ ('director', models.CharField(max_length=500)),
+ ('actors', models.CharField(max_length=500)),
+ ('plot', models.CharField(max_length=500)),
+ ('poster', models.CharField(max_length=500)),
+ ('last_watched', models.DateTimeField()),
+ ('created_at', models.DateTimeField(auto_now_add=True)),
+ ('updated_at', models.DateTimeField(auto_now=True)),
+ ('deleted_at', models.DateTimeField(blank=True, null=True)),
+ ],
+ ),
+ migrations.CreateModel(
+ name='MovieList',
+ fields=[
+ ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+ ('name', models.CharField(max_length=100)),
+ ('public', models.BooleanField(default=False)),
+ ('created_at', models.DateTimeField(auto_now_add=True)),
+ ('updated_at', models.DateTimeField(auto_now=True)),
+ ('deleted_at', models.DateTimeField(blank=True, null=True)),
+ ('owner', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)),
+ ],
+ ),
+ ]
diff --git a/movie_manager/migrations/0002_alter_movie_options_alter_movielist_options_and_more.py b/movie_manager/migrations/0002_alter_movie_options_alter_movielist_options_and_more.py
new file mode 100644
index 0000000..b0f1663
--- /dev/null
+++ b/movie_manager/migrations/0002_alter_movie_options_alter_movielist_options_and_more.py
@@ -0,0 +1,26 @@
+# Generated by Django 5.1.4 on 2025-04-07 05:02
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('movie_manager', '0001_initial'),
+ ]
+
+ operations = [
+ migrations.AlterModelOptions(
+ name='movie',
+ options={'ordering': ['title']},
+ ),
+ migrations.AlterModelOptions(
+ name='movielist',
+ options={'ordering': ['name']},
+ ),
+ migrations.AddField(
+ model_name='movielist',
+ name='movies',
+ field=models.ManyToManyField(to='movie_manager.movie'),
+ ),
+ ]
diff --git a/movie_manager/migrations/__init__.py b/movie_manager/migrations/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/movie_manager/models.py b/movie_manager/models.py
new file mode 100644
index 0000000..976d611
--- /dev/null
+++ b/movie_manager/models.py
@@ -0,0 +1,40 @@
+from django.db import models
+from django.contrib.auth.models import User
+
+# Create your models here.
+class Movie(models.Model):
+ class Meta:
+ ordering = ["title"]
+
+ title = models.CharField(max_length=100)
+ imdb_id = models.CharField(max_length=100)
+ year = models.IntegerField()
+ critic_score = models.CharField(max_length=500)
+ genre = models.CharField(max_length=100)
+ director = models.CharField(max_length=500)
+ actors = models.CharField(max_length=500)
+ plot = models.CharField(max_length=500)
+ poster = models.CharField(max_length=500)
+ last_watched = models.DateTimeField()
+ created_at = models.DateTimeField(auto_now_add=True)
+ updated_at = models.DateTimeField(auto_now=True)
+ deleted_at = models.DateTimeField(null=True, blank=True)
+
+ def __str__(self):
+ return self.title
+
+
+class MovieList(models.Model):
+ class Meta:
+ ordering = ["name"]
+
+ name = models.CharField(max_length=100)
+ public = models.BooleanField(default=False)
+ owner = models.ForeignKey(User, on_delete=models.CASCADE)
+ movies = models.ManyToManyField(Movie)
+ created_at = models.DateTimeField(auto_now_add=True)
+ updated_at = models.DateTimeField(auto_now=True)
+ deleted_at = models.DateTimeField(null=True, blank=True)
+
+ def __str__(self):
+ return self.name
diff --git a/movie_manager/serializers.py b/movie_manager/serializers.py
new file mode 100644
index 0000000..4a31cd4
--- /dev/null
+++ b/movie_manager/serializers.py
@@ -0,0 +1,21 @@
+from itertools import count
+
+from rest_framework import serializers
+from movie_manager.models import Movie, MovieList
+
+class MovieSerializer(serializers.ModelSerializer):
+ class Meta:
+ model = Movie
+ fields = '__all__'
+
+
+class MovieListSerializer(serializers.ModelSerializer):
+ movie_count = serializers.SerializerMethodField()
+
+ class Meta:
+ model = MovieList
+ fields = ["id","name","owner","public", "movie_count"]
+
+
+ def get_movie_count(self, obj):
+ return len(obj.movies.all())
diff --git a/movie_manager/tests.py b/movie_manager/tests.py
new file mode 100644
index 0000000..7ce503c
--- /dev/null
+++ b/movie_manager/tests.py
@@ -0,0 +1,3 @@
+from django.test import TestCase
+
+# Create your tests here.
diff --git a/movie_manager/views.py b/movie_manager/views.py
new file mode 100644
index 0000000..7d1f3f0
--- /dev/null
+++ b/movie_manager/views.py
@@ -0,0 +1,48 @@
+from django.http import HttpResponse, JsonResponse
+from django.contrib.auth.models import User
+from rest_framework import permissions, viewsets
+from knox.auth import TokenAuthentication
+from rest_framework.exceptions import NotFound
+
+from movie_manager.models import Movie, MovieList
+from movie_manager.serializers import MovieListSerializer, MovieSerializer
+
+
+# Create your views here.
+class MovieViewset(viewsets.ModelViewSet):
+ fields = '__all__'
+ queryset = Movie.objects.all().order_by("title")
+ authentication_classes = [TokenAuthentication]
+ permission_classes = [permissions.IsAuthenticated]
+
+ serializer_class = MovieSerializer
+
+class MovieListViewset(viewsets.ModelViewSet):
+ fields = '__all__'
+ queryset = MovieList.objects.all().order_by("name")
+ authentication_classes = [TokenAuthentication]
+ permission_classes = [permissions.IsAuthenticated]
+
+ serializer_class = MovieListSerializer
+
+ def update(self, request, pk=None, *args, **kwargs):
+ movie_list = MovieList.objects.get(pk=pk)
+ movie_list.name = request.data.get('name')
+ movie_list.owner = User.objects.get(pk=request.data.get("owner"))
+
+ if request.data.get('movies'):
+ movie_ids = request.data.get('movies')
+ for movie_id in movie_ids:
+ try:
+ movie = Movie.objects.get(pk=movie_id)
+ movie_list.movies.add(movie)
+ except Movie.DoesNotExist:
+ raise NotFound(f"Movie {movie_id} does not exist")
+
+ removed_movies = Movie.objects.exclude(id__in=movie_ids)
+ for removed_movie in removed_movies:
+ removed_movie.delete()
+
+ movie_list.save()
+
+ return JsonResponse(MovieListSerializer(movie_list).data)
diff --git a/movienight/__init__.py b/movienight/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/djangodocker/asgi.py b/movienight/asgi.py
similarity index 72%
rename from djangodocker/asgi.py
rename to movienight/asgi.py
index 42ac30c..a6acd95 100644
--- a/djangodocker/asgi.py
+++ b/movienight/asgi.py
@@ -1,5 +1,5 @@
"""
-ASGI config for djangodocker project.
+ASGI config for movienight project.
It exposes the ASGI callable as a module-level variable named ``application``.
@@ -11,6 +11,6 @@ import os
from django.core.asgi import get_asgi_application
-os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'djangodocker.settings')
+os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'movienight.settings')
application = get_asgi_application()
diff --git a/djangodocker/settings.py b/movienight/settings.py
similarity index 94%
rename from djangodocker/settings.py
rename to movienight/settings.py
index 6d5ccc5..4fcd523 100644
--- a/djangodocker/settings.py
+++ b/movienight/settings.py
@@ -28,6 +28,7 @@ SECRET_KEY = os.environ.get("DJANGO_SECRET_KEY")
DEBUG = bool(os.environ.get("DEBUG", default=0))
ALLOWED_HOSTS = os.environ.get("DJANGO_ALLOWED_HOSTS", "127.0.0.1").split(",")
+CORS_ALLOWED_ORIGINS = ["http://localhost:3000"]
# Application definition
@@ -42,11 +43,14 @@ INSTALLED_APPS = [
"rest_framework",
"rest_framework.authtoken",
"knox",
+ "movie_manager",
+ "corsheaders",
]
MIDDLEWARE = [
"django.middleware.security.SecurityMiddleware",
"django.contrib.sessions.middleware.SessionMiddleware",
+ "corsheaders.middleware.CorsMiddleware",
"django.middleware.common.CommonMiddleware",
"django.middleware.csrf.CsrfViewMiddleware",
"django.contrib.auth.middleware.AuthenticationMiddleware",
@@ -54,7 +58,7 @@ MIDDLEWARE = [
"django.middleware.clickjacking.XFrameOptionsMiddleware",
]
-ROOT_URLCONF = "djangodocker.urls"
+ROOT_URLCONF = "movienight.urls"
TEMPLATES = [
{
@@ -72,7 +76,7 @@ TEMPLATES = [
},
]
-WSGI_APPLICATION = "djangodocker.wsgi.application"
+WSGI_APPLICATION = "movienight.wsgi.application"
# Database
diff --git a/djangodocker/urls.py b/movienight/urls.py
similarity index 81%
rename from djangodocker/urls.py
rename to movienight/urls.py
index 52200ad..1cb7bfd 100644
--- a/djangodocker/urls.py
+++ b/movienight/urls.py
@@ -1,5 +1,5 @@
"""
-URL configuration for djangodocker project.
+URL configuration for movienight project.
"""
import knox
@@ -11,11 +11,14 @@ from django.conf import settings
from rest_framework.routers import DefaultRouter
from users import views as user_views
+from movie_manager import views as movie_views
from rest_framework.authtoken.views import obtain_auth_token
router = DefaultRouter()
router.register(r"api/users", user_views.UserViewSet)
router.register(r"api/groups", user_views.GroupViewSet)
+router.register(r"api/movies", movie_views.MovieViewset)
+router.register(r"api/lists", movie_views.MovieListViewset)
urlpatterns = [
path("", include(router.urls)),
diff --git a/djangodocker/wsgi.py b/movienight/wsgi.py
similarity index 72%
rename from djangodocker/wsgi.py
rename to movienight/wsgi.py
index 65d0ca1..afec5f1 100644
--- a/djangodocker/wsgi.py
+++ b/movienight/wsgi.py
@@ -1,5 +1,5 @@
"""
-WSGI config for djangodocker project.
+WSGI config for movienight project.
It exposes the WSGI callable as a module-level variable named ``application``.
@@ -11,6 +11,6 @@ import os
from django.core.wsgi import get_wsgi_application
-os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'djangodocker.settings')
+os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'movienight.settings')
application = get_wsgi_application()
diff --git a/requirements.txt b/requirements.txt
index d3077de..7c9b3b9 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -4,4 +4,5 @@ django-rest-knox
markdown
django-filter
gunicorn==23.0.0
-psycopg2-binary==2.9.10
\ No newline at end of file
+psycopg2-binary==2.9.10
+django-cors-headers==4.7.0
diff --git a/static/admin/js/vendor/jquery/jquery.js b/static/admin/js/vendor/jquery/jquery.js
index 18eb1ff..1a86433 100644
--- a/static/admin/js/vendor/jquery/jquery.js
+++ b/static/admin/js/vendor/jquery/jquery.js
@@ -2144,7 +2144,7 @@ function tokenize( selector, parseOnly ) {
// Return the length of the invalid excess
// if we're just parsing
- // Otherwise, throw an error or return users
+ // Otherwise, throw an error or return tokens
if ( parseOnly ) {
return soFar.length;
}
@@ -2152,7 +2152,7 @@ function tokenize( selector, parseOnly ) {
return soFar ?
find.error( selector ) :
- // Cache the users
+ // Cache the tokens
tokenCache( selector, groups ).slice( 0 );
}
@@ -2655,7 +2655,7 @@ function select( selector, context, results, seed ) {
testContext( context.parentNode ) || context
) ) ) {
- // If seed is empty or no users remain, we can return early
+ // If seed is empty or no tokens remain, we can return early
tokens.splice( i, 1 );
selector = seed.length && toSelector( tokens );
if ( !selector ) {
diff --git a/static/admin/js/vendor/xregexp/xregexp.js b/static/admin/js/vendor/xregexp/xregexp.js
index ad845da..215482c 100644
--- a/static/admin/js/vendor/xregexp/xregexp.js
+++ b/static/admin/js/vendor/xregexp/xregexp.js
@@ -43,7 +43,7 @@ function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len
var _default = function _default(XRegExp) {
/**
* Adds base support for Unicode matching:
- * - Adds syntax `\p{..}` for matching Unicode users. Tokens can be inverted using `\P{..}` or
+ * - Adds syntax `\p{..}` for matching Unicode tokens. Tokens can be inverted using `\P{..}` or
* `\p{^..}`. Token names ignore case, spaces, hyphens, and underscores. You can omit the
* braces for token names that are a single letter (e.g. `\pL` or `PL`).
* - Adds flag A (astral), which enables 21-bit Unicode support.
@@ -129,7 +129,7 @@ var _default = function _default(XRegExp) {
var _context2;
combined += (0, _concat["default"])(_context2 = "".concat(item.astral ? '|' : '', "[")).call(_context2, item.bmp, "]");
- } // Astral Unicode users always match a code point, never a code unit
+ } // Astral Unicode tokens always match a code point, never a code unit
return isNegated ? "(?:(?!".concat(combined, ")(?:[\uD800-\uDBFF][\uDC00-\uDFFF]|[\0-\uFFFF]))") : "(?:".concat(combined, ")");
@@ -154,7 +154,7 @@ var _default = function _default(XRegExp) {
var ERR_UNKNOWN_NAME = 'Unknown Unicode token ';
var ERR_UNKNOWN_REF = 'Unicode token missing data ';
var ERR_ASTRAL_ONLY = 'Astral mode required for Unicode token ';
- var ERR_ASTRAL_IN_CLASS = 'Astral mode does not support Unicode users within character classes';
+ var ERR_ASTRAL_IN_CLASS = 'Astral mode does not support Unicode tokens within character classes';
var _match = (0, _slicedToArray2["default"])(match, 6),
fullToken = _match[0],
@@ -221,7 +221,7 @@ var _default = function _default(XRegExp) {
leadChar: '\\'
});
/**
- * Adds to the list of Unicode users that XRegExp regexes can match via `\p` or `\P`.
+ * Adds to the list of Unicode tokens that XRegExp regexes can match via `\p` or `\P`.
*
* @memberOf XRegExp
* @param {Array} data Objects with named character ranges. Each object may have properties
@@ -239,7 +239,7 @@ var _default = function _default(XRegExp) {
* points. `inverseOf` can be used to avoid duplicating character data if a Unicode token is
* defined as the exact inverse of another token.
* @param {String} [typePrefix] Enables optionally using this type as a prefix for all of the
- * provided Unicode users, e.g. if given `'Type'`, then `\p{TokenName}` can also be written
+ * provided Unicode tokens, e.g. if given `'Type'`, then `\p{TokenName}` can also be written
* as `\p{Type=TokenName}`.
* @example
*
@@ -471,7 +471,7 @@ var fixed = {}; // Storage for regexes cached by `XRegExp.cache`
var regexCache = {}; // Storage for pattern details cached by the `XRegExp` constructor
-var patternCache = {}; // Storage for regex syntax users added internally or by `XRegExp.addToken`
+var patternCache = {}; // Storage for regex syntax tokens added internally or by `XRegExp.addToken`
var tokens = []; // Token scopes
@@ -668,7 +668,7 @@ function copyRegex(regex, options) {
xregexpFlags = flagsToAdd ? clipDuplicates((0, _flags["default"])(xData) + flagsToAdd) : (0, _flags["default"])(xData);
}
} // Augment with `XRegExp.prototype` properties, but use the native `RegExp` constructor to avoid
- // searching for special users. That would be wrong for regexes constructed by `RegExp`, and
+ // searching for special tokens. That would be wrong for regexes constructed by `RegExp`, and
// unnecessary for regexes constructed by `XRegExp` because the regex has already undergone the
// translation to native regex syntax
@@ -706,16 +706,16 @@ function getContextualTokenSeparator(match, scope, flags) {
var precedingChar = match.input[match.index - 1];
var followingChar = match.input[matchEndPos];
- if ( // No need to separate users if at the beginning or end of a group, before or after a
+ if ( // No need to separate tokens if at the beginning or end of a group, before or after a
// group, or before or after a `|`
- /^[()|]$/.test(precedingChar) || /^[()|]$/.test(followingChar) || // No need to separate users if at the beginning or end of the pattern
- match.index === 0 || matchEndPos === match.input.length || // No need to separate users if at the beginning of a noncapturing group or lookaround.
+ /^[()|]$/.test(precedingChar) || /^[()|]$/.test(followingChar) || // No need to separate tokens if at the beginning or end of the pattern
+ match.index === 0 || matchEndPos === match.input.length || // No need to separate tokens if at the beginning of a noncapturing group or lookaround.
// Looks only at the last 4 chars (at most) for perf when constructing long regexes.
- /\(\?(?:[:=!]|<[=!])$/.test(match.input.substring(match.index - 4, match.index)) || // Avoid separating users when the following token is a quantifier
+ /\(\?(?:[:=!]|<[=!])$/.test(match.input.substring(match.index - 4, match.index)) || // Avoid separating tokens when the following token is a quantifier
isQuantifierNext(match.input, matchEndPos, flags)) {
return '';
- } // Keep users separated. This avoids e.g. inadvertedly changing `\1 1` or `\1(?#)1` to `\11`.
- // This also ensures all users remain as discrete atoms, e.g. it prevents converting the
+ } // Keep tokens separated. This avoids e.g. inadvertedly changing `\1 1` or `\1(?#)1` to `\11`.
+ // This also ensures all tokens remain as discrete atoms, e.g. it prevents converting the
// syntax error `(? :` into `(?:`.
@@ -914,13 +914,13 @@ function registerFlag(flag) {
registeredFlags[flag] = true;
}
/**
- * Runs built-in and custom regex syntax users in reverse insertion order at the specified
+ * Runs built-in and custom regex syntax tokens in reverse insertion order at the specified
* position, until a match is found.
*
* @private
* @param {String} pattern Original pattern from which an XRegExp object is being built.
* @param {String} flags Flags being used to construct the regex.
- * @param {Number} pos Position to search for users within `pattern`.
+ * @param {Number} pos Position to search for tokens within `pattern`.
* @param {Number} scope Regex scope to apply: 'default' or 'class'.
* @param {Object} context Context object to use for token handler functions.
* @returns {Object} Object with properties `matchLength`, `output`, and `reparse`; or `null`.
@@ -1055,14 +1055,14 @@ function XRegExp(pattern, flags) {
var applied = prepareFlags(pattern, flags);
var appliedPattern = applied.pattern;
- var appliedFlags = (0, _flags["default"])(applied); // Use XRegExp's users to translate the pattern to a native regex pattern.
- // `appliedPattern.length` may change on each iteration if users use `reparse`
+ var appliedFlags = (0, _flags["default"])(applied); // Use XRegExp's tokens to translate the pattern to a native regex pattern.
+ // `appliedPattern.length` may change on each iteration if tokens use `reparse`
while (pos < appliedPattern.length) {
do {
- // Check for custom users at the current position
+ // Check for custom tokens at the current position
result = runTokens(appliedPattern, appliedFlags, pos, scope, context); // If the matched token used the `reparse` option, splice its output into the
- // pattern before running users again at the same position
+ // pattern before running tokens again at the same position
if (result && result.reparse) {
appliedPattern = (0, _slice["default"])(appliedPattern).call(appliedPattern, 0, pos) + result.output + (0, _slice["default"])(appliedPattern).call(appliedPattern, pos + result.matchLength);
@@ -1091,7 +1091,7 @@ function XRegExp(pattern, flags) {
patternCache[pattern][flags] = {
// Use basic cleanup to collapse repeated empty groups like `(?:)(?:)` to `(?:)`. Empty
- // groups are sometimes inserted during regex transpilation in order to keep users
+ // groups are sometimes inserted during regex transpilation in order to keep tokens
// separated. However, more than one empty group in a row is never needed.
pattern: output.replace(/(?:\(\?:\))+/g, '(?:)'),
// Strip all but native flags
@@ -1151,7 +1151,7 @@ XRegExp._pad4 = pad4;
* not required to trigger the token. This registers the flags, to prevent XRegExp from
* throwing an 'unknown flag' error when any of the flags are used.
* - `reparse` {Boolean} Whether the `handler` function's output should not be treated as
- * final, and instead be reparseable by other users (including the current token). Allows
+ * final, and instead be reparseable by other tokens (including the current token). Allows
* token chaining or deferring.
* - `leadChar` {String} Single character that occurs at the beginning of any successful match
* of the token (not always applicable). This doesn't change the behavior of the token unless
@@ -1204,7 +1204,7 @@ XRegExp.addToken = function (regex, handler, options) {
} finally {
_iterator2.f();
}
- } // Add to the private list of syntax users
+ } // Add to the private list of syntax tokens
tokens.push({
@@ -2035,7 +2035,7 @@ fixed.match = function (regex) {
return fixed.exec.call(regex, nullThrows(this));
};
/**
- * Adds support for `${n}` (or `$`) users for named and numbered backreferences in replacement
+ * Adds support for `${n}` (or `$`) tokens for named and numbered backreferences in replacement
* text, and provides named backreferences to replacement functions as `arguments[0].name`. Also
* fixes browser bugs in replacement text syntax when performing a replacement using a nonregex
* search value, and the value of a replacement regex's `lastIndex` property during replacement
@@ -2271,7 +2271,7 @@ fixed.split = function (separator, limit) {
separator.lastIndex = origLastIndex;
return output.length > limit ? (0, _slice["default"])(output).call(output, 0, limit) : output;
}; // ==--------------------------==
-// Built-in syntax/flag users
+// Built-in syntax/flag tokens
// ==--------------------------==
/*
@@ -2310,7 +2310,7 @@ XRegExp.addToken(/\\u{([\dA-Fa-f]+)}/, function (match, scope, flags) {
if (code <= 0xFFFF) {
// Converting to \uNNNN avoids needing to escape the literal character and keep it
- // separate from preceding users
+ // separate from preceding tokens
return "\\u".concat(pad4(hex(code)));
} // If `code` is between 0xFFFF and 0x10FFFF, require and defer to native handling
diff --git a/users/views.py b/users/views.py
index bb6470e..bcc7f13 100644
--- a/users/views.py
+++ b/users/views.py
@@ -3,7 +3,6 @@ from django.contrib.auth.models import Group, User, AnonymousUser
from rest_framework import permissions, viewsets, status
from knox.auth import TokenAuthentication
from knox.views import LoginView as KnoxLoginView
-from rest_framework.authentication import BasicAuthentication
from rest_framework.authtoken.serializers import AuthTokenSerializer
from rest_framework.response import Response
from rest_framework.decorators import api_view