├── .devcontainer
├── Dockerfile
├── build-assets
│ ├── heroku_config.sh
│ ├── http_server.py
│ └── make_url.py
├── devcontainer.json
└── docker-compose.yml
├── .github
└── ISSUE_TEMPLATE
│ └── user-story.md
├── .gitignore
├── .gitpod.yml
├── .vscode
└── extensions.json
├── Procfile
├── README.md
├── comments
├── __init__.py
├── admin.py
├── apps.py
├── migrations
│ ├── 0001_initial.py
│ └── __init__.py
├── models.py
├── serializers.py
├── tests.py
├── urls.py
└── views.py
├── db.sqlite3
├── drf_api
├── __init__.py
├── asgi.py
├── permissions.py
├── serializers.py
├── settings.py
├── urls.py
├── views.py
└── wsgi.py
├── followers
├── __init__.py
├── admin.py
├── apps.py
├── migrations
│ ├── 0001_initial.py
│ └── __init__.py
├── models.py
├── serializers.py
├── tests.py
├── urls.py
└── views.py
├── frontend
├── .env.development.local
├── package-lock.json
├── package.json
├── public
│ ├── favicon-16x16.png
│ ├── favicon.ico
│ ├── index.html
│ ├── logo192.png
│ ├── logo512.png
│ ├── manifest.json
│ └── robots.txt
└── src
│ ├── App.js
│ ├── App.module.css
│ ├── App.test.js
│ ├── api
│ └── axiosDefaults.js
│ ├── assets
│ ├── logo.png
│ ├── no-results.png
│ └── upload.png
│ ├── components
│ ├── Asset.js
│ ├── Avatar.js
│ ├── MoreDropdown.js
│ ├── NavBar.js
│ ├── NotFound.js
│ └── __tests__
│ │ └── NavBar.test.js
│ ├── contexts
│ ├── CurrentUserContext.js
│ └── ProfileDataContext.js
│ ├── hooks
│ ├── useClickOutsideToggle.js
│ └── useRedirect.js
│ ├── index.css
│ ├── index.js
│ ├── logo.svg
│ ├── mocks
│ └── handlers.js
│ ├── pages
│ ├── auth
│ │ ├── SignInForm.js
│ │ └── SignUpForm.js
│ ├── comments
│ │ ├── Comment.js
│ │ ├── CommentCreateForm.js
│ │ └── CommentEditForm.js
│ ├── posts
│ │ ├── Post.js
│ │ ├── PostCreateForm.js
│ │ ├── PostEditForm.js
│ │ ├── PostPage.js
│ │ └── PostsPage.js
│ └── profiles
│ │ ├── PopularProfiles.js
│ │ ├── Profile.js
│ │ ├── ProfileEditForm.js
│ │ ├── ProfilePage.js
│ │ ├── UserPasswordForm.js
│ │ └── UsernameForm.js
│ ├── reportWebVitals.js
│ ├── setupTests.js
│ ├── styles
│ ├── Asset.module.css
│ ├── Avatar.module.css
│ ├── Button.module.css
│ ├── Comment.module.css
│ ├── CommentCreateEditForm.module.css
│ ├── MoreDropdown.module.css
│ ├── NavBar.module.css
│ ├── NotFound.module.css
│ ├── Post.module.css
│ ├── PostCreateEditForm.module.css
│ ├── PostsPage.module.css
│ ├── Profile.module.css
│ ├── ProfilePage.module.css
│ └── SignInUpForm.module.css
│ └── utils
│ └── utils.js
├── likes
├── __init__.py
├── admin.py
├── apps.py
├── migrations
│ ├── 0001_initial.py
│ └── __init__.py
├── models.py
├── serializers.py
├── tests.py
├── urls.py
└── views.py
├── manage.py
├── package-lock.json
├── posts
├── __init__.py
├── admin.py
├── apps.py
├── migrations
│ ├── 0001_initial.py
│ └── __init__.py
├── models.py
├── serializers.py
├── tests.py
├── urls.py
└── views.py
├── profiles
├── __init__.py
├── admin.py
├── apps.py
├── migrations
│ ├── 0001_initial.py
│ └── __init__.py
├── models.py
├── serializers.py
├── tests.py
├── urls.py
└── views.py
├── requirements.txt
├── runtime.txt
└── staticfiles
├── admin
├── css
│ ├── autocomplete.css
│ ├── base.css
│ ├── changelists.css
│ ├── dashboard.css
│ ├── fonts.css
│ ├── forms.css
│ ├── login.css
│ ├── nav_sidebar.css
│ ├── responsive.css
│ ├── responsive_rtl.css
│ ├── rtl.css
│ ├── vendor
│ │ └── select2
│ │ │ ├── LICENSE-SELECT2.md
│ │ │ ├── select2.css
│ │ │ └── select2.min.css
│ └── widgets.css
├── fonts
│ ├── LICENSE.txt
│ ├── README.txt
│ ├── Roboto-Bold-webfont.woff
│ ├── Roboto-Light-webfont.woff
│ └── Roboto-Regular-webfont.woff
├── img
│ ├── LICENSE
│ ├── README.txt
│ ├── calendar-icons.svg
│ ├── gis
│ │ ├── move_vertex_off.svg
│ │ └── move_vertex_on.svg
│ ├── icon-addlink.svg
│ ├── icon-alert.svg
│ ├── icon-calendar.svg
│ ├── icon-changelink.svg
│ ├── icon-clock.svg
│ ├── icon-deletelink.svg
│ ├── icon-no.svg
│ ├── icon-unknown-alt.svg
│ ├── icon-unknown.svg
│ ├── icon-viewlink.svg
│ ├── icon-yes.svg
│ ├── inline-delete.svg
│ ├── search.svg
│ ├── selector-icons.svg
│ ├── sorting-icons.svg
│ ├── tooltag-add.svg
│ └── tooltag-arrowright.svg
└── js
│ ├── SelectBox.js
│ ├── SelectFilter2.js
│ ├── actions.js
│ ├── admin
│ ├── DateTimeShortcuts.js
│ └── RelatedObjectLookups.js
│ ├── autocomplete.js
│ ├── calendar.js
│ ├── cancel.js
│ ├── change_form.js
│ ├── collapse.js
│ ├── core.js
│ ├── inlines.js
│ ├── jquery.init.js
│ ├── nav_sidebar.js
│ ├── popup_response.js
│ ├── prepopulate.js
│ ├── prepopulate_init.js
│ ├── urlify.js
│ └── vendor
│ ├── jquery
│ ├── LICENSE.txt
│ ├── jquery.js
│ └── jquery.min.js
│ ├── select2
│ ├── LICENSE.md
│ ├── i18n
│ │ ├── af.js
│ │ ├── ar.js
│ │ ├── az.js
│ │ ├── bg.js
│ │ ├── bn.js
│ │ ├── bs.js
│ │ ├── ca.js
│ │ ├── cs.js
│ │ ├── da.js
│ │ ├── de.js
│ │ ├── dsb.js
│ │ ├── el.js
│ │ ├── en.js
│ │ ├── es.js
│ │ ├── et.js
│ │ ├── eu.js
│ │ ├── fa.js
│ │ ├── fi.js
│ │ ├── fr.js
│ │ ├── gl.js
│ │ ├── he.js
│ │ ├── hi.js
│ │ ├── hr.js
│ │ ├── hsb.js
│ │ ├── hu.js
│ │ ├── hy.js
│ │ ├── id.js
│ │ ├── is.js
│ │ ├── it.js
│ │ ├── ja.js
│ │ ├── ka.js
│ │ ├── km.js
│ │ ├── ko.js
│ │ ├── lt.js
│ │ ├── lv.js
│ │ ├── mk.js
│ │ ├── ms.js
│ │ ├── nb.js
│ │ ├── ne.js
│ │ ├── nl.js
│ │ ├── pl.js
│ │ ├── ps.js
│ │ ├── pt-BR.js
│ │ ├── pt.js
│ │ ├── ro.js
│ │ ├── ru.js
│ │ ├── sk.js
│ │ ├── sl.js
│ │ ├── sq.js
│ │ ├── sr-Cyrl.js
│ │ ├── sr.js
│ │ ├── sv.js
│ │ ├── th.js
│ │ ├── tk.js
│ │ ├── tr.js
│ │ ├── uk.js
│ │ ├── vi.js
│ │ ├── zh-CN.js
│ │ └── zh-TW.js
│ ├── select2.full.js
│ └── select2.full.min.js
│ └── xregexp
│ ├── LICENSE.txt
│ ├── xregexp.js
│ └── xregexp.min.js
├── build
├── asset-manifest.json
├── favicon-16x16.png
├── favicon.ico
├── index.html
├── logo192.png
├── logo512.png
├── manifest.json
├── robots.txt
└── static
│ ├── css
│ ├── main.ecc2cd5e.css
│ └── main.ecc2cd5e.css.map
│ └── js
│ ├── 787.5ad96c4b.chunk.js
│ ├── 787.5ad96c4b.chunk.js.map
│ ├── main.3ff53e20.js
│ ├── main.3ff53e20.js.LICENSE.txt
│ └── main.3ff53e20.js.map
├── cloudinary
├── html
│ └── cloudinary_cors.html
└── js
│ ├── canvas-to-blob.min.js
│ ├── jquery.cloudinary.js
│ ├── jquery.fileupload-image.js
│ ├── jquery.fileupload-process.js
│ ├── jquery.fileupload-validate.js
│ ├── jquery.fileupload.js
│ ├── jquery.iframe-transport.js
│ ├── jquery.ui.widget.js
│ └── load-image.all.min.js
└── rest_framework
├── css
├── bootstrap-theme.min.css
├── bootstrap-theme.min.css.map
├── bootstrap-tweaks.css
├── bootstrap.min.css
├── bootstrap.min.css.map
├── default.css
├── font-awesome-4.0.3.css
└── prettify.css
├── docs
├── css
│ ├── base.css
│ ├── highlight.css
│ └── jquery.json-view.min.css
├── img
│ ├── favicon.ico
│ └── grid.png
└── js
│ ├── api.js
│ ├── highlight.pack.js
│ └── jquery.json-view.min.js
├── fonts
├── fontawesome-webfont.eot
├── fontawesome-webfont.svg
├── fontawesome-webfont.ttf
├── fontawesome-webfont.woff
├── glyphicons-halflings-regular.eot
├── glyphicons-halflings-regular.svg
├── glyphicons-halflings-regular.ttf
├── glyphicons-halflings-regular.woff
└── glyphicons-halflings-regular.woff2
├── img
├── glyphicons-halflings-white.png
├── glyphicons-halflings.png
└── grid.png
└── js
├── ajax-form.js
├── bootstrap.min.js
├── coreapi-0.1.1.js
├── csrf.js
├── default.js
├── jquery-3.5.1.min.js
└── prettify-min.js
/.devcontainer/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM ubuntu:22.04
2 |
3 | ENV PYTHON_VERSION 3.8.12
4 | ENV DEBIAN_FRONTEND=noninteractive
5 | #Set of all dependencies needed for pyenv to work on Ubuntu
6 | RUN apt-get update \
7 | && apt-get install -y --no-install-recommends make build-essential libssl-dev libpq-dev zlib1g-dev libbz2-dev libreadline-dev libsqlite3-dev wget ca-certificates curl llvm libncurses5-dev xz-utils tk-dev libxml2-dev libxmlsec1-dev libffi-dev liblzma-dev mecab-ipadic-utf8 git postgresql-client telnet unzip zlib1g-dev
8 |
9 | RUN curl https://cli-assets.heroku.com/install.sh | sh
10 | RUN curl -fsSL https://deb.nodesource.com/setup_16.x | bash - && apt-get install -y nodejs
11 |
12 | ARG USERNAME=codeany
13 | RUN useradd -ms /bin/bash $USERNAME
14 | USER $USERNAME
15 | WORKDIR /home/$USERNAME
16 |
17 | # Set-up necessary Env vars for PyEnv
18 | ENV PYENV_ROOT /home/$USERNAME/.pyenv
19 | ENV PATH $PYENV_ROOT/shims:$PYENV_ROOT/bin:$PATH
20 |
21 | # Install pyenv
22 | RUN set -ex \
23 | && curl https://pyenv.run | bash \
24 | && pyenv update \
25 | && pyenv install $PYTHON_VERSION \
26 | && pyenv global $PYTHON_VERSION \
27 | && pyenv rehash \
28 | && python3 -m pip install --no-cache-dir --upgrade pip \
29 | && python3 -m pip install --no-cache-dir --upgrade setuptools wheel virtualenv pipenv pylint rope flake8 mypy autopep8 pep8 pylama pydocstyle bandit notebook twine
30 |
31 | ENV PATH=$PATH:"/home/codeany/.local/bin"
32 |
33 | RUN echo 'alias python=python3' >> ~/.bashrc && \
34 | echo 'export PIP_USER=yes' >> ~/.bashrc && \
35 | echo 'alias pip=pip3' >> ~/.bashrc && \
36 | echo 'alias psql="psql mydb"' >> ~/.bashrc
37 |
38 | COPY ./build-assets/heroku_config.sh /home/$USERNAME/.theia/heroku_config.sh
39 | RUN echo 'alias heroku_config=". $HOME/.theia/heroku_config.sh"' >> ~/.bashrc
40 |
41 | COPY ./build-assets/make_url.py /home/$USERNAME/.theia/make_url.py
42 | RUN echo 'alias make_url="python3 $HOME/.theia/make_url.py "' >> ~/.bashrc
43 |
44 | COPY ./build-assets/http_server.py /home/$USERNAME/.theia/http_server.py
45 | RUN echo 'alias http_server="python3 $HOME/.theia/http_server.py "' >> ~/.bashrc
46 |
47 |
48 | USER root
49 | RUN chown -R $USERNAME:$USERNAME /home/$USERNAME/.theia
50 |
51 | CMD ["tail", "-f", "/dev/null"]
52 |
53 | # Allows proxy to work for react/drf on cloud ide's
54 | ENV DANGEROUSLY_DISABLE_HOST_CHECK=true
55 |
--------------------------------------------------------------------------------
/.devcontainer/build-assets/heroku_config.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | # Script to allow Heroku API key to be pasted
3 | # exported as an environment variable
4 | #
5 | # Matt Rudge, May 2021
6 |
7 | echo Heroku authentication configuration script
8 | echo Code Institute, 2021
9 | echo
10 | echo Get your Heroku API key by going to https://dashboard.heroku.com
11 | echo Go to Account Settings and click on Reveal to view your Heroku API key
12 | echo
13 |
14 | if [[ -z "${HEROKU_API_KEY}" ]]; then
15 | echo Paste your Heroku API key here or press Enter to quit:
16 | read apikey
17 | if [[ -z "${apikey}" ]]; then
18 | return 0
19 | fi
20 | echo export HEROKU_API_KEY=${apikey} >> ~/.bashrc
21 | echo Added the export. Refreshing the terminal.
22 | . ~/.bashrc > /dev/null
23 | echo Done!
24 | else
25 | echo API key is already set.
26 | echo
27 | echo To reset the API key please input "'reset'":
28 | read reset_trigger
29 | if [[ ${reset_trigger} == reset ]]; then
30 | unset HEROKU_API_KEY
31 | unset reset_trigger
32 | echo
33 | echo API key removed!
34 | else
35 | unset reset_trigger
36 | echo API key unchanged.
37 | fi
38 | echo
39 | echo Exiting
40 | fi
--------------------------------------------------------------------------------
/.devcontainer/build-assets/http_server.py:
--------------------------------------------------------------------------------
1 | # Simple wrapper for http.server
2 | # to switch off caching for users
3 | #
4 | # Matt Rudge
5 | # 20th April, 2023
6 |
7 | import http.server
8 |
9 |
10 | class NoCacheHTTPHandler(http.server.SimpleHTTPRequestHandler):
11 | def end_headers(self):
12 | """
13 | Overrides default end_headers method
14 | """
15 | self.send_cache_headers()
16 | http.server.SimpleHTTPRequestHandler.end_headers(self)
17 |
18 | def send_cache_headers(self):
19 | """
20 | New method to send cache control headers
21 | """
22 | self.send_header("Cache-Control", "no-cache, no-store, must-revalidate")
23 | self.send_header("Pragma", "no-cache")
24 | self.send_header("Expires", "0")
25 |
26 |
27 | if __name__ == '__main__':
28 | http.server.test(HandlerClass=NoCacheHTTPHandler)
29 |
--------------------------------------------------------------------------------
/.devcontainer/build-assets/make_url.py:
--------------------------------------------------------------------------------
1 | # Simple utility for creating the Cloudinary URL from a
2 | # cloudinary_python.txt file
3 | # Matt Rudge, November 2021
4 |
5 | import re
6 |
7 | with open("cloudinary_python.txt") as f:
8 | content = f.readlines()
9 |
10 | cloud_name = re.findall(r"['](.*?)[']",content[15])[0]
11 | api_key = re.findall(r"['](.*?)[']",content[16])[0]
12 | api_secret = re.findall(r"['](.*?)[']",content[17])[0]
13 |
14 | print(f"cloudinary://{api_key}:{api_secret}@{cloud_name}")
--------------------------------------------------------------------------------
/.devcontainer/docker-compose.yml:
--------------------------------------------------------------------------------
1 | version: '3'
2 | services:
3 | app:
4 | build:
5 | context: .
6 | dockerfile: Dockerfile
7 | volumes:
8 | - "/tmp/postgres/socket:/var/run/postgresql"
9 |
10 | psql:
11 | image: postgres:11.9
12 | environment:
13 | - POSTGRES_DB=mydb
14 | - POSTGRES_USER=codeany
15 | - POSTGRES_PASSWORD=pass1234
16 | network_mode: service:app
17 | volumes:
18 | - "/workspace/db-data:/var/lib/postgresql/data"
19 | - "/tmp/postgres/socket:/var/run/postgresql"
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/user-story.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: User Story
3 | about: Default User Story template
4 | title: 'User Story:
'
5 | labels: user story
6 | assignees: ''
7 |
8 | ---
9 |
10 | Epic:
11 |
12 | As a **role** I can **capability** so that **received benefit**
13 |
14 | ### Acceptance Criteria
15 |
16 | - Acceptance criteria 1
17 | - Acceptance criteria 2
18 | - Acceptance criteria 3
19 |
20 | ### Tasks
21 |
22 | - Task 1
23 | - Task 2
24 | - Task 3
25 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | core.mongo*
2 | core.python*
3 | env.py
4 | __pycache__/
5 | *.py[cod]
6 | node_modules/
7 | .github/
8 | cloudinary_python.txt
--------------------------------------------------------------------------------
/.gitpod.yml:
--------------------------------------------------------------------------------
1 | # This configuration file was automatically generated by Gitpod.
2 | # Please adjust to your needs (see https://www.gitpod.io/docs/introduction/learn-gitpod/gitpod-yaml)
3 | # and commit this file to your remote git repository to share the goodness with others.
4 |
5 | # Learn more from ready-to-use templates: https://www.gitpod.io/docs/introduction/getting-started/quickstart
6 |
7 | tasks:
8 | - init: pip install -r requirements.txt
9 |
10 |
11 |
--------------------------------------------------------------------------------
/.vscode/extensions.json:
--------------------------------------------------------------------------------
1 | {
2 | "recommendations": [
3 | "ms-python.python",
4 | "ms-python.isort",
5 | "eventyret.bootstrap-4-cdn-snippet",
6 | "dsznajder.es7-react-js-snippets",
7 | "esbenp.prettier-vscode",
8 | "formulahendry.auto-close-tag"
9 | ]
10 | }
--------------------------------------------------------------------------------
/Procfile:
--------------------------------------------------------------------------------
1 | web: gunicorn drf_api.wsgi
--------------------------------------------------------------------------------
/comments/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bluesky-0412/API_Django/2fe694997713372b791572a78e86e2460706f303/comments/__init__.py
--------------------------------------------------------------------------------
/comments/admin.py:
--------------------------------------------------------------------------------
1 | from django.contrib import admin
2 |
3 | # Register your models here.
4 |
--------------------------------------------------------------------------------
/comments/apps.py:
--------------------------------------------------------------------------------
1 | from django.apps import AppConfig
2 |
3 |
4 | class CommentsConfig(AppConfig):
5 | default_auto_field = 'django.db.models.BigAutoField'
6 | name = 'comments'
7 |
--------------------------------------------------------------------------------
/comments/migrations/0001_initial.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 3.2.20 on 2024-01-28 17:04
2 |
3 | from django.conf import settings
4 | from django.db import migrations, models
5 | import django.db.models.deletion
6 |
7 |
8 | class Migration(migrations.Migration):
9 |
10 | initial = True
11 |
12 | dependencies = [
13 | ('posts', '0001_initial'),
14 | migrations.swappable_dependency(settings.AUTH_USER_MODEL),
15 | ]
16 |
17 | operations = [
18 | migrations.CreateModel(
19 | name='Comment',
20 | fields=[
21 | ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
22 | ('made_at', models.DateTimeField(auto_now_add=True)),
23 | ('edited_at', models.DateTimeField(auto_now=True)),
24 | ('content', models.TextField()),
25 | ('account_owner', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)),
26 | ('post', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='posts.post')),
27 | ],
28 | options={
29 | 'ordering': ['-made_at'],
30 | },
31 | ),
32 | ]
33 |
--------------------------------------------------------------------------------
/comments/migrations/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bluesky-0412/API_Django/2fe694997713372b791572a78e86e2460706f303/comments/migrations/__init__.py
--------------------------------------------------------------------------------
/comments/models.py:
--------------------------------------------------------------------------------
1 | from django.db import models
2 | from django.contrib.auth.models import User
3 | from posts.models import Post
4 |
5 |
6 | class Comment(models.Model):
7 | post = models.ForeignKey(Post, on_delete=models.CASCADE)
8 | content = models.TextField()
9 | account_owner = models.ForeignKey(User, on_delete=models.CASCADE)
10 | made_at = models.DateTimeField(auto_now_add=True)
11 | edited_at = models.DateTimeField(auto_now=True)
12 |
13 | class Meta:
14 | ordering = ['-made_at']
15 |
16 | def __str__(self):
17 | return self.content
--------------------------------------------------------------------------------
/comments/serializers.py:
--------------------------------------------------------------------------------
1 | from django.contrib.humanize.templatetags.humanize import naturaltime
2 | from rest_framework import serializers
3 | from .models import Comment
4 |
5 |
6 | class CommentSerializer(serializers.ModelSerializer):
7 | account_owner = serializers.ReadOnlyField(source='account_owner.username')
8 | is_account_owner = serializers.SerializerMethodField()
9 | profile_id = serializers.ReadOnlyField(source='account_owner.profile.id')
10 | profile_image = serializers.ReadOnlyField(source='account_owner.profile.image.url')
11 | made_at = serializers.SerializerMethodField()
12 | edited_at = serializers.SerializerMethodField()
13 |
14 | def get_is_account_owner(self, obj):
15 | request = self.context['request']
16 | return request.user == obj.account_owner
17 |
18 | def get_made_at(self, obj):
19 | return naturaltime(obj.made_at)
20 |
21 | def get_edited_at(self, obj):
22 | return naturaltime(obj.edited_at)
23 |
24 | class Meta:
25 | model = Comment
26 | fields = [
27 | 'id', 'account_owner', 'is_account_owner', 'profile_id', 'profile_image',
28 | 'post', 'made_at', 'edited_at', 'content'
29 | ]
30 |
31 |
32 | class CommentDetailSerializer(CommentSerializer):
33 | post = serializers.ReadOnlyField(source='post.id')
--------------------------------------------------------------------------------
/comments/tests.py:
--------------------------------------------------------------------------------
1 | from django.test import TestCase
2 |
3 | # Create your tests here.
4 |
--------------------------------------------------------------------------------
/comments/urls.py:
--------------------------------------------------------------------------------
1 | from django.urls import path
2 | from comments import views
3 |
4 | urlpatterns = [
5 | path('comments/', views.CommentList.as_view()),
6 | path('comments//', views.CommentDetail.as_view())
7 | ]
--------------------------------------------------------------------------------
/comments/views.py:
--------------------------------------------------------------------------------
1 | from rest_framework import generics, permissions
2 | from django_filters.rest_framework import DjangoFilterBackend
3 | from drf_api.permissions import IsAccountOwnerOrReadOnly
4 | from .models import Comment
5 | from .serializers import CommentSerializer, CommentDetailSerializer
6 |
7 |
8 | class CommentList(generics.ListCreateAPIView):
9 | serializer_class = CommentSerializer
10 | permission_classes = [permissions.IsAuthenticatedOrReadOnly]
11 | queryset = Comment.objects.all()
12 | filter_backends = [DjangoFilterBackend]
13 | filterset_fields = ['post']
14 |
15 | def perform_create(self, serializer):
16 | serializer.save(account_owner=self.request.user)
17 |
18 |
19 | class CommentDetail(generics.RetrieveUpdateDestroyAPIView):
20 | permission_classes = [IsAccountOwnerOrReadOnly]
21 | serializer_class = CommentDetailSerializer
22 | queryset = Comment.objects.all()
--------------------------------------------------------------------------------
/drf_api/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bluesky-0412/API_Django/2fe694997713372b791572a78e86e2460706f303/drf_api/__init__.py
--------------------------------------------------------------------------------
/drf_api/asgi.py:
--------------------------------------------------------------------------------
1 | """
2 | ASGI config for drf_api project.
3 |
4 | It exposes the ASGI callable as a module-level variable named ``application``.
5 |
6 | For more information on this file, see
7 | https://docs.djangoproject.com/en/3.2/howto/deployment/asgi/
8 | """
9 |
10 | import os
11 |
12 | from django.core.asgi import get_asgi_application
13 |
14 | os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'drf_api.settings')
15 |
16 | application = get_asgi_application()
17 |
--------------------------------------------------------------------------------
/drf_api/permissions.py:
--------------------------------------------------------------------------------
1 | from rest_framework import permissions
2 |
3 |
4 | class IsAccountOwnerOrReadOnly(permissions.BasePermission):
5 | def has_object_permission(self, request, view, obj):
6 | if request.method in permissions.SAFE_METHODS:
7 | return True
8 | return obj.account_owner == request.user
9 |
--------------------------------------------------------------------------------
/drf_api/serializers.py:
--------------------------------------------------------------------------------
1 | from dj_rest_auth.serializers import UserDetailsSerializer
2 | from rest_framework import serializers
3 |
4 |
5 | class CurrentUserSerializer(UserDetailsSerializer):
6 | profile_id = serializers.ReadOnlyField(source='profile.id')
7 | profile_image = serializers.ReadOnlyField(source='profile.image.url')
8 |
9 | class Meta(UserDetailsSerializer.Meta):
10 | fields = UserDetailsSerializer.Meta.fields + (
11 | 'profile_id', 'profile_image'
12 | )
--------------------------------------------------------------------------------
/drf_api/urls.py:
--------------------------------------------------------------------------------
1 | """drf_api URL Configuration
2 |
3 | The `urlpatterns` list routes URLs to views. For more information please see:
4 | https://docs.djangoproject.com/en/3.2/topics/http/urls/
5 | Examples:
6 | Function views
7 | 1. Add an import: from my_app import views
8 | 2. Add a URL to urlpatterns: path('', views.home, name='home')
9 | Class-based views
10 | 1. Add an import: from other_app.views import Home
11 | 2. Add a URL to urlpatterns: path('', Home.as_view(), name='home')
12 | Including another URLconf
13 | 1. Import the include() function: from django.urls import include, path
14 | 2. Add a URL to urlpatterns: path('blog/', include('blog.urls'))
15 | """
16 | from django.contrib import admin
17 | from django.urls import path, include
18 | from django.views.generic import TemplateView
19 | from .views import logout_route
20 |
21 | urlpatterns = [
22 | path('', TemplateView.as_view(template_name='index.html')),
23 | path('admin/', admin.site.urls),
24 | path('api/api-auth/', include('rest_framework.urls')),
25 | path('api/dj-rest-auth/logout/', logout_route),
26 | path('api/dj-rest-auth/', include('dj_rest_auth.urls')),
27 | path('api/dj-rest-auth/registration/', include('dj_rest_auth.registration.urls')),
28 | path('api/', include('profiles.urls')),
29 | path('api/', include('posts.urls')),
30 | path('api/', include('comments.urls')),
31 | path('api/', include('likes.urls')),
32 | path('api/', include('followers.urls')),
33 | ]
34 |
35 | handler404 = TemplateView.as_view(template_name='index.html')
36 |
--------------------------------------------------------------------------------
/drf_api/views.py:
--------------------------------------------------------------------------------
1 | from rest_framework.decorators import api_view
2 | from rest_framework.response import Response
3 | from .settings import (
4 | JWT_AUTH_COOKIE, JWT_AUTH_REFRESH_COOKIE, JWT_AUTH_SAMESITE,
5 | JWT_AUTH_SECURE,
6 | )
7 |
8 |
9 | @api_view()
10 | def root_route(request):
11 | return Response({
12 | "message": "'Capture The Moments' drf API"
13 | })
14 |
15 | # dj-rest-auth logout view fix
16 | @api_view(['POST'])
17 | def logout_route(request):
18 | response = Response()
19 | response.set_cookie(
20 | key=JWT_AUTH_COOKIE,
21 | value='',
22 | httponly=True,
23 | expires='Thu, 01 Jan 1970 00:00:00 GMT',
24 | max_age=0,
25 | samesite=JWT_AUTH_SAMESITE,
26 | secure=JWT_AUTH_SECURE,
27 | )
28 | response.set_cookie(
29 | key=JWT_AUTH_REFRESH_COOKIE,
30 | value='',
31 | httponly=True,
32 | expires='Thu, 01 Jan 1970 00:00:00 GMT',
33 | max_age=0,
34 | samesite=JWT_AUTH_SAMESITE,
35 | secure=JWT_AUTH_SECURE,
36 | )
37 | return response
--------------------------------------------------------------------------------
/drf_api/wsgi.py:
--------------------------------------------------------------------------------
1 | """
2 | WSGI config for drf_api project.
3 |
4 | It exposes the WSGI callable as a module-level variable named ``application``.
5 |
6 | For more information on this file, see
7 | https://docs.djangoproject.com/en/3.2/howto/deployment/wsgi/
8 | """
9 |
10 | import os
11 |
12 | from django.core.wsgi import get_wsgi_application
13 |
14 | os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'drf_api.settings')
15 |
16 | application = get_wsgi_application()
17 |
--------------------------------------------------------------------------------
/followers/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bluesky-0412/API_Django/2fe694997713372b791572a78e86e2460706f303/followers/__init__.py
--------------------------------------------------------------------------------
/followers/admin.py:
--------------------------------------------------------------------------------
1 | from django.contrib import admin
2 |
3 | # Register your models here.
4 |
--------------------------------------------------------------------------------
/followers/apps.py:
--------------------------------------------------------------------------------
1 | from django.apps import AppConfig
2 |
3 |
4 | class FollowersConfig(AppConfig):
5 | default_auto_field = 'django.db.models.BigAutoField'
6 | name = 'followers'
7 |
--------------------------------------------------------------------------------
/followers/migrations/0001_initial.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 3.2.20 on 2024-01-28 17:04
2 |
3 | from django.conf import settings
4 | from django.db import migrations, models
5 | import django.db.models.deletion
6 |
7 |
8 | class Migration(migrations.Migration):
9 |
10 | initial = True
11 |
12 | dependencies = [
13 | migrations.swappable_dependency(settings.AUTH_USER_MODEL),
14 | ]
15 |
16 | operations = [
17 | migrations.CreateModel(
18 | name='Follower',
19 | fields=[
20 | ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
21 | ('made_at', models.DateTimeField(auto_now_add=True)),
22 | ('account_owner', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='following', to=settings.AUTH_USER_MODEL)),
23 | ('followed', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='followed', to=settings.AUTH_USER_MODEL)),
24 | ],
25 | options={
26 | 'ordering': ['-made_at'],
27 | 'unique_together': {('account_owner', 'followed')},
28 | },
29 | ),
30 | ]
31 |
--------------------------------------------------------------------------------
/followers/migrations/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bluesky-0412/API_Django/2fe694997713372b791572a78e86e2460706f303/followers/migrations/__init__.py
--------------------------------------------------------------------------------
/followers/models.py:
--------------------------------------------------------------------------------
1 | from django.db import models
2 | from django.contrib.auth.models import User
3 |
4 |
5 | class Follower(models.Model):
6 | followed = models.ForeignKey(User, related_name='followed', on_delete=models.CASCADE)
7 | account_owner = models.ForeignKey(User, related_name='following', on_delete=models.CASCADE)
8 | made_at = models.DateTimeField(auto_now_add=True)
9 |
10 | class Meta:
11 | ordering = ['-made_at']
12 | unique_together = ['account_owner', 'followed']
13 |
14 | def __str__(self):
15 | return f'{self.account_owner} {self.followed}'
--------------------------------------------------------------------------------
/followers/serializers.py:
--------------------------------------------------------------------------------
1 | from django.db import IntegrityError
2 | from rest_framework import serializers
3 | from .models import Follower
4 |
5 |
6 | class FollowerSerializer(serializers.ModelSerializer):
7 | account_owner = serializers.ReadOnlyField(source='account_owner.username')
8 | followed_name = serializers.ReadOnlyField(source='followed.username')
9 |
10 | class Meta:
11 | model = Follower
12 | fields = [
13 | 'id', 'account_owner', 'made_at', 'followed', 'followed_name'
14 | ]
15 |
16 | def create(self, validated_data):
17 | try:
18 | return super().create(validated_data)
19 | except IntegrityError:
20 | raise serializers.ValidationError({'detail': 'possible duplicate'})
--------------------------------------------------------------------------------
/followers/tests.py:
--------------------------------------------------------------------------------
1 | from django.test import TestCase
2 |
3 | # Create your tests here.
4 |
--------------------------------------------------------------------------------
/followers/urls.py:
--------------------------------------------------------------------------------
1 | from django.urls import path
2 | from followers import views
3 |
4 | urlpatterns = [
5 | path('followers/', views.FollowerList.as_view()),
6 | path('followers//', views.FollowerDetail.as_view())
7 | ]
--------------------------------------------------------------------------------
/followers/views.py:
--------------------------------------------------------------------------------
1 | from rest_framework import generics, permissions
2 | from drf_api.permissions import IsAccountOwnerOrReadOnly
3 | from .models import Follower
4 | from .serializers import FollowerSerializer
5 |
6 |
7 | class FollowerList(generics.ListCreateAPIView):
8 | permission_classes = [permissions.IsAuthenticatedOrReadOnly]
9 | queryset = Follower.objects.all()
10 | serializer_class = FollowerSerializer
11 |
12 | def perform_create(self, serializer):
13 | serializer.save(account_owner=self.request.user)
14 |
15 |
16 | class FollowerDetail(generics.RetrieveDestroyAPIView):
17 | permission_classes = [IsAccountOwnerOrReadOnly]
18 | queryset = Follower.objects.all()
19 | serializer_class = FollowerSerializer
--------------------------------------------------------------------------------
/frontend/.env.development.local:
--------------------------------------------------------------------------------
1 | DANGEROUSLY_DISABLE_HOST_CHECK=true
--------------------------------------------------------------------------------
/frontend/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "frontend",
3 | "version": "0.1.0",
4 | "private": true,
5 | "dependencies": {
6 | "@testing-library/jest-dom": "^5.17.0",
7 | "@testing-library/react": "^11.2.7",
8 | "@testing-library/user-event": "^12.8.3",
9 | "axios": "^1.6.7",
10 | "bootstrap": "^4.6.0",
11 | "jwt-decode": "^3.1.2",
12 | "react": "^17.0.2",
13 | "react-bootstrap": "^1.6.3",
14 | "react-dom": "^17.0.2",
15 | "react-infinite-scroll-component": "^6.1.0",
16 | "react-router-dom": "^5.3.0",
17 | "react-scripts": "^5.0.1",
18 | "web-vitals": "^1.1.2"
19 | },
20 | "scripts": {
21 | "heroku-prebuild": "npm install -g serve",
22 | "start": "react-scripts --openssl-legacy-provider start",
23 | "build": "react-scripts --openssl-legacy-provider build",
24 | "test": "react-scripts test",
25 | "eject": "react-scripts eject"
26 | },
27 | "eslintConfig": {
28 | "extends": [
29 | "react-app",
30 | "react-app/jest"
31 | ]
32 | },
33 | "browserslist": {
34 | "production": [
35 | ">0.2%",
36 | "not dead",
37 | "not op_mini all"
38 | ],
39 | "development": [
40 | "last 1 chrome version",
41 | "last 1 firefox version",
42 | "last 1 safari version"
43 | ]
44 | },
45 | "devDependencies": {
46 | "@types/react-router-dom": "^5.3.3",
47 | "msw": "^0.35.0",
48 | "react-app-rewired": "^2.2.1"
49 | },
50 | "engines": {
51 | "node": "16.19.1",
52 | "npm": "8.19.3"
53 | },
54 | "proxy": "http://localhost:8000/"
55 | }
56 |
--------------------------------------------------------------------------------
/frontend/public/favicon-16x16.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bluesky-0412/API_Django/2fe694997713372b791572a78e86e2460706f303/frontend/public/favicon-16x16.png
--------------------------------------------------------------------------------
/frontend/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bluesky-0412/API_Django/2fe694997713372b791572a78e86e2460706f303/frontend/public/favicon.ico
--------------------------------------------------------------------------------
/frontend/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
12 |
13 |
17 |
23 |
28 |
32 |
36 |
45 | Capture The Moment
46 |
47 |
48 |
49 |
50 |
60 |
61 |
--------------------------------------------------------------------------------
/frontend/public/logo192.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bluesky-0412/API_Django/2fe694997713372b791572a78e86e2460706f303/frontend/public/logo192.png
--------------------------------------------------------------------------------
/frontend/public/logo512.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bluesky-0412/API_Django/2fe694997713372b791572a78e86e2460706f303/frontend/public/logo512.png
--------------------------------------------------------------------------------
/frontend/public/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "short_name": "React App",
3 | "name": "Create React App Sample",
4 | "icons": [
5 | {
6 | "src": "favicon.ico",
7 | "sizes": "64x64 32x32 24x24 16x16",
8 | "type": "image/x-icon"
9 | },
10 | {
11 | "src": "logo192.png",
12 | "type": "image/png",
13 | "sizes": "192x192"
14 | },
15 | {
16 | "src": "logo512.png",
17 | "type": "image/png",
18 | "sizes": "512x512"
19 | }
20 | ],
21 | "start_url": ".",
22 | "display": "standalone",
23 | "theme_color": "#000000",
24 | "background_color": "#ffffff"
25 | }
26 |
--------------------------------------------------------------------------------
/frontend/public/robots.txt:
--------------------------------------------------------------------------------
1 | # https://www.robotstxt.org/robotstxt.html
2 | User-agent: *
3 | Disallow:
4 |
--------------------------------------------------------------------------------
/frontend/src/App.js:
--------------------------------------------------------------------------------
1 | import styles from "./App.module.css";
2 | import NavBar from "./components/NavBar";
3 | import Container from "react-bootstrap/Container";
4 | import { Route, Switch } from "react-router-dom";
5 | import './api/axiosDefaults';
6 | import SignUpForm from "./pages/auth/SignUpForm";
7 | import SignInForm from "./pages/auth/SignInForm";
8 | import PostCreateForm from "./pages/posts/PostCreateForm";
9 | import PostPage from "./pages/posts/PostPage";
10 | import PostsPage from "./pages/posts/PostsPage";
11 | import { useCurrentUser } from "./contexts/CurrentUserContext";
12 | import PostEditForm from "./pages/posts/PostEditForm";
13 | import ProfilePage from "./pages/profiles/ProfilePage";
14 | import UsernameForm from "./pages/profiles/UsernameForm";
15 | import UserPasswordForm from "./pages/profiles/UserPasswordForm";
16 | import ProfileEditForm from "./pages/profiles/ProfileEditForm";
17 | import NotFound from "./components/NotFound";
18 |
19 | function App() {
20 | const currentUser = useCurrentUser();
21 | const profile_id = currentUser?.profile_id || '';
22 |
23 | return (
24 |
25 |
26 |
27 |
28 | (
31 |
32 | )}
33 | />
34 | (
37 |
41 | )}
42 | />
43 | (
46 |
50 | )}
51 | />
52 | } />
53 | } />
54 | } />
55 | } />
56 | } />
57 | } />
58 | } />
59 | } />
60 | } />
61 |
62 | } />
63 |
64 |
65 |
66 | );
67 | };
68 |
69 | export default App;
--------------------------------------------------------------------------------
/frontend/src/App.module.css:
--------------------------------------------------------------------------------
1 | .App {
2 | font-family: "DM Sans", sans-serif;
3 | background-color: #39859462;
4 | min-height: 100vh;
5 | }
6 |
7 | .Main {
8 | padding-top: 81px;
9 | }
10 |
11 | .Content {
12 | background-color: #ffffff;
13 | padding: 10px;
14 | border-radius: 2px;
15 | border: 1px solid #b8b8b89f;
16 | }
17 |
18 | .FillerImage {
19 | object-fit: cover;
20 | height: 100%;
21 | width: 100%;
22 | }
23 |
24 | .Image {
25 | max-height: 40vh;
26 | max-width: 100%;
27 | object-fit: contain;
28 | }
29 |
30 | * {
31 | box-sizing: border-box;
32 | }
33 |
34 | a {
35 | color: #555555;
36 | transition: color ease-in-out 0.3s;
37 | }
38 |
39 | a:hover {
40 | text-decoration: none;
41 | color: #1db7d9;
42 | }
43 |
44 | a:hover i {
45 | color: #1db7d9;
46 | transition: color ease-in-out 0.3s;
47 | }
48 |
49 | input[type="file"] {
50 | display: none;
51 | }
52 |
53 | i {
54 | color: #cfced3;
55 | font-size: 1.6rem;
56 | padding: 7px;
57 | vertical-align: middle;
58 | }
59 |
60 | i:hover {
61 | cursor: pointer;
62 | transition: color ease-in-out 0.3s;
63 | color: #1db7d9;
64 | }
65 |
66 | figure {
67 | text-align: center;
68 | display: inline-block;
69 | }
70 |
71 | /* scrollbar */
72 | *::-webkit-scrollbar {
73 | width: 5px;
74 | }
75 | *::-webkit-scrollbar-track {
76 | background: #f1f1f1;
77 | }
78 | *::-webkit-scrollbar-thumb {
79 | background: #888;
80 | }
81 | *::-webkit-scrollbar-thumb:hover {
82 | background: #555;
83 | }
--------------------------------------------------------------------------------
/frontend/src/App.test.js:
--------------------------------------------------------------------------------
1 | import { render, screen } from '@testing-library/react';
2 | import App from './App';
3 |
4 | test('renders learn react link', () => {
5 | // render();
6 | // const linkElement = screen.getByText(/learn react/i);
7 | // expect(linkElement).toBeInTheDocument();
8 | });
9 |
--------------------------------------------------------------------------------
/frontend/src/api/axiosDefaults.js:
--------------------------------------------------------------------------------
1 | import axios from 'axios';
2 |
3 | axios.defaults.baseURL = '/api';
4 | axios.defaults.headers.post['Content-Type'] = 'multipart/form-data';
5 | axios.defaults.withCredentials = true;
6 |
7 | export const axiosReq = axios.create();
8 | export const axiosRes = axios.create();
9 |
--------------------------------------------------------------------------------
/frontend/src/assets/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bluesky-0412/API_Django/2fe694997713372b791572a78e86e2460706f303/frontend/src/assets/logo.png
--------------------------------------------------------------------------------
/frontend/src/assets/no-results.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bluesky-0412/API_Django/2fe694997713372b791572a78e86e2460706f303/frontend/src/assets/no-results.png
--------------------------------------------------------------------------------
/frontend/src/assets/upload.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bluesky-0412/API_Django/2fe694997713372b791572a78e86e2460706f303/frontend/src/assets/upload.png
--------------------------------------------------------------------------------
/frontend/src/components/Asset.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import Spinner from "react-bootstrap/Spinner";
3 | import styles from "../styles/Asset.module.css";
4 |
5 | const Asset = ({ spinner, src, message }) => {
6 | return (
7 |
8 | {spinner &&
}
9 | {src &&

}
10 | {message &&
{message}
}
11 |
12 | );
13 | };
14 |
15 | export default Asset;
--------------------------------------------------------------------------------
/frontend/src/components/Avatar.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import styles from "../styles/Avatar.module.css";
3 |
4 | const Avatar = ({ src, height = 45, text }) => {
5 | return (
6 |
7 |
14 | {text}
15 |
16 | );
17 | };
18 |
19 | export default Avatar;
--------------------------------------------------------------------------------
/frontend/src/components/MoreDropdown.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import Dropdown from 'react-bootstrap/Dropdown';
3 | import styles from '../styles/MoreDropdown.module.css';
4 | import { useHistory } from "react-router";
5 |
6 | // The forwardRef is important!!
7 | // Dropdown needs access to the DOM node in order to position the Menu
8 | const DropdownDots = React.forwardRef(({ onClick }, ref) => (
9 | {
13 | e.preventDefault();
14 | onClick(e);
15 | }}
16 | />
17 | ));
18 |
19 | export const MoreDropdown = ({ handleEdit, handleDelete }) => {
20 | return (
21 |
22 |
23 |
24 |
28 |
33 |
34 |
35 |
40 |
41 |
42 |
43 |
44 | );
45 | };
46 |
47 | export function ProfileEditDropdown({ id }) {
48 | const history = useHistory();
49 | return (
50 |
51 |
52 |
53 | history.push(`/profiles/${id}/edit`)}
55 | aria-label="edit-profile"
56 | >
57 | Edit Profile
58 |
59 | history.push(`/profiles/${id}/edit/username`)}
61 | aria-label="edit-username"
62 | >
63 |
64 | Change Username
65 |
66 | history.push(`/profiles/${id}/edit/password`)}
68 | aria-label="edit-password"
69 | >
70 |
71 | Change Password
72 |
73 |
74 |
75 | );
76 | };
--------------------------------------------------------------------------------
/frontend/src/components/NotFound.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import NoResults from '../assets/no-results.png';
3 | import styles from '../styles/NotFound.module.css';
4 | import Asset from './Asset';
5 |
6 | const NotFound = () => {
7 | return (
8 |
14 | );
15 | };
16 |
17 | export default NotFound;
--------------------------------------------------------------------------------
/frontend/src/components/__tests__/NavBar.test.js:
--------------------------------------------------------------------------------
1 | import { render, screen, fireEvent } from "@testing-library/react";
2 | import { BrowserRouter as Router } from 'react-router-dom';
3 | import { CurrentUserProvider } from "../../contexts/CurrentUserContext";
4 | import NavBar from '../NavBar';
5 |
6 | test('renders NavBar', () => {
7 | render(
8 |
9 |
10 |
11 | );
12 |
13 | // screen.debug();
14 | const signInLink = screen.getByRole('link', { name: 'SIGN IN' });
15 | expect(signInLink).toBeInTheDocument();
16 | });
17 |
18 | test('renders link to the user profile for a logged in user', async () => {
19 | render(
20 |
21 |
22 |
23 |
24 |
25 | );
26 |
27 | const profileAvatar = await screen.findByText('PROFILE');
28 | expect(profileAvatar).toBeInTheDocument();
29 | });
30 |
31 | test('renders SIGN IN and SIGN UP buttons again on log out', async () => {
32 | render(
33 |
34 |
35 |
36 |
37 |
38 | );
39 |
40 | const signOutLink = await screen.findByRole('link', { name: 'SIGN OUT' });
41 | fireEvent.click(signOutLink);
42 |
43 | const signInLink = await screen.findByRole('link', { name: 'SIGN IN' });
44 | const signUpLink = await screen.findByRole('link', { name: 'SIGN UP' });
45 |
46 | expect(signInLink).toBeInTheDocument();
47 | expect(signUpLink).toBeInTheDocument();
48 | });
--------------------------------------------------------------------------------
/frontend/src/contexts/CurrentUserContext.js:
--------------------------------------------------------------------------------
1 | import { createContext, useContext, useEffect, useMemo, useState } from "react";
2 | import axios from "axios";
3 | import { axiosReq, axiosRes } from "../api/axiosDefaults";
4 | import { useHistory } from "react-router";
5 | import { removeTokenTimestamp, shouldRefreshToken } from "../utils/utils";
6 |
7 | export const CurrentUserContext = createContext();
8 | export const SetCurrentUserContext = createContext();
9 |
10 | export const useCurrentUser = () => useContext(CurrentUserContext);
11 | export const useSetCurrentUser = () => useContext(SetCurrentUserContext);
12 |
13 | export const CurrentUserProvider = ({ children }) => {
14 | const [currentUser, setCurrentUser] = useState(null);
15 | const history = useHistory();
16 |
17 | const handleMount = async () => {
18 | try {
19 | const { data } = await axiosRes.get('dj-rest-auth/user/');
20 | setCurrentUser(data);
21 | } catch (err) {
22 | // console.log(err);
23 | }
24 | };
25 |
26 | useEffect(() => {
27 | handleMount();
28 | }, []);
29 |
30 | useMemo(() => {
31 | axiosReq.interceptors.request.use(
32 | async (config) => {
33 | if (shouldRefreshToken()) {
34 | try {
35 | await axios.post('/dj-rest-auth/token/refresh/');
36 | } catch (err) {
37 | setCurrentUser((prevCurrentUser) => {
38 | if (prevCurrentUser) {
39 | history.push('/signin');
40 | }
41 | return null;
42 | });
43 | removeTokenTimestamp();
44 | return config;
45 | }
46 | }
47 | return config;
48 | },
49 | (err) => {
50 | return Promise.reject(err);
51 | }
52 | );
53 |
54 | axiosRes.interceptors.response.use(
55 | (response) => response,
56 | async (err) => {
57 | if (err.response?.status === 401) {
58 | try {
59 | await axios.post('dj-rest-auth/token/refresh/');
60 | } catch (err) {
61 | setCurrentUser((prevCurrentUser) => {
62 | if (prevCurrentUser){
63 | history.push('/signin');
64 | }
65 | return null;
66 | });
67 | removeTokenTimestamp();
68 | }
69 | return axios(err.config);
70 | }
71 | return Promise.reject(err);
72 | }
73 | );
74 | }, [history]);
75 |
76 | return (
77 |
78 |
79 | {children}
80 |
81 |
82 | );
83 | };
--------------------------------------------------------------------------------
/frontend/src/hooks/useClickOutsideToggle.js:
--------------------------------------------------------------------------------
1 | import { useEffect, useRef, useState } from 'react'
2 |
3 | const useClickOutsideToggle = () => {
4 | const [expanded, setExpanded] = useState(false);
5 | const ref = useRef(null);
6 | useEffect(() => {
7 | const handleClickOutside = (event) => {
8 | if (ref.current && !ref.current.contains(event.target)) {
9 | setExpanded(false);
10 | }
11 | };
12 |
13 | document.addEventListener('mouseup', handleClickOutside);
14 | return () => {
15 | document.removeEventListener('mouseup', handleClickOutside);
16 | };
17 | }, [ref]);
18 |
19 | return { expanded, setExpanded, ref };
20 | };
21 |
22 | export default useClickOutsideToggle;
--------------------------------------------------------------------------------
/frontend/src/hooks/useRedirect.js:
--------------------------------------------------------------------------------
1 | import axios from 'axios';
2 | import { useEffect } from 'react';
3 | import { useHistory } from 'react-router';
4 |
5 | export const useRedirect = (userAuthStatus) => {
6 | const history = useHistory();
7 |
8 | useEffect(() => {
9 | const handleMount = async () => {
10 | try {
11 | await axios.post("/dj-rest-auth/token/refresh/");
12 | // If user is logged in, the code below will run
13 | if (userAuthStatus === "loggedIn") {
14 | history.push("/");
15 | }
16 | } catch (err) {
17 | // If user is not logged in, the code below will run
18 | if (userAuthStatus === "loggedOut") {
19 | history.push("/");
20 | }
21 | }
22 | };
23 |
24 | handleMount();
25 | }, [history, userAuthStatus]);
26 | };
--------------------------------------------------------------------------------
/frontend/src/index.css:
--------------------------------------------------------------------------------
1 | body {
2 | margin: 0;
3 | font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen',
4 | 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue',
5 | sans-serif;
6 | -webkit-font-smoothing: antialiased;
7 | -moz-osx-font-smoothing: grayscale;
8 | }
9 |
10 | code {
11 | font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New',
12 | monospace;
13 | }
14 |
--------------------------------------------------------------------------------
/frontend/src/index.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import ReactDOM from "react-dom";
3 | import "./index.css";
4 | import App from "./App";
5 | import reportWebVitals from "./reportWebVitals";
6 | import { BrowserRouter as Router } from "react-router-dom";
7 | import { CurrentUserProvider } from "./contexts/CurrentUserContext";
8 | import { ProfileDataProvider } from "./contexts/ProfileDataContext";
9 |
10 | ReactDOM.render(
11 |
12 |
13 |
14 |
15 |
16 |
17 | ,
18 | document.getElementById("root")
19 | );
20 |
21 | // If you want to start measuring performance in your app, pass a function
22 | // to log results (for example: reportWebVitals(console.log))
23 | // or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals
24 | reportWebVitals();
--------------------------------------------------------------------------------
/frontend/src/logo.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/frontend/src/mocks/handlers.js:
--------------------------------------------------------------------------------
1 | import { rest } from 'msw';
2 |
3 | const baseURL = 'https://api-django-5-e93439fb77b5.herokuapp.com/';
4 |
5 | export const handlers = [
6 | rest.get(`${baseURL}dj-rest-auth/user/`, (req, res, ctx) => {
7 | return res(
8 | ctx.json({
9 | pk: 15,
10 | username: 'wikstromphotos',
11 | email: '',
12 | first_name: '',
13 | last_name: '',
14 | profile_id: 15,
15 | profile_image:
16 | 'https://res.cloudinary.com/dsllv7c2n/image/upload/v1/media/images/Photo_1636490896993_remastered_yjfp7y',
17 | })
18 | );
19 | }),
20 | rest.post(`${baseURL}dj-rest-auth/logout/`, (req, res, ctx) => {
21 | return res(ctx.status(200));
22 | }),
23 | ];
--------------------------------------------------------------------------------
/frontend/src/pages/comments/CommentCreateForm.js:
--------------------------------------------------------------------------------
1 | import React, { useState } from "react";
2 | import { Link } from "react-router-dom";
3 |
4 | import Form from "react-bootstrap/Form";
5 | import InputGroup from "react-bootstrap/InputGroup";
6 |
7 | import Alert from "react-bootstrap/esm/Alert";
8 |
9 | import styles from "../../styles/CommentCreateEditForm.module.css";
10 | import Avatar from "../../components/Avatar";
11 | import { axiosRes } from "../../api/axiosDefaults";
12 |
13 | function CommentCreateForm(props) {
14 | const { post, setPost, setComments, profileImage, profile_id } = props;
15 | const [content, setContent] = useState('');
16 | const [showSuccessAlert, setShowSuccessAlert] = useState(false);
17 |
18 | const handleChange = (event) => {
19 | setContent(event.target.value);
20 | };
21 |
22 | const handleSubmit = async (event) => {
23 | event.preventDefault();
24 | try {
25 | const { data } = await axiosRes.post("/comments/", {
26 | content,
27 | post,
28 | });
29 | setComments((prevComments) => ({
30 | ...prevComments,
31 | results: [data, ...prevComments.results],
32 | }));
33 | setPost((prevPost) => ({
34 | results: [
35 | {
36 | ...prevPost.results[0],
37 | comments_count: prevPost.results[0].comments_count + 1,
38 | },
39 | ],
40 | }));
41 | setContent('');
42 | setShowSuccessAlert(true);
43 | } catch (err) {
44 | // console.log(err);
45 | }
46 | };
47 |
48 | return (
49 | <>
50 | setShowSuccessAlert(false)}
54 | dismissible
55 | >
56 | Comment posted!
57 |
58 |
60 |
61 |
62 |
63 |
64 |
72 |
73 |
74 |
81 |
82 | >
83 | );
84 | }
85 |
86 | export default CommentCreateForm;
--------------------------------------------------------------------------------
/frontend/src/pages/comments/CommentEditForm.js:
--------------------------------------------------------------------------------
1 | import React, { useState } from "react";
2 |
3 | import Form from "react-bootstrap/Form";
4 | import { axiosRes } from "../../api/axiosDefaults";
5 |
6 | import styles from "../../styles/CommentCreateEditForm.module.css";
7 |
8 | function CommentEditForm(props) {
9 | const { id, content, setShowEditForm, setComments } = props;
10 |
11 | const [formContent, setFormContent] = useState(content);
12 |
13 | const handleChange = (event) => {
14 | setFormContent(event.target.value);
15 | };
16 |
17 | const handleSubmit = async (event) => {
18 | event.preventDefault();
19 | try {
20 | await axiosRes.put(`/comments/${id}/`, {
21 | content: formContent.trim(),
22 | });
23 | setComments((prevComments) => ({
24 | ...prevComments,
25 | results: prevComments.results.map((comment) => {
26 | return comment.id === id
27 | ? {
28 | ...comment,
29 | content: formContent.trim(),
30 | edited_at: 'now',
31 | }
32 | : comment;
33 | }),
34 | }));
35 | setShowEditForm(false);
36 | } catch (err) {
37 | // console.log(err);
38 | }
39 | };
40 |
41 | return (
42 |
44 |
51 |
52 |
53 |
60 |
67 |
68 |
69 | );
70 | };
71 |
72 | export default CommentEditForm;
73 |
--------------------------------------------------------------------------------
/frontend/src/pages/profiles/PopularProfiles.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import Container from "react-bootstrap/Container";
3 | import appStyles from "../../App.module.css";
4 | import Asset from "../../components/Asset";
5 | import { useProfileData } from "../../contexts/ProfileDataContext";
6 | import Profile from "./Profile";
7 |
8 | const PopularProfiles = ({ mobile }) => {
9 | const { popularProfiles } = useProfileData();
10 |
11 | return (
12 |
17 | {popularProfiles.results.length ? (
18 | <>
19 | Other interesting users to check out:
20 | {mobile ? (
21 |
22 | {popularProfiles.results.slice(0, 4).map((profile) => (
23 |
24 | ))}
25 |
26 | ) : (
27 | popularProfiles.results.map((profile) => (
28 |
29 | ))
30 | )}
31 | >
32 | ) : (
33 |
34 | )}
35 |
36 | );
37 | };
38 |
39 | export default PopularProfiles;
--------------------------------------------------------------------------------
/frontend/src/pages/profiles/Profile.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import styles from '../../styles/Profile.module.css';
3 | import btnStyles from '../../styles/Button.module.css';
4 | import { useCurrentUser } from '../../contexts/CurrentUserContext';
5 | import { Link } from "react-router-dom";
6 | import Avatar from "../../components/Avatar";
7 | import Button from 'react-bootstrap/Button';
8 | import { useSetProfileData } from '../../contexts/ProfileDataContext';
9 |
10 | const Profile = (props) => {
11 | const { profile, mobile, imageSize = 55 } = props;
12 | const { id, following_id, image, account_owner } = profile;
13 |
14 | const currentUser = useCurrentUser();
15 | const is_account_owner = currentUser?.username === account_owner;
16 |
17 | const {handleFollow, handleUnfollow} = useSetProfileData();
18 |
19 | return (
20 |
23 |
28 |
29 | {account_owner}
30 |
31 |
32 | {!mobile &&
33 | currentUser &&
34 | !is_account_owner &&
35 | (following_id ? (
36 |
42 | ) : (
43 |
49 | ))}
50 |
51 |
52 | );
53 | };
54 |
55 | export default Profile;
--------------------------------------------------------------------------------
/frontend/src/reportWebVitals.js:
--------------------------------------------------------------------------------
1 | const reportWebVitals = onPerfEntry => {
2 | if (onPerfEntry && onPerfEntry instanceof Function) {
3 | import('web-vitals').then(({ getCLS, getFID, getFCP, getLCP, getTTFB }) => {
4 | getCLS(onPerfEntry);
5 | getFID(onPerfEntry);
6 | getFCP(onPerfEntry);
7 | getLCP(onPerfEntry);
8 | getTTFB(onPerfEntry);
9 | });
10 | }
11 | };
12 |
13 | export default reportWebVitals;
14 |
--------------------------------------------------------------------------------
/frontend/src/setupTests.js:
--------------------------------------------------------------------------------
1 | // jest-dom adds custom jest matchers for asserting on DOM nodes.
2 | // allows you to do things like:
3 | // expect(element).toHaveTextContent(/react/i)
4 | // learn more: https://github.com/testing-library/jest-dom
5 | import '@testing-library/jest-dom';
6 | import { setupServer } from 'msw/node';
7 | import { handlers } from './mocks/handlers';
8 |
9 | const server = setupServer(...handlers);
10 |
11 | beforeAll(() => server.listen());
12 | afterEach(() => server.resetHandlers());
13 | afterAll(() => server.close());
--------------------------------------------------------------------------------
/frontend/src/styles/Asset.module.css:
--------------------------------------------------------------------------------
1 | .Asset {
2 | display: flex;
3 | flex-direction: column;
4 | justify-content: center;
5 | align-items: center;
6 | min-height: 120px;
7 | }
--------------------------------------------------------------------------------
/frontend/src/styles/Avatar.module.css:
--------------------------------------------------------------------------------
1 | .Avatar {
2 | border-radius: 50%;
3 | border: 1px solid #a3a3a49f;
4 | margin: 0px 8px 0px 8px;
5 | object-fit: cover;
6 | }
--------------------------------------------------------------------------------
/frontend/src/styles/Button.module.css:
--------------------------------------------------------------------------------
1 | .Button {
2 | font-size: 0.8rem;
3 | align-self: center;
4 | border-radius: 100px;
5 | border-color: transparent;
6 | padding: 4px 10px;
7 | margin-left: 2px;
8 | margin-right: 2px;
9 | min-width: 75px;
10 | }
11 |
12 | .Button:hover {
13 | opacity: 0.8;
14 | border-color: transparent;
15 | cursor: pointer;
16 | }
17 |
18 | .Button:hover:active {
19 | background-color: #1db7d9 !important;
20 | }
21 |
22 | .Button:active {
23 | background-color: #1db7d9 !important;
24 | }
25 |
26 | .Button:focus {
27 | background-color: #1db7d9;
28 | }
29 |
30 | .Wide {
31 | padding: 10px 50px;
32 | width: 100%;
33 | }
34 |
35 | .Blue,
36 | .BlueOutline:hover,
37 | .Bright:hover {
38 | background-color: #57c6dfe7;
39 | color: #3a3a3a;
40 | }
41 |
42 | .BlueOutline,
43 | .Blue:hover {
44 | background-color: #ffffff;
45 | color: #1db7d9;
46 | }
47 |
48 | .Black,
49 | .BlackOutline:hover {
50 | background-color: #2274d8;
51 | color: aliceblue;
52 | }
53 |
54 | .Black:hover,
55 | .BlackOutline {
56 | background-color: #1e68c3;
57 | color: aliceblue;
58 | }
59 |
60 | .Bright {
61 | background-color: #1db7d9;
62 | color: aliceblue;
63 | }
--------------------------------------------------------------------------------
/frontend/src/styles/Comment.module.css:
--------------------------------------------------------------------------------
1 | .AccountOwner {
2 | font-weight: bold;
3 | color: #1db7d9;
4 | margin-right: 8px;
5 | }
6 |
7 | .Date {
8 | font-weight: lighter;
9 | color: #c1c1c5;
10 | }
--------------------------------------------------------------------------------
/frontend/src/styles/CommentCreateEditForm.module.css:
--------------------------------------------------------------------------------
1 | .Form {
2 | border: none;
3 | border-bottom: 3px #19a1c0 solid;
4 | }
5 |
6 | .Button {
7 | border: none;
8 | background-color: #19a1c0;
9 | color: aliceblue;
10 | border-radius: 100px;
11 | padding: 4px 10px;
12 | min-width: 75px;
13 | margin: 5px;
14 | }
15 |
16 | .Button:hover {
17 | cursor: pointer;
18 | background-color: aliceblue;
19 | color: #19a1c0;
20 | }
--------------------------------------------------------------------------------
/frontend/src/styles/MoreDropdown.module.css:
--------------------------------------------------------------------------------
1 | .DropdownItem {
2 | display: inline-block;
3 | max-width: 50%;
4 | padding: 0px;
5 | }
6 |
7 | .Absolute {
8 | position: absolute;
9 | right: 0;
10 | z-index: 99;
11 | }
--------------------------------------------------------------------------------
/frontend/src/styles/NavBar.module.css:
--------------------------------------------------------------------------------
1 | .NavBar {
2 | background-color: #ffffff;
3 | border: 1px solid #a3a3a49f;
4 | }
5 |
6 | .NavLink {
7 | padding: 5px;
8 | }
9 |
10 | .Active i {
11 | color: #1db7d9;
12 | }
--------------------------------------------------------------------------------
/frontend/src/styles/NotFound.module.css:
--------------------------------------------------------------------------------
1 | .NotFound {
2 | margin-top: 25vh;
3 | }
--------------------------------------------------------------------------------
/frontend/src/styles/Post.module.css:
--------------------------------------------------------------------------------
1 | .Post {
2 | background-color: #ffffff;
3 | border: 1px solid #dadadf;
4 | border-radius: 2px;
5 | margin-bottom: 16px;
6 | text-align: center;
7 | }
8 |
9 | .Post figure,
10 | h5 {
11 | margin: 0 0;
12 | }
13 |
14 | .Heart {
15 | color: #f6162c;
16 | }
17 |
18 | .Heart:hover {
19 | color: #b21020;
20 | }
21 |
22 | .HeartOutline:hover {
23 | color: #b21020;
24 | }
--------------------------------------------------------------------------------
/frontend/src/styles/PostCreateEditForm.module.css:
--------------------------------------------------------------------------------
1 | .Container {
2 | min-height: 343px;
3 | }
--------------------------------------------------------------------------------
/frontend/src/styles/PostsPage.module.css:
--------------------------------------------------------------------------------
1 | .SearchBar input {
2 | border-radius: 20px;
3 | border: 1px solid #b8b8b89f;
4 | color: #242a3d;
5 | padding-left: 40px;
6 | margin-bottom: 16px;
7 | }
8 |
9 | .SearchIcon {
10 | position: absolute;
11 | font-size: 1.2rem;
12 | padding: 9px;
13 | padding-left: 15px;
14 | }
15 |
16 | .SearchIcon:hover {
17 | cursor: default;
18 | color: #cfced3;
19 | }
--------------------------------------------------------------------------------
/frontend/src/styles/Profile.module.css:
--------------------------------------------------------------------------------
1 | .WordBreak {
2 | word-break: break-all;
3 | }
--------------------------------------------------------------------------------
/frontend/src/styles/ProfilePage.module.css:
--------------------------------------------------------------------------------
1 | .ProfileImage {
2 | object-fit: cover;
3 | height: 120px;
4 | width: 120px;
5 | margin: 4px;
6 | border-radius: 50%;
7 | border: 1px solid #a3a3a49f;
8 | }
9 |
10 | @media screen and (max-width: 991px) {
11 | .ProfileImage {
12 | width: 250px;
13 | height: 250px;
14 | }
15 | }
--------------------------------------------------------------------------------
/frontend/src/styles/SignInUpForm.module.css:
--------------------------------------------------------------------------------
1 | .Row {
2 | height: calc(100vh - 81px);
3 | }
4 | .Input {
5 | background: #ffffff;
6 | border: 1px solid #f0f1f9;
7 | box-sizing: border-box;
8 | border-radius: 2px;
9 | color: #7177a1;
10 | text-align: center;
11 | padding: 10px;
12 | }
13 |
14 | .Header {
15 | font-style: normal;
16 | font-weight: bold;
17 | font-size: 16px;
18 | line-height: 19px;
19 | text-align: center;
20 | letter-spacing: 0.2em;
21 | text-transform: uppercase;
22 | color: #1db7d9;
23 | }
24 |
25 | .Link {
26 | text-decoration: none;
27 | text-align: center;
28 | display: block;
29 | margin: auto;
30 | }
31 |
32 | .Link span {
33 | color: #7654ff;
34 | }
35 |
36 | .Container {
37 | padding: 30px 10px;
38 | }
39 |
40 | .SignInCol {
41 | height: 320px;
42 | }
43 |
44 | .SignUpCol {
45 | height: 375px;
46 | }
--------------------------------------------------------------------------------
/frontend/src/utils/utils.js:
--------------------------------------------------------------------------------
1 | import jwtDecode from "jwt-decode";
2 | import { axiosReq } from "../api/axiosDefaults";
3 |
4 | export const fetchMoreData = async (resource, setResource) => {
5 | try {
6 | const { data } = await axiosReq.get(resource.next);
7 | setResource((prevResource) => ({
8 | ...prevResource,
9 | next: data.next,
10 | results: data.results.reduce((acc, cur) => {
11 | return acc.some((accResult) => accResult.id === cur.id)
12 | ? acc
13 | : [...acc, cur];
14 | }, prevResource.results),
15 | }));
16 | } catch (err) {}
17 | };
18 |
19 | export const followHelper = (profile, clickedProfile, following_id) => {
20 | return profile.id === clickedProfile.id
21 | ? // The clicked profile, update followers count and set following id
22 | {
23 | ...profile,
24 | followers_count: profile.followers_count + 1,
25 | following_id,
26 | }
27 | : profile.is_account_owner
28 | ? // The logged in users profile, update it's following count
29 | { ...profile, following_count: profile.following_count + 1 }
30 | : // Not the profile the user clicked on or the profile the user owns
31 | // Return it unchanged
32 | profile;
33 | };
34 |
35 | export const unfollowHelper = (profile, clickedProfile) => {
36 | return profile.id === clickedProfile.id
37 | ? // The clicked profile, update followers count and set following id
38 | {
39 | ...profile,
40 | followers_count: profile.followers_count - 1,
41 | following_id: null,
42 | }
43 | : profile.is_account_owner
44 | ? // The logged in users profile, update it's following count
45 | { ...profile, following_count: profile.following_count - 1 }
46 | : // Not the profile the user clicked on or the profile the user owns
47 | // Return it unchanged
48 | profile;
49 | };
50 |
51 | export const setTokenTimestamp = (data) => {
52 | const refreshTokenTimestamp = jwtDecode(data?.refresh_token).exp;
53 | localStorage.setItem('refreshTokenTimestamp', refreshTokenTimestamp);
54 | };
55 |
56 | export const shouldRefreshToken = () => {
57 | return !!localStorage.getItem('refreshTokenTimestamp');
58 | };
59 |
60 | export const removeTokenTimestamp = () => {
61 | localStorage.removeItem('refreshTokenTimestamp');
62 | };
--------------------------------------------------------------------------------
/likes/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bluesky-0412/API_Django/2fe694997713372b791572a78e86e2460706f303/likes/__init__.py
--------------------------------------------------------------------------------
/likes/admin.py:
--------------------------------------------------------------------------------
1 | from django.contrib import admin
2 |
3 | # Register your models here.
4 |
--------------------------------------------------------------------------------
/likes/apps.py:
--------------------------------------------------------------------------------
1 | from django.apps import AppConfig
2 |
3 |
4 | class LikesConfig(AppConfig):
5 | default_auto_field = 'django.db.models.BigAutoField'
6 | name = 'likes'
7 |
--------------------------------------------------------------------------------
/likes/migrations/0001_initial.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 3.2.20 on 2024-01-28 17:04
2 |
3 | from django.conf import settings
4 | from django.db import migrations, models
5 | import django.db.models.deletion
6 |
7 |
8 | class Migration(migrations.Migration):
9 |
10 | initial = True
11 |
12 | dependencies = [
13 | ('posts', '0001_initial'),
14 | migrations.swappable_dependency(settings.AUTH_USER_MODEL),
15 | ]
16 |
17 | operations = [
18 | migrations.CreateModel(
19 | name='Like',
20 | fields=[
21 | ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
22 | ('made_at', models.DateTimeField(auto_now_add=True)),
23 | ('account_owner', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)),
24 | ('post', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='likes', to='posts.post')),
25 | ],
26 | options={
27 | 'ordering': ['-made_at'],
28 | 'unique_together': {('account_owner', 'post')},
29 | },
30 | ),
31 | ]
32 |
--------------------------------------------------------------------------------
/likes/migrations/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bluesky-0412/API_Django/2fe694997713372b791572a78e86e2460706f303/likes/migrations/__init__.py
--------------------------------------------------------------------------------
/likes/models.py:
--------------------------------------------------------------------------------
1 | from django.db import models
2 | from django.contrib.auth.models import User
3 | from posts.models import Post
4 |
5 |
6 | class Like(models.Model):
7 | post = models.ForeignKey(Post, related_name='likes', on_delete=models.CASCADE)
8 | account_owner = models.ForeignKey(User, on_delete=models.CASCADE)
9 | made_at = models.DateTimeField(auto_now_add=True)
10 |
11 | class Meta:
12 | ordering = ['-made_at']
13 | unique_together = ['account_owner', 'post']
14 |
15 | def __str__(self):
16 | return f'{self.account_owner} {self.post}'
--------------------------------------------------------------------------------
/likes/serializers.py:
--------------------------------------------------------------------------------
1 | from django.db import IntegrityError
2 | from rest_framework import serializers
3 | from likes.models import Like
4 |
5 |
6 | class LikeSerializer(serializers.ModelSerializer):
7 | account_owner = serializers.ReadOnlyField(source='account_owner.username')
8 |
9 | class Meta:
10 | model = Like
11 | fields = ['id', 'made_at', 'account_owner', 'post']
12 |
13 |
14 | def create(self, validated_data):
15 | try:
16 | return super().create(validated_data)
17 | except IntegrityError:
18 | raise serializers.ValidationError({'detail': 'possible duplicate'})
19 |
20 |
--------------------------------------------------------------------------------
/likes/tests.py:
--------------------------------------------------------------------------------
1 | from django.test import TestCase
2 |
3 | # Create your tests here.
4 |
--------------------------------------------------------------------------------
/likes/urls.py:
--------------------------------------------------------------------------------
1 | from django.urls import path
2 | from likes import views
3 |
4 | urlpatterns = [
5 | path('likes/', views.LikeList.as_view()),
6 | path('likes//', views.LikeDetail.as_view()),
7 | ]
8 |
--------------------------------------------------------------------------------
/likes/views.py:
--------------------------------------------------------------------------------
1 | from rest_framework import generics, permissions
2 | from drf_api.permissions import IsAccountOwnerOrReadOnly
3 | from .models import Like
4 | from .serializers import LikeSerializer
5 |
6 |
7 | class LikeList(generics.ListCreateAPIView):
8 | permission_classes = [permissions.IsAuthenticatedOrReadOnly]
9 | serializer_class = LikeSerializer
10 | queryset = Like.objects.all()
11 |
12 | def perform_create(self, serializer):
13 | serializer.save(account_owner=self.request.user)
14 |
15 |
16 | class LikeDetail(generics.RetrieveDestroyAPIView):
17 | permission_classes = [IsAccountOwnerOrReadOnly]
18 | queryset = Like.objects.all()
19 | serializer_class = LikeSerializer
20 |
21 |
--------------------------------------------------------------------------------
/manage.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | """Django's command-line utility for administrative tasks."""
3 | import os
4 | import sys
5 |
6 |
7 | def main():
8 | """Run administrative tasks."""
9 | os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'drf_api.settings')
10 | try:
11 | from django.core.management import execute_from_command_line
12 | except ImportError as exc:
13 | raise ImportError(
14 | "Couldn't import Django. Are you sure it's installed and "
15 | "available on your PYTHONPATH environment variable? Did you "
16 | "forget to activate a virtual environment?"
17 | ) from exc
18 | execute_from_command_line(sys.argv)
19 |
20 |
21 | if __name__ == '__main__':
22 | main()
23 |
--------------------------------------------------------------------------------
/package-lock.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "API-Django",
3 | "lockfileVersion": 3,
4 | "requires": true,
5 | "packages": {}
6 | }
7 |
--------------------------------------------------------------------------------
/posts/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bluesky-0412/API_Django/2fe694997713372b791572a78e86e2460706f303/posts/__init__.py
--------------------------------------------------------------------------------
/posts/admin.py:
--------------------------------------------------------------------------------
1 | from django.contrib import admin
2 |
3 | # Register your models here.
4 |
--------------------------------------------------------------------------------
/posts/apps.py:
--------------------------------------------------------------------------------
1 | from django.apps import AppConfig
2 |
3 |
4 | class PostsConfig(AppConfig):
5 | default_auto_field = 'django.db.models.BigAutoField'
6 | name = 'posts'
7 |
--------------------------------------------------------------------------------
/posts/migrations/0001_initial.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 3.2.20 on 2024-01-28 17:04
2 |
3 | from django.conf import settings
4 | from django.db import migrations, models
5 | import django.db.models.deletion
6 |
7 |
8 | class Migration(migrations.Migration):
9 |
10 | initial = True
11 |
12 | dependencies = [
13 | migrations.swappable_dependency(settings.AUTH_USER_MODEL),
14 | ]
15 |
16 | operations = [
17 | migrations.CreateModel(
18 | name='Post',
19 | fields=[
20 | ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
21 | ('made_at', models.DateTimeField(auto_now_add=True)),
22 | ('edited_at', models.DateTimeField(auto_now=True)),
23 | ('title', models.CharField(max_length=255)),
24 | ('content', models.TextField(blank=True)),
25 | ('image', models.ImageField(blank=True, default='../default_post_hde9ti', upload_to='images/')),
26 | ('image_filter', models.CharField(choices=[('_1977', '1977'), ('brannan', 'Brannan'), ('earlybird', 'Earlybird'), ('hudson', 'Hudson'), ('inkwell', 'Inkwell'), ('lofi', 'Lo-Fi'), ('kelvin', 'Kelvin'), ('normal', 'Normal'), ('nashville', 'Nashville'), ('rise', 'Rise'), ('toaster', 'Toaster'), ('valencia', 'Valencia'), ('walden', 'Walden'), ('xpro2', 'X-pro II')], default='normal', max_length=32)),
27 | ('account_owner', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)),
28 | ],
29 | options={
30 | 'ordering': ['-made_at'],
31 | },
32 | ),
33 | ]
34 |
--------------------------------------------------------------------------------
/posts/migrations/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bluesky-0412/API_Django/2fe694997713372b791572a78e86e2460706f303/posts/migrations/__init__.py
--------------------------------------------------------------------------------
/posts/models.py:
--------------------------------------------------------------------------------
1 | from django.db import models
2 | from django.contrib.auth.models import User
3 |
4 |
5 | class Post(models.Model):
6 |
7 | image_filter_choices = [
8 | ('_1977', '1977'),
9 | ('brannan', 'Brannan'),
10 | ('earlybird', 'Earlybird'),
11 | ('hudson', 'Hudson'),
12 | ('inkwell', 'Inkwell'),
13 | ('lofi', 'Lo-Fi'),
14 | ('kelvin', 'Kelvin'),
15 | ('normal', 'Normal'),
16 | ('nashville', 'Nashville'),
17 | ('rise', 'Rise'),
18 | ('toaster', 'Toaster'),
19 | ('valencia', 'Valencia'),
20 | ('walden', 'Walden'),
21 | ('xpro2', 'X-pro II')
22 | ]
23 | account_owner = models.ForeignKey(User, on_delete=models.CASCADE)
24 | image = models.ImageField(upload_to='images/', default='../default_post_hde9ti', blank=True)
25 | image_filter = models.CharField(max_length=32, choices=image_filter_choices, default='normal')
26 | title = models.CharField(max_length=255)
27 | content = models.TextField(blank=True)
28 | made_at = models.DateTimeField(auto_now_add=True)
29 | edited_at = models.DateTimeField(auto_now=True)
30 |
31 | class Meta:
32 | ordering = ['-made_at']
33 |
34 | def __str__(self):
35 | return f'{self.id} {self.title}'
--------------------------------------------------------------------------------
/posts/serializers.py:
--------------------------------------------------------------------------------
1 | from rest_framework import serializers
2 | from posts.models import Post
3 | from likes.models import Like
4 |
5 |
6 | class PostSerializer(serializers.ModelSerializer):
7 | account_owner = serializers.ReadOnlyField(source='account_owner.username')
8 | is_account_owner = serializers.SerializerMethodField()
9 | profile_id = serializers.ReadOnlyField(source='account_owner.profile.id')
10 | profile_image = serializers.ReadOnlyField(source='account_owner.profile.image.url')
11 | like_id = serializers.SerializerMethodField()
12 | likes_count = serializers.ReadOnlyField()
13 | comments_count = serializers.ReadOnlyField()
14 |
15 | def validate_image(self, value):
16 | if value.size > 2 * 1024 * 1024:
17 | raise serializers.ValidationError('Image size larger than 2MB!')
18 | if value.image.height > 4096:
19 | raise serializers.ValidationError(
20 | 'Image height larger than 4096px!'
21 | )
22 | if value.image.width > 4096:
23 | raise serializers.ValidationError(
24 | 'Image width larger than 4096px!'
25 | )
26 | return value
27 |
28 | def get_is_account_owner(self, obj):
29 | request = self.context['request']
30 | return request.user == obj.account_owner
31 |
32 | def get_like_id(self, obj):
33 | user = self.context['request'].user
34 | if user.is_authenticated:
35 | like = Like.objects.filter(
36 | account_owner=user, post=obj
37 | ).first()
38 | return like.id if like else None
39 | return None
40 |
41 | class Meta:
42 | model = Post
43 | fields = [
44 | 'id', 'account_owner', 'is_account_owner', 'profile_id',
45 | 'profile_image', 'made_at', 'edited_at',
46 | 'title', 'content', 'image', 'image_filter',
47 | 'like_id', 'likes_count', 'comments_count',
48 | ]
--------------------------------------------------------------------------------
/posts/tests.py:
--------------------------------------------------------------------------------
1 | from django.contrib.auth.models import User
2 | from .models import Post
3 | from rest_framework import status
4 | from rest_framework.test import APITestCase
5 |
6 |
7 | class PostListViewTests(APITestCase):
8 | def setUp(self):
9 | User.objects.create_user(username='adam', password='pass')
10 |
11 | def test_can_list_posts(self):
12 | adam = User.objects.get(username='adam')
13 | Post.objects.create(owner=adam, title='a title')
14 | response = self.client.get('/posts/')
15 | self.assertEqual(response.status_code, status.HTTP_200_OK)
16 | print(response.data)
17 | print(len(response.data))
18 |
19 | def test_logged_in_user_can_create_post(self):
20 | self.client.login(username='adam', password='pass')
21 | response = self.client.post('/posts/', {'title': 'a title'})
22 | count = Post.objects.count()
23 | self.assertEqual(count, 1)
24 | self.assertEqual(response.status_code, status.HTTP_201_CREATED)
25 |
26 | def test_user_not_logged_in_cant_create_post(self):
27 | response = self.client.post('/posts/', {'title': 'a title'})
28 | self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN)
29 |
30 |
31 | class PostDetailViewTests(APITestCase):
32 | def setUp(self):
33 | adam = User.objects.create_user(username='adam', password='pass')
34 | brian = User.objects.create_user(username='brian', password='pass')
35 | Post.objects.create(
36 | owner=adam, title='a title', content='adams content'
37 | )
38 | Post.objects.create(
39 | owner=brian, title='another title', content='brians content'
40 | )
41 |
42 | def test_can_retrieve_post_using_valid_id(self):
43 | response = self.client.get('/posts/1/')
44 | self.assertEqual(response.data['title'], 'a title')
45 | self.assertEqual(response.status_code, status.HTTP_200_OK)
46 |
47 | def test_cant_retrieve_post_using_invalid_id(self):
48 | response = self.client.get('/posts/999/')
49 | self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND)
50 |
51 | def test_user_can_update_own_post(self):
52 | self.client.login(username='adam', password='pass')
53 | response = self.client.put('/posts/1/', {'title': 'a new title'})
54 | post = Post.objects.filter(pk=1).first()
55 | self.assertEqual(post.title, 'a new title')
56 | self.assertEqual(response.status_code, status.HTTP_200_OK)
57 |
58 | def test_user_cant_update_another_users_post(self):
59 | self.client.login(username='adam', password='pass')
60 | response = self.client.put('/posts/2/', {'title': 'a new title'})
61 | self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN)
--------------------------------------------------------------------------------
/posts/urls.py:
--------------------------------------------------------------------------------
1 | from django.urls import path
2 | from posts import views
3 |
4 | urlpatterns = [
5 | path('posts/', views.PostList.as_view()),
6 | path('posts//', views.PostDetail.as_view())
7 | ]
--------------------------------------------------------------------------------
/posts/views.py:
--------------------------------------------------------------------------------
1 | from django.db.models import Count
2 | from rest_framework import generics, permissions, filters
3 | from django_filters.rest_framework import DjangoFilterBackend
4 | from drf_api.permissions import IsAccountOwnerOrReadOnly
5 | from .models import Post
6 | from .serializers import PostSerializer
7 |
8 |
9 | class PostList(generics.ListCreateAPIView):
10 | serializer_class = PostSerializer
11 | permission_classes = [permissions.IsAuthenticatedOrReadOnly]
12 | queryset = Post.objects.annotate(
13 | likes_count=Count('likes', distinct=True),
14 | comments_count=Count('comment', distinct=True)
15 | ).order_by('-made_at')
16 | filter_backends = [
17 | filters.OrderingFilter,
18 | filters.SearchFilter,
19 | DjangoFilterBackend,
20 | ]
21 | filterset_fields = [
22 | 'account_owner__followed__account_owner__profile',
23 | 'likes__account_owner__profile',
24 | 'account_owner__profile',
25 | ]
26 | search_fields = [
27 | 'account_owner__username',
28 | 'title',
29 | ]
30 | ordering_fields = [
31 | 'likes_count',
32 | 'comments_count',
33 | 'likes__made_at',
34 | ]
35 |
36 | def perform_create(self, serializer):
37 | serializer.save(account_owner=self.request.user)
38 |
39 |
40 | class PostDetail(generics.RetrieveUpdateDestroyAPIView):
41 | serializer_class = PostSerializer
42 | permission_classes = [IsAccountOwnerOrReadOnly]
43 | queryset = Post.objects.annotate(
44 | likes_count=Count('likes', distinct=True),
45 | comments_count=Count('comment', distinct=True)
46 | ).order_by('-made_at')
--------------------------------------------------------------------------------
/profiles/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bluesky-0412/API_Django/2fe694997713372b791572a78e86e2460706f303/profiles/__init__.py
--------------------------------------------------------------------------------
/profiles/admin.py:
--------------------------------------------------------------------------------
1 | from django.contrib import admin
2 | from .models import Profile
3 |
4 | admin.site.register(Profile)
5 |
--------------------------------------------------------------------------------
/profiles/apps.py:
--------------------------------------------------------------------------------
1 | from django.apps import AppConfig
2 |
3 |
4 | class ProfilesConfig(AppConfig):
5 | default_auto_field = 'django.db.models.BigAutoField'
6 | name = 'profiles'
7 |
--------------------------------------------------------------------------------
/profiles/migrations/0001_initial.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 3.2.20 on 2024-01-28 17:04
2 |
3 | from django.conf import settings
4 | from django.db import migrations, models
5 | import django.db.models.deletion
6 |
7 |
8 | class Migration(migrations.Migration):
9 |
10 | initial = True
11 |
12 | dependencies = [
13 | migrations.swappable_dependency(settings.AUTH_USER_MODEL),
14 | ]
15 |
16 | operations = [
17 | migrations.CreateModel(
18 | name='Profile',
19 | fields=[
20 | ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
21 | ('made_at', models.DateTimeField(auto_now_add=True)),
22 | ('edited_at', models.DateTimeField(auto_now=True)),
23 | ('name', models.CharField(blank=True, max_length=255)),
24 | ('content', models.TextField(blank=True)),
25 | ('image', models.ImageField(default='../default_profile_ftyuqx', upload_to='images/')),
26 | ('account_owner', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)),
27 | ],
28 | options={
29 | 'ordering': ['-made_at'],
30 | },
31 | ),
32 | ]
33 |
--------------------------------------------------------------------------------
/profiles/migrations/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bluesky-0412/API_Django/2fe694997713372b791572a78e86e2460706f303/profiles/migrations/__init__.py
--------------------------------------------------------------------------------
/profiles/models.py:
--------------------------------------------------------------------------------
1 | from django.db import models
2 | from django.db.models.signals import post_save
3 | from django.contrib.auth.models import User
4 |
5 |
6 | class Profile(models.Model):
7 | image = models.ImageField(upload_to='images/', default='../default_profile_ftyuqx')
8 | account_owner = models.OneToOneField(User, on_delete=models.CASCADE)
9 | name = models.CharField(max_length=255, blank=True)
10 | content = models.TextField(blank=True)
11 | made_at = models.DateTimeField(auto_now_add=True)
12 | edited_at = models.DateTimeField(auto_now=True)
13 |
14 | class Meta:
15 | ordering = ['-made_at']
16 |
17 | def __str__(self):
18 | return f"{self.account_owner}'s profile"
19 |
20 |
21 | def create_profile(sender, instance, created, **kwargs):
22 | if created:
23 | Profile.objects.create(account_owner=instance)
24 |
25 | post_save.connect(create_profile, sender=User)
26 |
--------------------------------------------------------------------------------
/profiles/serializers.py:
--------------------------------------------------------------------------------
1 | from rest_framework import serializers
2 | from .models import Profile
3 | from followers.models import Follower
4 |
5 |
6 | class ProfileSerializer(serializers.ModelSerializer):
7 | account_owner = serializers.ReadOnlyField(source='account_owner.username')
8 | is_account_owner = serializers.SerializerMethodField()
9 | following_id = serializers.SerializerMethodField()
10 | posts_count = serializers.ReadOnlyField()
11 | followers_count = serializers.ReadOnlyField()
12 | following_count = serializers.ReadOnlyField()
13 |
14 | def get_is_account_owner(self, obj):
15 | request = self.context['request']
16 | return request.user == obj.account_owner
17 |
18 | def get_following_id(self, obj):
19 | user = self.context['request'].user
20 | if user.is_authenticated:
21 | following = Follower.objects.filter(
22 | account_owner=user, followed=obj.account_owner
23 | ).first()
24 | # print(following)
25 | return following.id if following else None
26 | return None
27 |
28 | class Meta:
29 | model = Profile
30 | fields = [
31 | 'id', 'account_owner', 'made_at', 'edited_at', 'name',
32 | 'content', 'image', 'is_account_owner', 'following_id',
33 | 'posts_count', 'followers_count', 'following_count',
34 | ]
--------------------------------------------------------------------------------
/profiles/tests.py:
--------------------------------------------------------------------------------
1 | from django.test import TestCase
2 |
3 | # Create your tests here.
4 |
--------------------------------------------------------------------------------
/profiles/urls.py:
--------------------------------------------------------------------------------
1 | from django.urls import path
2 | from profiles import views
3 |
4 | urlpatterns = [
5 | path('profiles/', views.ProfileList.as_view()),
6 | path('profiles//', views.ProfileDetail.as_view()),
7 | ]
--------------------------------------------------------------------------------
/profiles/views.py:
--------------------------------------------------------------------------------
1 | from django.db.models import Count
2 | from rest_framework import generics, filters
3 | from django_filters.rest_framework import DjangoFilterBackend
4 | from drf_api.permissions import IsAccountOwnerOrReadOnly
5 | from .models import Profile
6 | from .serializers import ProfileSerializer
7 |
8 |
9 | class ProfileList(generics.ListAPIView):
10 | queryset = Profile.objects.annotate(
11 | posts_count=Count('account_owner__post', distinct=True),
12 | followers_count=Count('account_owner__followed', distinct=True),
13 | following_count=Count('account_owner__following', distinct=True)
14 | ).order_by('-made_at')
15 | serializer_class = ProfileSerializer
16 | filter_backends = [
17 | filters.OrderingFilter,
18 | DjangoFilterBackend,
19 | ]
20 | filterset_fields = [
21 | 'account_owner__following__followed__profile',
22 | 'account_owner__followed__account_owner__profile',
23 | ]
24 | ordering_fields = [
25 | 'posts_count',
26 | 'followers_count',
27 | 'following_count',
28 | 'account_owner__following__made_at',
29 | 'account_owner__followed__made_at',
30 | ]
31 |
32 |
33 | class ProfileDetail(generics.RetrieveUpdateAPIView):
34 | permission_classes = [IsAccountOwnerOrReadOnly]
35 | queryset = Profile.objects.annotate(
36 | posts_count=Count('account_owner__post', distinct=True),
37 | followers_count=Count('account_owner__followed', distinct=True),
38 | following_count=Count('account_owner__following', distinct=True)
39 | ).order_by('-made_at')
40 | serializer_class = ProfileSerializer
--------------------------------------------------------------------------------
/requirements.txt:
--------------------------------------------------------------------------------
1 | asgiref==3.7.2
2 | cloudinary==1.33.0
3 | dj-database-url==0.5.0
4 | dj-rest-auth==2.1.9
5 | Django==3.2.20
6 | django-allauth==0.44.0
7 | django-cloudinary-storage==0.3.0
8 | django-cors-headers==4.2.0
9 | django-filter==23.2
10 | djangorestframework==3.14.0
11 | djangorestframework-simplejwt==4.7.2
12 | gunicorn==20.1.0
13 | oauthlib==3.2.2
14 | Pillow==8.2.0
15 | psycopg2==2.9.6
16 | PyJWT==2.7.0
17 | python3-openid==3.2.0
18 | pytz==2023.3
19 | requests-oauthlib==1.3.1
20 | sqlparse==0.4.4
21 | urllib3==1.26.16
22 | whitenoise==6.4.0
23 |
--------------------------------------------------------------------------------
/runtime.txt:
--------------------------------------------------------------------------------
1 | python-3.9.16
--------------------------------------------------------------------------------
/staticfiles/admin/css/dashboard.css:
--------------------------------------------------------------------------------
1 | /* DASHBOARD */
2 |
3 | .dashboard .module table th {
4 | width: 100%;
5 | }
6 |
7 | .dashboard .module table td {
8 | white-space: nowrap;
9 | }
10 |
11 | .dashboard .module table td a {
12 | display: block;
13 | padding-right: .6em;
14 | }
15 |
16 | /* RECENT ACTIONS MODULE */
17 |
18 | .module ul.actionlist {
19 | margin-left: 0;
20 | }
21 |
22 | ul.actionlist li {
23 | list-style-type: none;
24 | overflow: hidden;
25 | text-overflow: ellipsis;
26 | }
27 |
--------------------------------------------------------------------------------
/staticfiles/admin/css/fonts.css:
--------------------------------------------------------------------------------
1 | @font-face {
2 | font-family: 'Roboto';
3 | src: url('../fonts/Roboto-Bold-webfont.woff');
4 | font-weight: 700;
5 | font-style: normal;
6 | }
7 |
8 | @font-face {
9 | font-family: 'Roboto';
10 | src: url('../fonts/Roboto-Regular-webfont.woff');
11 | font-weight: 400;
12 | font-style: normal;
13 | }
14 |
15 | @font-face {
16 | font-family: 'Roboto';
17 | src: url('../fonts/Roboto-Light-webfont.woff');
18 | font-weight: 300;
19 | font-style: normal;
20 | }
21 |
--------------------------------------------------------------------------------
/staticfiles/admin/css/login.css:
--------------------------------------------------------------------------------
1 | /* LOGIN FORM */
2 |
3 | .login {
4 | background: var(--darkened-bg);
5 | height: auto;
6 | }
7 |
8 | .login #header {
9 | height: auto;
10 | padding: 15px 16px;
11 | justify-content: center;
12 | }
13 |
14 | .login #header h1 {
15 | font-size: 18px;
16 | }
17 |
18 | .login #header h1 a {
19 | color: var(--header-link-color);
20 | }
21 |
22 | .login #content {
23 | padding: 20px 20px 0;
24 | }
25 |
26 | .login #container {
27 | background: var(--body-bg);
28 | border: 1px solid var(--hairline-color);
29 | border-radius: 4px;
30 | overflow: hidden;
31 | width: 28em;
32 | min-width: 300px;
33 | margin: 100px auto;
34 | height: auto;
35 | }
36 |
37 | .login .form-row {
38 | padding: 4px 0;
39 | }
40 |
41 | .login .form-row label {
42 | display: block;
43 | line-height: 2em;
44 | }
45 |
46 | .login .form-row #id_username, .login .form-row #id_password {
47 | padding: 8px;
48 | width: 100%;
49 | box-sizing: border-box;
50 | }
51 |
52 | .login .submit-row {
53 | padding: 1em 0 0 0;
54 | margin: 0;
55 | text-align: center;
56 | }
57 |
58 | .login .password-reset-link {
59 | text-align: center;
60 | }
61 |
--------------------------------------------------------------------------------
/staticfiles/admin/css/nav_sidebar.css:
--------------------------------------------------------------------------------
1 | .sticky {
2 | position: sticky;
3 | top: 0;
4 | max-height: 100vh;
5 | }
6 |
7 | .toggle-nav-sidebar {
8 | z-index: 20;
9 | left: 0;
10 | display: flex;
11 | align-items: center;
12 | justify-content: center;
13 | flex: 0 0 23px;
14 | width: 23px;
15 | border: 0;
16 | border-right: 1px solid var(--hairline-color);
17 | background-color: var(--body-bg);
18 | cursor: pointer;
19 | font-size: 20px;
20 | color: var(--link-fg);
21 | padding: 0;
22 | }
23 |
24 | [dir="rtl"] .toggle-nav-sidebar {
25 | border-left: 1px solid var(--hairline-color);
26 | border-right: 0;
27 | }
28 |
29 | .toggle-nav-sidebar:hover,
30 | .toggle-nav-sidebar:focus {
31 | background-color: var(--darkened-bg);
32 | }
33 |
34 | #nav-sidebar {
35 | z-index: 15;
36 | flex: 0 0 275px;
37 | left: -276px;
38 | margin-left: -276px;
39 | border-top: 1px solid transparent;
40 | border-right: 1px solid var(--hairline-color);
41 | background-color: var(--body-bg);
42 | overflow: auto;
43 | }
44 |
45 | [dir="rtl"] #nav-sidebar {
46 | border-left: 1px solid var(--hairline-color);
47 | border-right: 0;
48 | left: 0;
49 | margin-left: 0;
50 | right: -276px;
51 | margin-right: -276px;
52 | }
53 |
54 | .toggle-nav-sidebar::before {
55 | content: '\00BB';
56 | }
57 |
58 | .main.shifted .toggle-nav-sidebar::before {
59 | content: '\00AB';
60 | }
61 |
62 | .main.shifted > #nav-sidebar {
63 | left: 24px;
64 | margin-left: 0;
65 | }
66 |
67 | [dir="rtl"] .main.shifted > #nav-sidebar {
68 | left: 0;
69 | right: 24px;
70 | margin-right: 0;
71 | }
72 |
73 | #nav-sidebar .module th {
74 | width: 100%;
75 | overflow-wrap: anywhere;
76 | }
77 |
78 | #nav-sidebar .module th,
79 | #nav-sidebar .module caption {
80 | padding-left: 16px;
81 | }
82 |
83 | #nav-sidebar .module td {
84 | white-space: nowrap;
85 | }
86 |
87 | [dir="rtl"] #nav-sidebar .module th,
88 | [dir="rtl"] #nav-sidebar .module caption {
89 | padding-left: 8px;
90 | padding-right: 16px;
91 | }
92 |
93 | #nav-sidebar .current-app .section:link,
94 | #nav-sidebar .current-app .section:visited {
95 | color: var(--header-color);
96 | font-weight: bold;
97 | }
98 |
99 | #nav-sidebar .current-model {
100 | background: var(--selected-row);
101 | }
102 |
103 | .main > #nav-sidebar + .content {
104 | max-width: calc(100% - 23px);
105 | }
106 |
107 | .main.shifted > #nav-sidebar + .content {
108 | max-width: calc(100% - 299px);
109 | }
110 |
111 | @media (max-width: 767px) {
112 | #nav-sidebar, #toggle-nav-sidebar {
113 | display: none;
114 | }
115 |
116 | .main > #nav-sidebar + .content,
117 | .main.shifted > #nav-sidebar + .content {
118 | max-width: 100%;
119 | }
120 | }
121 |
--------------------------------------------------------------------------------
/staticfiles/admin/css/responsive_rtl.css:
--------------------------------------------------------------------------------
1 | /* TABLETS */
2 |
3 | @media (max-width: 1024px) {
4 | [dir="rtl"] .colMS {
5 | margin-right: 0;
6 | }
7 |
8 | [dir="rtl"] #user-tools {
9 | text-align: right;
10 | }
11 |
12 | [dir="rtl"] #changelist .actions label {
13 | padding-left: 10px;
14 | padding-right: 0;
15 | }
16 |
17 | [dir="rtl"] #changelist .actions select {
18 | margin-left: 0;
19 | margin-right: 15px;
20 | }
21 |
22 | [dir="rtl"] .change-list .filtered .results,
23 | [dir="rtl"] .change-list .filtered .paginator,
24 | [dir="rtl"] .filtered #toolbar,
25 | [dir="rtl"] .filtered div.xfull,
26 | [dir="rtl"] .filtered .actions,
27 | [dir="rtl"] #changelist-filter {
28 | margin-left: 0;
29 | }
30 |
31 | [dir="rtl"] .inline-group ul.tools a.add,
32 | [dir="rtl"] .inline-group div.add-row a,
33 | [dir="rtl"] .inline-group .tabular tr.add-row td a {
34 | padding: 8px 26px 8px 10px;
35 | background-position: calc(100% - 8px) 9px;
36 | }
37 |
38 | [dir="rtl"] .related-widget-wrapper-link + .selector {
39 | margin-right: 0;
40 | margin-left: 15px;
41 | }
42 |
43 | [dir="rtl"] .selector .selector-filter label {
44 | margin-right: 0;
45 | margin-left: 8px;
46 | }
47 |
48 | [dir="rtl"] .object-tools li {
49 | float: right;
50 | }
51 |
52 | [dir="rtl"] .object-tools li + li {
53 | margin-left: 0;
54 | margin-right: 15px;
55 | }
56 |
57 | [dir="rtl"] .dashboard .module table td a {
58 | padding-left: 0;
59 | padding-right: 16px;
60 | }
61 | }
62 |
63 | /* MOBILE */
64 |
65 | @media (max-width: 767px) {
66 | [dir="rtl"] .aligned .related-lookup,
67 | [dir="rtl"] .aligned .datetimeshortcuts {
68 | margin-left: 0;
69 | margin-right: 15px;
70 | }
71 |
72 | [dir="rtl"] .aligned ul {
73 | margin-right: 0;
74 | }
75 |
76 | [dir="rtl"] #changelist-filter {
77 | margin-left: 0;
78 | margin-right: 0;
79 | }
80 | }
81 |
--------------------------------------------------------------------------------
/staticfiles/admin/css/vendor/select2/LICENSE-SELECT2.md:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2012-2017 Kevin Brown, Igor Vaynberg, and Select2 contributors
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in
13 | all copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21 | THE SOFTWARE.
22 |
--------------------------------------------------------------------------------
/staticfiles/admin/fonts/README.txt:
--------------------------------------------------------------------------------
1 | Roboto webfont source: https://www.google.com/fonts/specimen/Roboto
2 | WOFF files extracted using https://github.com/majodev/google-webfonts-helper
3 | Weights used in this project: Light (300), Regular (400), Bold (700)
4 |
--------------------------------------------------------------------------------
/staticfiles/admin/fonts/Roboto-Bold-webfont.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bluesky-0412/API_Django/2fe694997713372b791572a78e86e2460706f303/staticfiles/admin/fonts/Roboto-Bold-webfont.woff
--------------------------------------------------------------------------------
/staticfiles/admin/fonts/Roboto-Light-webfont.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bluesky-0412/API_Django/2fe694997713372b791572a78e86e2460706f303/staticfiles/admin/fonts/Roboto-Light-webfont.woff
--------------------------------------------------------------------------------
/staticfiles/admin/fonts/Roboto-Regular-webfont.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bluesky-0412/API_Django/2fe694997713372b791572a78e86e2460706f303/staticfiles/admin/fonts/Roboto-Regular-webfont.woff
--------------------------------------------------------------------------------
/staticfiles/admin/img/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2014 Code Charm Ltd
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy of
6 | this software and associated documentation files (the "Software"), to deal in
7 | the Software without restriction, including without limitation the rights to
8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
9 | the Software, and to permit persons to whom the Software is furnished to do so,
10 | subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21 |
--------------------------------------------------------------------------------
/staticfiles/admin/img/README.txt:
--------------------------------------------------------------------------------
1 | All icons are taken from Font Awesome (http://fontawesome.io/) project.
2 | The Font Awesome font is licensed under the SIL OFL 1.1:
3 | - https://scripts.sil.org/OFL
4 |
5 | SVG icons source: https://github.com/encharm/Font-Awesome-SVG-PNG
6 | Font-Awesome-SVG-PNG is licensed under the MIT license (see file license
7 | in current folder).
8 |
--------------------------------------------------------------------------------
/staticfiles/admin/img/calendar-icons.svg:
--------------------------------------------------------------------------------
1 |
15 |
--------------------------------------------------------------------------------
/staticfiles/admin/img/gis/move_vertex_off.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/staticfiles/admin/img/gis/move_vertex_on.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/staticfiles/admin/img/icon-addlink.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/staticfiles/admin/img/icon-alert.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/staticfiles/admin/img/icon-calendar.svg:
--------------------------------------------------------------------------------
1 |
10 |
--------------------------------------------------------------------------------
/staticfiles/admin/img/icon-changelink.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/staticfiles/admin/img/icon-clock.svg:
--------------------------------------------------------------------------------
1 |
10 |
--------------------------------------------------------------------------------
/staticfiles/admin/img/icon-deletelink.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/staticfiles/admin/img/icon-no.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/staticfiles/admin/img/icon-unknown-alt.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/staticfiles/admin/img/icon-unknown.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/staticfiles/admin/img/icon-viewlink.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/staticfiles/admin/img/icon-yes.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/staticfiles/admin/img/inline-delete.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/staticfiles/admin/img/search.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/staticfiles/admin/img/sorting-icons.svg:
--------------------------------------------------------------------------------
1 |
20 |
--------------------------------------------------------------------------------
/staticfiles/admin/img/tooltag-add.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/staticfiles/admin/img/tooltag-arrowright.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/staticfiles/admin/js/autocomplete.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 | {
3 | const $ = django.jQuery;
4 | const init = function($element, options) {
5 | const settings = $.extend({
6 | ajax: {
7 | data: function(params) {
8 | return {
9 | term: params.term,
10 | page: params.page,
11 | app_label: $element.data('app-label'),
12 | model_name: $element.data('model-name'),
13 | field_name: $element.data('field-name')
14 | };
15 | }
16 | }
17 | }, options);
18 | $element.select2(settings);
19 | };
20 |
21 | $.fn.djangoAdminSelect2 = function(options) {
22 | const settings = $.extend({}, options);
23 | $.each(this, function(i, element) {
24 | const $element = $(element);
25 | init($element, settings);
26 | });
27 | return this;
28 | };
29 |
30 | $(function() {
31 | // Initialize all autocomplete widgets except the one in the template
32 | // form used when a new formset is added.
33 | $('.admin-autocomplete').not('[name*=__prefix__]').djangoAdminSelect2();
34 | });
35 |
36 | $(document).on('formset:added', (function() {
37 | return function(event, $newFormset) {
38 | return $newFormset.find('.admin-autocomplete').djangoAdminSelect2();
39 | };
40 | })(this));
41 | }
42 |
--------------------------------------------------------------------------------
/staticfiles/admin/js/cancel.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 | {
3 | // Call function fn when the DOM is loaded and ready. If it is already
4 | // loaded, call the function now.
5 | // http://youmightnotneedjquery.com/#ready
6 | function ready(fn) {
7 | if (document.readyState !== 'loading') {
8 | fn();
9 | } else {
10 | document.addEventListener('DOMContentLoaded', fn);
11 | }
12 | }
13 |
14 | ready(function() {
15 | function handleClick(event) {
16 | event.preventDefault();
17 | const params = new URLSearchParams(window.location.search);
18 | if (params.has('_popup')) {
19 | window.close(); // Close the popup.
20 | } else {
21 | window.history.back(); // Otherwise, go back.
22 | }
23 | }
24 |
25 | document.querySelectorAll('.cancel-link').forEach(function(el) {
26 | el.addEventListener('click', handleClick);
27 | });
28 | });
29 | }
30 |
--------------------------------------------------------------------------------
/staticfiles/admin/js/change_form.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 | {
3 | const inputTags = ['BUTTON', 'INPUT', 'SELECT', 'TEXTAREA'];
4 | const modelName = document.getElementById('django-admin-form-add-constants').dataset.modelName;
5 | if (modelName) {
6 | const form = document.getElementById(modelName + '_form');
7 | for (const element of form.elements) {
8 | // HTMLElement.offsetParent returns null when the element is not
9 | // rendered.
10 | if (inputTags.includes(element.tagName) && !element.disabled && element.offsetParent) {
11 | element.focus();
12 | break;
13 | }
14 | }
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/staticfiles/admin/js/collapse.js:
--------------------------------------------------------------------------------
1 | /*global gettext*/
2 | 'use strict';
3 | {
4 | window.addEventListener('load', function() {
5 | // Add anchor tag for Show/Hide link
6 | const fieldsets = document.querySelectorAll('fieldset.collapse');
7 | for (const [i, elem] of fieldsets.entries()) {
8 | // Don't hide if fields in this fieldset have errors
9 | if (elem.querySelectorAll('div.errors, ul.errorlist').length === 0) {
10 | elem.classList.add('collapsed');
11 | const h2 = elem.querySelector('h2');
12 | const link = document.createElement('a');
13 | link.id = 'fieldsetcollapser' + i;
14 | link.className = 'collapse-toggle';
15 | link.href = '#';
16 | link.textContent = gettext('Show');
17 | h2.appendChild(document.createTextNode(' ('));
18 | h2.appendChild(link);
19 | h2.appendChild(document.createTextNode(')'));
20 | }
21 | }
22 | // Add toggle to hide/show anchor tag
23 | const toggleFunc = function(ev) {
24 | if (ev.target.matches('.collapse-toggle')) {
25 | ev.preventDefault();
26 | ev.stopPropagation();
27 | const fieldset = ev.target.closest('fieldset');
28 | if (fieldset.classList.contains('collapsed')) {
29 | // Show
30 | ev.target.textContent = gettext('Hide');
31 | fieldset.classList.remove('collapsed');
32 | } else {
33 | // Hide
34 | ev.target.textContent = gettext('Show');
35 | fieldset.classList.add('collapsed');
36 | }
37 | }
38 | };
39 | document.querySelectorAll('fieldset.module').forEach(function(el) {
40 | el.addEventListener('click', toggleFunc);
41 | });
42 | });
43 | }
44 |
--------------------------------------------------------------------------------
/staticfiles/admin/js/jquery.init.js:
--------------------------------------------------------------------------------
1 | /*global jQuery:false*/
2 | 'use strict';
3 | /* Puts the included jQuery into our own namespace using noConflict and passing
4 | * it 'true'. This ensures that the included jQuery doesn't pollute the global
5 | * namespace (i.e. this preserves pre-existing values for both window.$ and
6 | * window.jQuery).
7 | */
8 | window.django = {jQuery: jQuery.noConflict(true)};
9 |
--------------------------------------------------------------------------------
/staticfiles/admin/js/nav_sidebar.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 | {
3 | const toggleNavSidebar = document.getElementById('toggle-nav-sidebar');
4 | if (toggleNavSidebar !== null) {
5 | const navLinks = document.querySelectorAll('#nav-sidebar a');
6 | function disableNavLinkTabbing() {
7 | for (const navLink of navLinks) {
8 | navLink.tabIndex = -1;
9 | }
10 | }
11 | function enableNavLinkTabbing() {
12 | for (const navLink of navLinks) {
13 | navLink.tabIndex = 0;
14 | }
15 | }
16 |
17 | const main = document.getElementById('main');
18 | let navSidebarIsOpen = localStorage.getItem('django.admin.navSidebarIsOpen');
19 | if (navSidebarIsOpen === null) {
20 | navSidebarIsOpen = 'true';
21 | }
22 | if (navSidebarIsOpen === 'false') {
23 | disableNavLinkTabbing();
24 | }
25 | main.classList.toggle('shifted', navSidebarIsOpen === 'true');
26 |
27 | toggleNavSidebar.addEventListener('click', function() {
28 | if (navSidebarIsOpen === 'true') {
29 | navSidebarIsOpen = 'false';
30 | disableNavLinkTabbing();
31 | } else {
32 | navSidebarIsOpen = 'true';
33 | enableNavLinkTabbing();
34 | }
35 | localStorage.setItem('django.admin.navSidebarIsOpen', navSidebarIsOpen);
36 | main.classList.toggle('shifted');
37 | });
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/staticfiles/admin/js/popup_response.js:
--------------------------------------------------------------------------------
1 | /*global opener */
2 | 'use strict';
3 | {
4 | const initData = JSON.parse(document.getElementById('django-admin-popup-response-constants').dataset.popupResponse);
5 | switch(initData.action) {
6 | case 'change':
7 | opener.dismissChangeRelatedObjectPopup(window, initData.value, initData.obj, initData.new_value);
8 | break;
9 | case 'delete':
10 | opener.dismissDeleteRelatedObjectPopup(window, initData.value);
11 | break;
12 | default:
13 | opener.dismissAddRelatedObjectPopup(window, initData.value, initData.obj);
14 | break;
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/staticfiles/admin/js/prepopulate.js:
--------------------------------------------------------------------------------
1 | /*global URLify*/
2 | 'use strict';
3 | {
4 | const $ = django.jQuery;
5 | $.fn.prepopulate = function(dependencies, maxLength, allowUnicode) {
6 | /*
7 | Depends on urlify.js
8 | Populates a selected field with the values of the dependent fields,
9 | URLifies and shortens the string.
10 | dependencies - array of dependent fields ids
11 | maxLength - maximum length of the URLify'd string
12 | allowUnicode - Unicode support of the URLify'd string
13 | */
14 | return this.each(function() {
15 | const prepopulatedField = $(this);
16 |
17 | const populate = function() {
18 | // Bail if the field's value has been changed by the user
19 | if (prepopulatedField.data('_changed')) {
20 | return;
21 | }
22 |
23 | const values = [];
24 | $.each(dependencies, function(i, field) {
25 | field = $(field);
26 | if (field.val().length > 0) {
27 | values.push(field.val());
28 | }
29 | });
30 | prepopulatedField.val(URLify(values.join(' '), maxLength, allowUnicode));
31 | };
32 |
33 | prepopulatedField.data('_changed', false);
34 | prepopulatedField.on('change', function() {
35 | prepopulatedField.data('_changed', true);
36 | });
37 |
38 | if (!prepopulatedField.val()) {
39 | $(dependencies.join(',')).on('keyup change focus', populate);
40 | }
41 | });
42 | };
43 | }
44 |
--------------------------------------------------------------------------------
/staticfiles/admin/js/prepopulate_init.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 | {
3 | const $ = django.jQuery;
4 | const fields = $('#django-admin-prepopulated-fields-constants').data('prepopulatedFields');
5 | $.each(fields, function(index, field) {
6 | $('.empty-form .form-row .field-' + field.name + ', .empty-form.form-row .field-' + field.name).addClass('prepopulated_field');
7 | $(field.id).data('dependency_list', field.dependency_list).prepopulate(
8 | field.dependency_ids, field.maxLength, field.allowUnicode
9 | );
10 | });
11 | }
12 |
--------------------------------------------------------------------------------
/staticfiles/admin/js/vendor/jquery/LICENSE.txt:
--------------------------------------------------------------------------------
1 | Copyright JS Foundation and other contributors, https://js.foundation/
2 |
3 | Permission is hereby granted, free of charge, to any person obtaining
4 | a copy of this software and associated documentation files (the
5 | "Software"), to deal in the Software without restriction, including
6 | without limitation the rights to use, copy, modify, merge, publish,
7 | distribute, sublicense, and/or sell copies of the Software, and to
8 | permit persons to whom the Software is furnished to do so, subject to
9 | the following conditions:
10 |
11 | The above copyright notice and this permission notice shall be
12 | included in all copies or substantial portions of the Software.
13 |
14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21 |
--------------------------------------------------------------------------------
/staticfiles/admin/js/vendor/select2/LICENSE.md:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2012-2017 Kevin Brown, Igor Vaynberg, and Select2 contributors
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in
13 | all copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21 | THE SOFTWARE.
22 |
--------------------------------------------------------------------------------
/staticfiles/admin/js/vendor/select2/i18n/af.js:
--------------------------------------------------------------------------------
1 | /*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */
2 |
3 | !function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;e.define("select2/i18n/af",[],function(){return{errorLoading:function(){return"Die resultate kon nie gelaai word nie."},inputTooLong:function(e){var n=e.input.length-e.maximum,r="Verwyders asseblief "+n+" character";return 1!=n&&(r+="s"),r},inputTooShort:function(e){return"Voer asseblief "+(e.minimum-e.input.length)+" of meer karakters"},loadingMore:function(){return"Meer resultate word gelaai…"},maximumSelected:function(e){var n="Kies asseblief net "+e.maximum+" item";return 1!=e.maximum&&(n+="s"),n},noResults:function(){return"Geen resultate gevind"},searching:function(){return"Besig…"},removeAllItems:function(){return"Verwyder alle items"}}}),e.define,e.require}();
--------------------------------------------------------------------------------
/staticfiles/admin/js/vendor/select2/i18n/ar.js:
--------------------------------------------------------------------------------
1 | /*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */
2 |
3 | !function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var n=jQuery.fn.select2.amd;n.define("select2/i18n/ar",[],function(){return{errorLoading:function(){return"لا يمكن تحميل النتائج"},inputTooLong:function(n){return"الرجاء حذف "+(n.input.length-n.maximum)+" عناصر"},inputTooShort:function(n){return"الرجاء إضافة "+(n.minimum-n.input.length)+" عناصر"},loadingMore:function(){return"جاري تحميل نتائج إضافية..."},maximumSelected:function(n){return"تستطيع إختيار "+n.maximum+" بنود فقط"},noResults:function(){return"لم يتم العثور على أي نتائج"},searching:function(){return"جاري البحث…"},removeAllItems:function(){return"قم بإزالة كل العناصر"}}}),n.define,n.require}();
--------------------------------------------------------------------------------
/staticfiles/admin/js/vendor/select2/i18n/az.js:
--------------------------------------------------------------------------------
1 | /*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */
2 |
3 | !function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var n=jQuery.fn.select2.amd;n.define("select2/i18n/az",[],function(){return{inputTooLong:function(n){return n.input.length-n.maximum+" simvol silin"},inputTooShort:function(n){return n.minimum-n.input.length+" simvol daxil edin"},loadingMore:function(){return"Daha çox nəticə yüklənir…"},maximumSelected:function(n){return"Sadəcə "+n.maximum+" element seçə bilərsiniz"},noResults:function(){return"Nəticə tapılmadı"},searching:function(){return"Axtarılır…"},removeAllItems:function(){return"Bütün elementləri sil"}}}),n.define,n.require}();
--------------------------------------------------------------------------------
/staticfiles/admin/js/vendor/select2/i18n/bg.js:
--------------------------------------------------------------------------------
1 | /*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */
2 |
3 | !function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var n=jQuery.fn.select2.amd;n.define("select2/i18n/bg",[],function(){return{inputTooLong:function(n){var e=n.input.length-n.maximum,u="Моля въведете с "+e+" по-малко символ";return e>1&&(u+="a"),u},inputTooShort:function(n){var e=n.minimum-n.input.length,u="Моля въведете още "+e+" символ";return e>1&&(u+="a"),u},loadingMore:function(){return"Зареждат се още…"},maximumSelected:function(n){var e="Можете да направите до "+n.maximum+" ";return n.maximum>1?e+="избора":e+="избор",e},noResults:function(){return"Няма намерени съвпадения"},searching:function(){return"Търсене…"},removeAllItems:function(){return"Премахнете всички елементи"}}}),n.define,n.require}();
--------------------------------------------------------------------------------
/staticfiles/admin/js/vendor/select2/i18n/bn.js:
--------------------------------------------------------------------------------
1 | /*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */
2 |
3 | !function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var n=jQuery.fn.select2.amd;n.define("select2/i18n/bn",[],function(){return{errorLoading:function(){return"ফলাফলগুলি লোড করা যায়নি।"},inputTooLong:function(n){var e=n.input.length-n.maximum,u="অনুগ্রহ করে "+e+" টি অক্ষর মুছে দিন।";return 1!=e&&(u="অনুগ্রহ করে "+e+" টি অক্ষর মুছে দিন।"),u},inputTooShort:function(n){return n.minimum-n.input.length+" টি অক্ষর অথবা অধিক অক্ষর লিখুন।"},loadingMore:function(){return"আরো ফলাফল লোড হচ্ছে ..."},maximumSelected:function(n){var e=n.maximum+" টি আইটেম নির্বাচন করতে পারবেন।";return 1!=n.maximum&&(e=n.maximum+" টি আইটেম নির্বাচন করতে পারবেন।"),e},noResults:function(){return"কোন ফলাফল পাওয়া যায়নি।"},searching:function(){return"অনুসন্ধান করা হচ্ছে ..."}}}),n.define,n.require}();
--------------------------------------------------------------------------------
/staticfiles/admin/js/vendor/select2/i18n/bs.js:
--------------------------------------------------------------------------------
1 | /*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */
2 |
3 | !function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;e.define("select2/i18n/bs",[],function(){function e(e,n,r,t){return e%10==1&&e%100!=11?n:e%10>=2&&e%10<=4&&(e%100<12||e%100>14)?r:t}return{errorLoading:function(){return"Preuzimanje nije uspijelo."},inputTooLong:function(n){var r=n.input.length-n.maximum,t="Obrišite "+r+" simbol";return t+=e(r,"","a","a")},inputTooShort:function(n){var r=n.minimum-n.input.length,t="Ukucajte bar još "+r+" simbol";return t+=e(r,"","a","a")},loadingMore:function(){return"Preuzimanje još rezultata…"},maximumSelected:function(n){var r="Možete izabrati samo "+n.maximum+" stavk";return r+=e(n.maximum,"u","e","i")},noResults:function(){return"Ništa nije pronađeno"},searching:function(){return"Pretraga…"},removeAllItems:function(){return"Uklonite sve stavke"}}}),e.define,e.require}();
--------------------------------------------------------------------------------
/staticfiles/admin/js/vendor/select2/i18n/ca.js:
--------------------------------------------------------------------------------
1 | /*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */
2 |
3 | !function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;e.define("select2/i18n/ca",[],function(){return{errorLoading:function(){return"La càrrega ha fallat"},inputTooLong:function(e){var n=e.input.length-e.maximum,r="Si us plau, elimina "+n+" car";return r+=1==n?"àcter":"àcters"},inputTooShort:function(e){var n=e.minimum-e.input.length,r="Si us plau, introdueix "+n+" car";return r+=1==n?"àcter":"àcters"},loadingMore:function(){return"Carregant més resultats…"},maximumSelected:function(e){var n="Només es pot seleccionar "+e.maximum+" element";return 1!=e.maximum&&(n+="s"),n},noResults:function(){return"No s'han trobat resultats"},searching:function(){return"Cercant…"},removeAllItems:function(){return"Treu tots els elements"}}}),e.define,e.require}();
--------------------------------------------------------------------------------
/staticfiles/admin/js/vendor/select2/i18n/cs.js:
--------------------------------------------------------------------------------
1 | /*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */
2 |
3 | !function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;e.define("select2/i18n/cs",[],function(){function e(e,n){switch(e){case 2:return n?"dva":"dvě";case 3:return"tři";case 4:return"čtyři"}return""}return{errorLoading:function(){return"Výsledky nemohly být načteny."},inputTooLong:function(n){var t=n.input.length-n.maximum;return 1==t?"Prosím, zadejte o jeden znak méně.":t<=4?"Prosím, zadejte o "+e(t,!0)+" znaky méně.":"Prosím, zadejte o "+t+" znaků méně."},inputTooShort:function(n){var t=n.minimum-n.input.length;return 1==t?"Prosím, zadejte ještě jeden znak.":t<=4?"Prosím, zadejte ještě další "+e(t,!0)+" znaky.":"Prosím, zadejte ještě dalších "+t+" znaků."},loadingMore:function(){return"Načítají se další výsledky…"},maximumSelected:function(n){var t=n.maximum;return 1==t?"Můžete zvolit jen jednu položku.":t<=4?"Můžete zvolit maximálně "+e(t,!1)+" položky.":"Můžete zvolit maximálně "+t+" položek."},noResults:function(){return"Nenalezeny žádné položky."},searching:function(){return"Vyhledávání…"},removeAllItems:function(){return"Odstraňte všechny položky"}}}),e.define,e.require}();
--------------------------------------------------------------------------------
/staticfiles/admin/js/vendor/select2/i18n/da.js:
--------------------------------------------------------------------------------
1 | /*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */
2 |
3 | !function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;e.define("select2/i18n/da",[],function(){return{errorLoading:function(){return"Resultaterne kunne ikke indlæses."},inputTooLong:function(e){return"Angiv venligst "+(e.input.length-e.maximum)+" tegn mindre"},inputTooShort:function(e){return"Angiv venligst "+(e.minimum-e.input.length)+" tegn mere"},loadingMore:function(){return"Indlæser flere resultater…"},maximumSelected:function(e){var n="Du kan kun vælge "+e.maximum+" emne";return 1!=e.maximum&&(n+="r"),n},noResults:function(){return"Ingen resultater fundet"},searching:function(){return"Søger…"},removeAllItems:function(){return"Fjern alle elementer"}}}),e.define,e.require}();
--------------------------------------------------------------------------------
/staticfiles/admin/js/vendor/select2/i18n/de.js:
--------------------------------------------------------------------------------
1 | /*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */
2 |
3 | !function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;e.define("select2/i18n/de",[],function(){return{errorLoading:function(){return"Die Ergebnisse konnten nicht geladen werden."},inputTooLong:function(e){return"Bitte "+(e.input.length-e.maximum)+" Zeichen weniger eingeben"},inputTooShort:function(e){return"Bitte "+(e.minimum-e.input.length)+" Zeichen mehr eingeben"},loadingMore:function(){return"Lade mehr Ergebnisse…"},maximumSelected:function(e){var n="Sie können nur "+e.maximum+" Element";return 1!=e.maximum&&(n+="e"),n+=" auswählen"},noResults:function(){return"Keine Übereinstimmungen gefunden"},searching:function(){return"Suche…"},removeAllItems:function(){return"Entferne alle Elemente"}}}),e.define,e.require}();
--------------------------------------------------------------------------------
/staticfiles/admin/js/vendor/select2/i18n/dsb.js:
--------------------------------------------------------------------------------
1 | /*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */
2 |
3 | !function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var n=jQuery.fn.select2.amd;n.define("select2/i18n/dsb",[],function(){var n=["znamuško","znamušce","znamuška","znamuškow"],e=["zapisk","zapiska","zapiski","zapiskow"],u=function(n,e){return 1===n?e[0]:2===n?e[1]:n>2&&n<=4?e[2]:n>=5?e[3]:void 0};return{errorLoading:function(){return"Wuslědki njejsu se dali zacytaś."},inputTooLong:function(e){var a=e.input.length-e.maximum;return"Pšosym lašuj "+a+" "+u(a,n)},inputTooShort:function(e){var a=e.minimum-e.input.length;return"Pšosym zapódaj nanejmjenjej "+a+" "+u(a,n)},loadingMore:function(){return"Dalšne wuslědki se zacytaju…"},maximumSelected:function(n){return"Móžoš jano "+n.maximum+" "+u(n.maximum,e)+"wubraś."},noResults:function(){return"Žedne wuslědki namakane"},searching:function(){return"Pyta se…"},removeAllItems:function(){return"Remove all items"}}}),n.define,n.require}();
--------------------------------------------------------------------------------
/staticfiles/admin/js/vendor/select2/i18n/el.js:
--------------------------------------------------------------------------------
1 | /*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */
2 |
3 | !function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var n=jQuery.fn.select2.amd;n.define("select2/i18n/el",[],function(){return{errorLoading:function(){return"Τα αποτελέσματα δεν μπόρεσαν να φορτώσουν."},inputTooLong:function(n){var e=n.input.length-n.maximum,u="Παρακαλώ διαγράψτε "+e+" χαρακτήρ";return 1==e&&(u+="α"),1!=e&&(u+="ες"),u},inputTooShort:function(n){return"Παρακαλώ συμπληρώστε "+(n.minimum-n.input.length)+" ή περισσότερους χαρακτήρες"},loadingMore:function(){return"Φόρτωση περισσότερων αποτελεσμάτων…"},maximumSelected:function(n){var e="Μπορείτε να επιλέξετε μόνο "+n.maximum+" επιλογ";return 1==n.maximum&&(e+="ή"),1!=n.maximum&&(e+="ές"),e},noResults:function(){return"Δεν βρέθηκαν αποτελέσματα"},searching:function(){return"Αναζήτηση…"},removeAllItems:function(){return"Καταργήστε όλα τα στοιχεία"}}}),n.define,n.require}();
--------------------------------------------------------------------------------
/staticfiles/admin/js/vendor/select2/i18n/en.js:
--------------------------------------------------------------------------------
1 | /*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */
2 |
3 | !function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;e.define("select2/i18n/en",[],function(){return{errorLoading:function(){return"The results could not be loaded."},inputTooLong:function(e){var n=e.input.length-e.maximum,r="Please delete "+n+" character";return 1!=n&&(r+="s"),r},inputTooShort:function(e){return"Please enter "+(e.minimum-e.input.length)+" or more characters"},loadingMore:function(){return"Loading more results…"},maximumSelected:function(e){var n="You can only select "+e.maximum+" item";return 1!=e.maximum&&(n+="s"),n},noResults:function(){return"No results found"},searching:function(){return"Searching…"},removeAllItems:function(){return"Remove all items"}}}),e.define,e.require}();
--------------------------------------------------------------------------------
/staticfiles/admin/js/vendor/select2/i18n/es.js:
--------------------------------------------------------------------------------
1 | /*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */
2 |
3 | !function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;e.define("select2/i18n/es",[],function(){return{errorLoading:function(){return"No se pudieron cargar los resultados"},inputTooLong:function(e){var n=e.input.length-e.maximum,r="Por favor, elimine "+n+" car";return r+=1==n?"ácter":"acteres"},inputTooShort:function(e){var n=e.minimum-e.input.length,r="Por favor, introduzca "+n+" car";return r+=1==n?"ácter":"acteres"},loadingMore:function(){return"Cargando más resultados…"},maximumSelected:function(e){var n="Sólo puede seleccionar "+e.maximum+" elemento";return 1!=e.maximum&&(n+="s"),n},noResults:function(){return"No se encontraron resultados"},searching:function(){return"Buscando…"},removeAllItems:function(){return"Eliminar todos los elementos"}}}),e.define,e.require}();
--------------------------------------------------------------------------------
/staticfiles/admin/js/vendor/select2/i18n/et.js:
--------------------------------------------------------------------------------
1 | /*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */
2 |
3 | !function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;e.define("select2/i18n/et",[],function(){return{inputTooLong:function(e){var n=e.input.length-e.maximum,t="Sisesta "+n+" täht";return 1!=n&&(t+="e"),t+=" vähem"},inputTooShort:function(e){var n=e.minimum-e.input.length,t="Sisesta "+n+" täht";return 1!=n&&(t+="e"),t+=" rohkem"},loadingMore:function(){return"Laen tulemusi…"},maximumSelected:function(e){var n="Saad vaid "+e.maximum+" tulemus";return 1==e.maximum?n+="e":n+="t",n+=" valida"},noResults:function(){return"Tulemused puuduvad"},searching:function(){return"Otsin…"},removeAllItems:function(){return"Eemalda kõik esemed"}}}),e.define,e.require}();
--------------------------------------------------------------------------------
/staticfiles/admin/js/vendor/select2/i18n/eu.js:
--------------------------------------------------------------------------------
1 | /*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */
2 |
3 | !function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;e.define("select2/i18n/eu",[],function(){return{inputTooLong:function(e){var t=e.input.length-e.maximum,n="Idatzi ";return n+=1==t?"karaktere bat":t+" karaktere",n+=" gutxiago"},inputTooShort:function(e){var t=e.minimum-e.input.length,n="Idatzi ";return n+=1==t?"karaktere bat":t+" karaktere",n+=" gehiago"},loadingMore:function(){return"Emaitza gehiago kargatzen…"},maximumSelected:function(e){return 1===e.maximum?"Elementu bakarra hauta dezakezu":e.maximum+" elementu hauta ditzakezu soilik"},noResults:function(){return"Ez da bat datorrenik aurkitu"},searching:function(){return"Bilatzen…"},removeAllItems:function(){return"Kendu elementu guztiak"}}}),e.define,e.require}();
--------------------------------------------------------------------------------
/staticfiles/admin/js/vendor/select2/i18n/fa.js:
--------------------------------------------------------------------------------
1 | /*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */
2 |
3 | !function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var n=jQuery.fn.select2.amd;n.define("select2/i18n/fa",[],function(){return{errorLoading:function(){return"امکان بارگذاری نتایج وجود ندارد."},inputTooLong:function(n){return"لطفاً "+(n.input.length-n.maximum)+" کاراکتر را حذف نمایید"},inputTooShort:function(n){return"لطفاً تعداد "+(n.minimum-n.input.length)+" کاراکتر یا بیشتر وارد نمایید"},loadingMore:function(){return"در حال بارگذاری نتایج بیشتر..."},maximumSelected:function(n){return"شما تنها میتوانید "+n.maximum+" آیتم را انتخاب نمایید"},noResults:function(){return"هیچ نتیجهای یافت نشد"},searching:function(){return"در حال جستجو..."},removeAllItems:function(){return"همه موارد را حذف کنید"}}}),n.define,n.require}();
--------------------------------------------------------------------------------
/staticfiles/admin/js/vendor/select2/i18n/fi.js:
--------------------------------------------------------------------------------
1 | /*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */
2 |
3 | !function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var n=jQuery.fn.select2.amd;n.define("select2/i18n/fi",[],function(){return{errorLoading:function(){return"Tuloksia ei saatu ladattua."},inputTooLong:function(n){return"Ole hyvä ja anna "+(n.input.length-n.maximum)+" merkkiä vähemmän"},inputTooShort:function(n){return"Ole hyvä ja anna "+(n.minimum-n.input.length)+" merkkiä lisää"},loadingMore:function(){return"Ladataan lisää tuloksia…"},maximumSelected:function(n){return"Voit valita ainoastaan "+n.maximum+" kpl"},noResults:function(){return"Ei tuloksia"},searching:function(){return"Haetaan…"},removeAllItems:function(){return"Poista kaikki kohteet"}}}),n.define,n.require}();
--------------------------------------------------------------------------------
/staticfiles/admin/js/vendor/select2/i18n/fr.js:
--------------------------------------------------------------------------------
1 | /*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */
2 |
3 | !function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;e.define("select2/i18n/fr",[],function(){return{errorLoading:function(){return"Les résultats ne peuvent pas être chargés."},inputTooLong:function(e){var n=e.input.length-e.maximum;return"Supprimez "+n+" caractère"+(n>1?"s":"")},inputTooShort:function(e){var n=e.minimum-e.input.length;return"Saisissez au moins "+n+" caractère"+(n>1?"s":"")},loadingMore:function(){return"Chargement de résultats supplémentaires…"},maximumSelected:function(e){return"Vous pouvez seulement sélectionner "+e.maximum+" élément"+(e.maximum>1?"s":"")},noResults:function(){return"Aucun résultat trouvé"},searching:function(){return"Recherche en cours…"},removeAllItems:function(){return"Supprimer tous les éléments"}}}),e.define,e.require}();
--------------------------------------------------------------------------------
/staticfiles/admin/js/vendor/select2/i18n/gl.js:
--------------------------------------------------------------------------------
1 | /*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */
2 |
3 | !function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;e.define("select2/i18n/gl",[],function(){return{errorLoading:function(){return"Non foi posíbel cargar os resultados."},inputTooLong:function(e){var n=e.input.length-e.maximum;return 1===n?"Elimine un carácter":"Elimine "+n+" caracteres"},inputTooShort:function(e){var n=e.minimum-e.input.length;return 1===n?"Engada un carácter":"Engada "+n+" caracteres"},loadingMore:function(){return"Cargando máis resultados…"},maximumSelected:function(e){return 1===e.maximum?"Só pode seleccionar un elemento":"Só pode seleccionar "+e.maximum+" elementos"},noResults:function(){return"Non se atoparon resultados"},searching:function(){return"Buscando…"},removeAllItems:function(){return"Elimina todos os elementos"}}}),e.define,e.require}();
--------------------------------------------------------------------------------
/staticfiles/admin/js/vendor/select2/i18n/he.js:
--------------------------------------------------------------------------------
1 | /*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */
2 |
3 | !function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var n=jQuery.fn.select2.amd;n.define("select2/i18n/he",[],function(){return{errorLoading:function(){return"שגיאה בטעינת התוצאות"},inputTooLong:function(n){var e=n.input.length-n.maximum,r="נא למחוק ";return r+=1===e?"תו אחד":e+" תווים"},inputTooShort:function(n){var e=n.minimum-n.input.length,r="נא להכניס ";return r+=1===e?"תו אחד":e+" תווים",r+=" או יותר"},loadingMore:function(){return"טוען תוצאות נוספות…"},maximumSelected:function(n){var e="באפשרותך לבחור עד ";return 1===n.maximum?e+="פריט אחד":e+=n.maximum+" פריטים",e},noResults:function(){return"לא נמצאו תוצאות"},searching:function(){return"מחפש…"},removeAllItems:function(){return"הסר את כל הפריטים"}}}),n.define,n.require}();
--------------------------------------------------------------------------------
/staticfiles/admin/js/vendor/select2/i18n/hi.js:
--------------------------------------------------------------------------------
1 | /*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */
2 |
3 | !function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var n=jQuery.fn.select2.amd;n.define("select2/i18n/hi",[],function(){return{errorLoading:function(){return"परिणामों को लोड नहीं किया जा सका।"},inputTooLong:function(n){var e=n.input.length-n.maximum,r=e+" अक्षर को हटा दें";return e>1&&(r=e+" अक्षरों को हटा दें "),r},inputTooShort:function(n){return"कृपया "+(n.minimum-n.input.length)+" या अधिक अक्षर दर्ज करें"},loadingMore:function(){return"अधिक परिणाम लोड हो रहे है..."},maximumSelected:function(n){return"आप केवल "+n.maximum+" आइटम का चयन कर सकते हैं"},noResults:function(){return"कोई परिणाम नहीं मिला"},searching:function(){return"खोज रहा है..."},removeAllItems:function(){return"सभी वस्तुओं को हटा दें"}}}),n.define,n.require}();
--------------------------------------------------------------------------------
/staticfiles/admin/js/vendor/select2/i18n/hr.js:
--------------------------------------------------------------------------------
1 | /*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */
2 |
3 | !function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var n=jQuery.fn.select2.amd;n.define("select2/i18n/hr",[],function(){function n(n){var e=" "+n+" znak";return n%10<5&&n%10>0&&(n%100<5||n%100>19)?n%10>1&&(e+="a"):e+="ova",e}return{errorLoading:function(){return"Preuzimanje nije uspjelo."},inputTooLong:function(e){return"Unesite "+n(e.input.length-e.maximum)},inputTooShort:function(e){return"Unesite još "+n(e.minimum-e.input.length)},loadingMore:function(){return"Učitavanje rezultata…"},maximumSelected:function(n){return"Maksimalan broj odabranih stavki je "+n.maximum},noResults:function(){return"Nema rezultata"},searching:function(){return"Pretraga…"},removeAllItems:function(){return"Ukloni sve stavke"}}}),n.define,n.require}();
--------------------------------------------------------------------------------
/staticfiles/admin/js/vendor/select2/i18n/hsb.js:
--------------------------------------------------------------------------------
1 | /*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */
2 |
3 | !function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var n=jQuery.fn.select2.amd;n.define("select2/i18n/hsb",[],function(){var n=["znamješko","znamješce","znamješka","znamješkow"],e=["zapisk","zapiskaj","zapiski","zapiskow"],u=function(n,e){return 1===n?e[0]:2===n?e[1]:n>2&&n<=4?e[2]:n>=5?e[3]:void 0};return{errorLoading:function(){return"Wuslědki njedachu so začitać."},inputTooLong:function(e){var a=e.input.length-e.maximum;return"Prošu zhašej "+a+" "+u(a,n)},inputTooShort:function(e){var a=e.minimum-e.input.length;return"Prošu zapodaj znajmjeńša "+a+" "+u(a,n)},loadingMore:function(){return"Dalše wuslědki so začitaja…"},maximumSelected:function(n){return"Móžeš jenož "+n.maximum+" "+u(n.maximum,e)+"wubrać"},noResults:function(){return"Žane wuslědki namakane"},searching:function(){return"Pyta so…"},removeAllItems:function(){return"Remove all items"}}}),n.define,n.require}();
--------------------------------------------------------------------------------
/staticfiles/admin/js/vendor/select2/i18n/hu.js:
--------------------------------------------------------------------------------
1 | /*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */
2 |
3 | !function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;e.define("select2/i18n/hu",[],function(){return{errorLoading:function(){return"Az eredmények betöltése nem sikerült."},inputTooLong:function(e){return"Túl hosszú. "+(e.input.length-e.maximum)+" karakterrel több, mint kellene."},inputTooShort:function(e){return"Túl rövid. Még "+(e.minimum-e.input.length)+" karakter hiányzik."},loadingMore:function(){return"Töltés…"},maximumSelected:function(e){return"Csak "+e.maximum+" elemet lehet kiválasztani."},noResults:function(){return"Nincs találat."},searching:function(){return"Keresés…"},removeAllItems:function(){return"Távolítson el minden elemet"}}}),e.define,e.require}();
--------------------------------------------------------------------------------
/staticfiles/admin/js/vendor/select2/i18n/hy.js:
--------------------------------------------------------------------------------
1 | /*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */
2 |
3 | !function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var n=jQuery.fn.select2.amd;n.define("select2/i18n/hy",[],function(){return{errorLoading:function(){return"Արդյունքները հնարավոր չէ բեռնել։"},inputTooLong:function(n){return"Խնդրում ենք հեռացնել "+(n.input.length-n.maximum)+" նշան"},inputTooShort:function(n){return"Խնդրում ենք մուտքագրել "+(n.minimum-n.input.length)+" կամ ավել նշաններ"},loadingMore:function(){return"Բեռնվում են նոր արդյունքներ․․․"},maximumSelected:function(n){return"Դուք կարող եք ընտրել առավելագույնը "+n.maximum+" կետ"},noResults:function(){return"Արդյունքներ չեն գտնվել"},searching:function(){return"Որոնում․․․"},removeAllItems:function(){return"Հեռացնել բոլոր տարրերը"}}}),n.define,n.require}();
--------------------------------------------------------------------------------
/staticfiles/admin/js/vendor/select2/i18n/id.js:
--------------------------------------------------------------------------------
1 | /*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */
2 |
3 | !function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var n=jQuery.fn.select2.amd;n.define("select2/i18n/id",[],function(){return{errorLoading:function(){return"Data tidak boleh diambil."},inputTooLong:function(n){return"Hapuskan "+(n.input.length-n.maximum)+" huruf"},inputTooShort:function(n){return"Masukkan "+(n.minimum-n.input.length)+" huruf lagi"},loadingMore:function(){return"Mengambil data…"},maximumSelected:function(n){return"Anda hanya dapat memilih "+n.maximum+" pilihan"},noResults:function(){return"Tidak ada data yang sesuai"},searching:function(){return"Mencari…"},removeAllItems:function(){return"Hapus semua item"}}}),n.define,n.require}();
--------------------------------------------------------------------------------
/staticfiles/admin/js/vendor/select2/i18n/is.js:
--------------------------------------------------------------------------------
1 | /*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */
2 |
3 | !function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var n=jQuery.fn.select2.amd;n.define("select2/i18n/is",[],function(){return{inputTooLong:function(n){var t=n.input.length-n.maximum,e="Vinsamlegast styttið texta um "+t+" staf";return t<=1?e:e+"i"},inputTooShort:function(n){var t=n.minimum-n.input.length,e="Vinsamlegast skrifið "+t+" staf";return t>1&&(e+="i"),e+=" í viðbót"},loadingMore:function(){return"Sæki fleiri niðurstöður…"},maximumSelected:function(n){return"Þú getur aðeins valið "+n.maximum+" atriði"},noResults:function(){return"Ekkert fannst"},searching:function(){return"Leita…"},removeAllItems:function(){return"Fjarlægðu öll atriði"}}}),n.define,n.require}();
--------------------------------------------------------------------------------
/staticfiles/admin/js/vendor/select2/i18n/it.js:
--------------------------------------------------------------------------------
1 | /*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */
2 |
3 | !function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;e.define("select2/i18n/it",[],function(){return{errorLoading:function(){return"I risultati non possono essere caricati."},inputTooLong:function(e){var n=e.input.length-e.maximum,t="Per favore cancella "+n+" caratter";return t+=1!==n?"i":"e"},inputTooShort:function(e){return"Per favore inserisci "+(e.minimum-e.input.length)+" o più caratteri"},loadingMore:function(){return"Caricando più risultati…"},maximumSelected:function(e){var n="Puoi selezionare solo "+e.maximum+" element";return 1!==e.maximum?n+="i":n+="o",n},noResults:function(){return"Nessun risultato trovato"},searching:function(){return"Sto cercando…"},removeAllItems:function(){return"Rimuovi tutti gli oggetti"}}}),e.define,e.require}();
--------------------------------------------------------------------------------
/staticfiles/admin/js/vendor/select2/i18n/ja.js:
--------------------------------------------------------------------------------
1 | /*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */
2 |
3 | !function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var n=jQuery.fn.select2.amd;n.define("select2/i18n/ja",[],function(){return{errorLoading:function(){return"結果が読み込まれませんでした"},inputTooLong:function(n){return n.input.length-n.maximum+" 文字を削除してください"},inputTooShort:function(n){return"少なくとも "+(n.minimum-n.input.length)+" 文字を入力してください"},loadingMore:function(){return"読み込み中…"},maximumSelected:function(n){return n.maximum+" 件しか選択できません"},noResults:function(){return"対象が見つかりません"},searching:function(){return"検索しています…"},removeAllItems:function(){return"すべてのアイテムを削除"}}}),n.define,n.require}();
--------------------------------------------------------------------------------
/staticfiles/admin/js/vendor/select2/i18n/ka.js:
--------------------------------------------------------------------------------
1 | /*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */
2 |
3 | !function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var n=jQuery.fn.select2.amd;n.define("select2/i18n/ka",[],function(){return{errorLoading:function(){return"მონაცემების ჩატვირთვა შეუძლებელია."},inputTooLong:function(n){return"გთხოვთ აკრიფეთ "+(n.input.length-n.maximum)+" სიმბოლოთი ნაკლები"},inputTooShort:function(n){return"გთხოვთ აკრიფეთ "+(n.minimum-n.input.length)+" სიმბოლო ან მეტი"},loadingMore:function(){return"მონაცემების ჩატვირთვა…"},maximumSelected:function(n){return"თქვენ შეგიძლიათ აირჩიოთ არაუმეტეს "+n.maximum+" ელემენტი"},noResults:function(){return"რეზულტატი არ მოიძებნა"},searching:function(){return"ძიება…"},removeAllItems:function(){return"ამოიღე ყველა ელემენტი"}}}),n.define,n.require}();
--------------------------------------------------------------------------------
/staticfiles/admin/js/vendor/select2/i18n/km.js:
--------------------------------------------------------------------------------
1 | /*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */
2 |
3 | !function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var n=jQuery.fn.select2.amd;n.define("select2/i18n/km",[],function(){return{errorLoading:function(){return"មិនអាចទាញយកទិន្នន័យ"},inputTooLong:function(n){return"សូមលុបចេញ "+(n.input.length-n.maximum)+" អក្សរ"},inputTooShort:function(n){return"សូមបញ្ចូល"+(n.minimum-n.input.length)+" អក្សរ រឺ ច្រើនជាងនេះ"},loadingMore:function(){return"កំពុងទាញយកទិន្នន័យបន្ថែម..."},maximumSelected:function(n){return"អ្នកអាចជ្រើសរើសបានតែ "+n.maximum+" ជម្រើសប៉ុណ្ណោះ"},noResults:function(){return"មិនមានលទ្ធផល"},searching:function(){return"កំពុងស្វែងរក..."},removeAllItems:function(){return"លុបធាតុទាំងអស់"}}}),n.define,n.require}();
--------------------------------------------------------------------------------
/staticfiles/admin/js/vendor/select2/i18n/ko.js:
--------------------------------------------------------------------------------
1 | /*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */
2 |
3 | !function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var n=jQuery.fn.select2.amd;n.define("select2/i18n/ko",[],function(){return{errorLoading:function(){return"결과를 불러올 수 없습니다."},inputTooLong:function(n){return"너무 깁니다. "+(n.input.length-n.maximum)+" 글자 지워주세요."},inputTooShort:function(n){return"너무 짧습니다. "+(n.minimum-n.input.length)+" 글자 더 입력해주세요."},loadingMore:function(){return"불러오는 중…"},maximumSelected:function(n){return"최대 "+n.maximum+"개까지만 선택 가능합니다."},noResults:function(){return"결과가 없습니다."},searching:function(){return"검색 중…"},removeAllItems:function(){return"모든 항목 삭제"}}}),n.define,n.require}();
--------------------------------------------------------------------------------
/staticfiles/admin/js/vendor/select2/i18n/lt.js:
--------------------------------------------------------------------------------
1 | /*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */
2 |
3 | !function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var n=jQuery.fn.select2.amd;n.define("select2/i18n/lt",[],function(){function n(n,e,i,t){return n%10==1&&(n%100<11||n%100>19)?e:n%10>=2&&n%10<=9&&(n%100<11||n%100>19)?i:t}return{inputTooLong:function(e){var i=e.input.length-e.maximum,t="Pašalinkite "+i+" simbol";return t+=n(i,"į","ius","ių")},inputTooShort:function(e){var i=e.minimum-e.input.length,t="Įrašykite dar "+i+" simbol";return t+=n(i,"į","ius","ių")},loadingMore:function(){return"Kraunama daugiau rezultatų…"},maximumSelected:function(e){var i="Jūs galite pasirinkti tik "+e.maximum+" element";return i+=n(e.maximum,"ą","us","ų")},noResults:function(){return"Atitikmenų nerasta"},searching:function(){return"Ieškoma…"},removeAllItems:function(){return"Pašalinti visus elementus"}}}),n.define,n.require}();
--------------------------------------------------------------------------------
/staticfiles/admin/js/vendor/select2/i18n/lv.js:
--------------------------------------------------------------------------------
1 | /*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */
2 |
3 | !function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;e.define("select2/i18n/lv",[],function(){function e(e,n,u,i){return 11===e?n:e%10==1?u:i}return{inputTooLong:function(n){var u=n.input.length-n.maximum,i="Lūdzu ievadiet par "+u;return(i+=" simbol"+e(u,"iem","u","iem"))+" mazāk"},inputTooShort:function(n){var u=n.minimum-n.input.length,i="Lūdzu ievadiet vēl "+u;return i+=" simbol"+e(u,"us","u","us")},loadingMore:function(){return"Datu ielāde…"},maximumSelected:function(n){var u="Jūs varat izvēlēties ne vairāk kā "+n.maximum;return u+=" element"+e(n.maximum,"us","u","us")},noResults:function(){return"Sakritību nav"},searching:function(){return"Meklēšana…"},removeAllItems:function(){return"Noņemt visus vienumus"}}}),e.define,e.require}();
--------------------------------------------------------------------------------
/staticfiles/admin/js/vendor/select2/i18n/mk.js:
--------------------------------------------------------------------------------
1 | /*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */
2 |
3 | !function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var n=jQuery.fn.select2.amd;n.define("select2/i18n/mk",[],function(){return{inputTooLong:function(n){var e=(n.input.length,n.maximum,"Ве молиме внесете "+n.maximum+" помалку карактер");return 1!==n.maximum&&(e+="и"),e},inputTooShort:function(n){var e=(n.minimum,n.input.length,"Ве молиме внесете уште "+n.maximum+" карактер");return 1!==n.maximum&&(e+="и"),e},loadingMore:function(){return"Вчитување резултати…"},maximumSelected:function(n){var e="Можете да изберете само "+n.maximum+" ставк";return 1===n.maximum?e+="а":e+="и",e},noResults:function(){return"Нема пронајдено совпаѓања"},searching:function(){return"Пребарување…"},removeAllItems:function(){return"Отстрани ги сите предмети"}}}),n.define,n.require}();
--------------------------------------------------------------------------------
/staticfiles/admin/js/vendor/select2/i18n/ms.js:
--------------------------------------------------------------------------------
1 | /*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */
2 |
3 | !function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var n=jQuery.fn.select2.amd;n.define("select2/i18n/ms",[],function(){return{errorLoading:function(){return"Keputusan tidak berjaya dimuatkan."},inputTooLong:function(n){return"Sila hapuskan "+(n.input.length-n.maximum)+" aksara"},inputTooShort:function(n){return"Sila masukkan "+(n.minimum-n.input.length)+" atau lebih aksara"},loadingMore:function(){return"Sedang memuatkan keputusan…"},maximumSelected:function(n){return"Anda hanya boleh memilih "+n.maximum+" pilihan"},noResults:function(){return"Tiada padanan yang ditemui"},searching:function(){return"Mencari…"},removeAllItems:function(){return"Keluarkan semua item"}}}),n.define,n.require}();
--------------------------------------------------------------------------------
/staticfiles/admin/js/vendor/select2/i18n/nb.js:
--------------------------------------------------------------------------------
1 | /*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */
2 |
3 | !function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;e.define("select2/i18n/nb",[],function(){return{errorLoading:function(){return"Kunne ikke hente resultater."},inputTooLong:function(e){return"Vennligst fjern "+(e.input.length-e.maximum)+" tegn"},inputTooShort:function(e){return"Vennligst skriv inn "+(e.minimum-e.input.length)+" tegn til"},loadingMore:function(){return"Laster flere resultater…"},maximumSelected:function(e){return"Du kan velge maks "+e.maximum+" elementer"},noResults:function(){return"Ingen treff"},searching:function(){return"Søker…"},removeAllItems:function(){return"Fjern alle elementer"}}}),e.define,e.require}();
--------------------------------------------------------------------------------
/staticfiles/admin/js/vendor/select2/i18n/ne.js:
--------------------------------------------------------------------------------
1 | /*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */
2 |
3 | !function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var n=jQuery.fn.select2.amd;n.define("select2/i18n/ne",[],function(){return{errorLoading:function(){return"नतिजाहरु देखाउन सकिएन।"},inputTooLong:function(n){var e=n.input.length-n.maximum,u="कृपया "+e+" अक्षर मेटाउनुहोस्।";return 1!=e&&(u+="कृपया "+e+" अक्षरहरु मेटाउनुहोस्।"),u},inputTooShort:function(n){return"कृपया बाँकी रहेका "+(n.minimum-n.input.length)+" वा अरु धेरै अक्षरहरु भर्नुहोस्।"},loadingMore:function(){return"अरु नतिजाहरु भरिँदैछन् …"},maximumSelected:function(n){var e="तँपाई "+n.maximum+" वस्तु मात्र छान्न पाउँनुहुन्छ।";return 1!=n.maximum&&(e="तँपाई "+n.maximum+" वस्तुहरु मात्र छान्न पाउँनुहुन्छ।"),e},noResults:function(){return"कुनै पनि नतिजा भेटिएन।"},searching:function(){return"खोजि हुँदैछ…"}}}),n.define,n.require}();
--------------------------------------------------------------------------------
/staticfiles/admin/js/vendor/select2/i18n/nl.js:
--------------------------------------------------------------------------------
1 | /*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */
2 |
3 | !function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;e.define("select2/i18n/nl",[],function(){return{errorLoading:function(){return"De resultaten konden niet worden geladen."},inputTooLong:function(e){return"Gelieve "+(e.input.length-e.maximum)+" karakters te verwijderen"},inputTooShort:function(e){return"Gelieve "+(e.minimum-e.input.length)+" of meer karakters in te voeren"},loadingMore:function(){return"Meer resultaten laden…"},maximumSelected:function(e){var n=1==e.maximum?"kan":"kunnen",r="Er "+n+" maar "+e.maximum+" item";return 1!=e.maximum&&(r+="s"),r+=" worden geselecteerd"},noResults:function(){return"Geen resultaten gevonden…"},searching:function(){return"Zoeken…"},removeAllItems:function(){return"Verwijder alle items"}}}),e.define,e.require}();
--------------------------------------------------------------------------------
/staticfiles/admin/js/vendor/select2/i18n/pl.js:
--------------------------------------------------------------------------------
1 | /*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */
2 |
3 | !function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var n=jQuery.fn.select2.amd;n.define("select2/i18n/pl",[],function(){var n=["znak","znaki","znaków"],e=["element","elementy","elementów"],r=function(n,e){return 1===n?e[0]:n>1&&n<=4?e[1]:n>=5?e[2]:void 0};return{errorLoading:function(){return"Nie można załadować wyników."},inputTooLong:function(e){var t=e.input.length-e.maximum;return"Usuń "+t+" "+r(t,n)},inputTooShort:function(e){var t=e.minimum-e.input.length;return"Podaj przynajmniej "+t+" "+r(t,n)},loadingMore:function(){return"Trwa ładowanie…"},maximumSelected:function(n){return"Możesz zaznaczyć tylko "+n.maximum+" "+r(n.maximum,e)},noResults:function(){return"Brak wyników"},searching:function(){return"Trwa wyszukiwanie…"},removeAllItems:function(){return"Usuń wszystkie przedmioty"}}}),n.define,n.require}();
--------------------------------------------------------------------------------
/staticfiles/admin/js/vendor/select2/i18n/ps.js:
--------------------------------------------------------------------------------
1 | /*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */
2 |
3 | !function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var n=jQuery.fn.select2.amd;n.define("select2/i18n/ps",[],function(){return{errorLoading:function(){return"پايلي نه سي ترلاسه کېدای"},inputTooLong:function(n){var e=n.input.length-n.maximum,r="د مهربانۍ لمخي "+e+" توری ړنګ کړئ";return 1!=e&&(r=r.replace("توری","توري")),r},inputTooShort:function(n){return"لږ تر لږه "+(n.minimum-n.input.length)+" يا ډېر توري وليکئ"},loadingMore:function(){return"نوري پايلي ترلاسه کيږي..."},maximumSelected:function(n){var e="تاسو يوازي "+n.maximum+" قلم په نښه کولای سی";return 1!=n.maximum&&(e=e.replace("قلم","قلمونه")),e},noResults:function(){return"پايلي و نه موندل سوې"},searching:function(){return"لټول کيږي..."},removeAllItems:function(){return"ټول توکي لرې کړئ"}}}),n.define,n.require}();
--------------------------------------------------------------------------------
/staticfiles/admin/js/vendor/select2/i18n/pt-BR.js:
--------------------------------------------------------------------------------
1 | /*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */
2 |
3 | !function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;e.define("select2/i18n/pt-BR",[],function(){return{errorLoading:function(){return"Os resultados não puderam ser carregados."},inputTooLong:function(e){var n=e.input.length-e.maximum,r="Apague "+n+" caracter";return 1!=n&&(r+="es"),r},inputTooShort:function(e){return"Digite "+(e.minimum-e.input.length)+" ou mais caracteres"},loadingMore:function(){return"Carregando mais resultados…"},maximumSelected:function(e){var n="Você só pode selecionar "+e.maximum+" ite";return 1==e.maximum?n+="m":n+="ns",n},noResults:function(){return"Nenhum resultado encontrado"},searching:function(){return"Buscando…"},removeAllItems:function(){return"Remover todos os itens"}}}),e.define,e.require}();
--------------------------------------------------------------------------------
/staticfiles/admin/js/vendor/select2/i18n/pt.js:
--------------------------------------------------------------------------------
1 | /*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */
2 |
3 | !function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;e.define("select2/i18n/pt",[],function(){return{errorLoading:function(){return"Os resultados não puderam ser carregados."},inputTooLong:function(e){var r=e.input.length-e.maximum,n="Por favor apague "+r+" ";return n+=1!=r?"caracteres":"caractere"},inputTooShort:function(e){return"Introduza "+(e.minimum-e.input.length)+" ou mais caracteres"},loadingMore:function(){return"A carregar mais resultados…"},maximumSelected:function(e){var r="Apenas pode seleccionar "+e.maximum+" ";return r+=1!=e.maximum?"itens":"item"},noResults:function(){return"Sem resultados"},searching:function(){return"A procurar…"},removeAllItems:function(){return"Remover todos os itens"}}}),e.define,e.require}();
--------------------------------------------------------------------------------
/staticfiles/admin/js/vendor/select2/i18n/ro.js:
--------------------------------------------------------------------------------
1 | /*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */
2 |
3 | !function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;e.define("select2/i18n/ro",[],function(){return{errorLoading:function(){return"Rezultatele nu au putut fi incărcate."},inputTooLong:function(e){var t=e.input.length-e.maximum,n="Vă rugăm să ștergeți"+t+" caracter";return 1!==t&&(n+="e"),n},inputTooShort:function(e){return"Vă rugăm să introduceți "+(e.minimum-e.input.length)+" sau mai multe caractere"},loadingMore:function(){return"Se încarcă mai multe rezultate…"},maximumSelected:function(e){var t="Aveți voie să selectați cel mult "+e.maximum;return t+=" element",1!==e.maximum&&(t+="e"),t},noResults:function(){return"Nu au fost găsite rezultate"},searching:function(){return"Căutare…"},removeAllItems:function(){return"Eliminați toate elementele"}}}),e.define,e.require}();
--------------------------------------------------------------------------------
/staticfiles/admin/js/vendor/select2/i18n/ru.js:
--------------------------------------------------------------------------------
1 | /*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */
2 |
3 | !function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var n=jQuery.fn.select2.amd;n.define("select2/i18n/ru",[],function(){function n(n,e,r,u){return n%10<5&&n%10>0&&n%100<5||n%100>20?n%10>1?r:e:u}return{errorLoading:function(){return"Невозможно загрузить результаты"},inputTooLong:function(e){var r=e.input.length-e.maximum,u="Пожалуйста, введите на "+r+" символ";return u+=n(r,"","a","ов"),u+=" меньше"},inputTooShort:function(e){var r=e.minimum-e.input.length,u="Пожалуйста, введите ещё хотя бы "+r+" символ";return u+=n(r,"","a","ов")},loadingMore:function(){return"Загрузка данных…"},maximumSelected:function(e){var r="Вы можете выбрать не более "+e.maximum+" элемент";return r+=n(e.maximum,"","a","ов")},noResults:function(){return"Совпадений не найдено"},searching:function(){return"Поиск…"},removeAllItems:function(){return"Удалить все элементы"}}}),n.define,n.require}();
--------------------------------------------------------------------------------
/staticfiles/admin/js/vendor/select2/i18n/sk.js:
--------------------------------------------------------------------------------
1 | /*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */
2 |
3 | !function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;e.define("select2/i18n/sk",[],function(){var e={2:function(e){return e?"dva":"dve"},3:function(){return"tri"},4:function(){return"štyri"}};return{errorLoading:function(){return"Výsledky sa nepodarilo načítať."},inputTooLong:function(n){var t=n.input.length-n.maximum;return 1==t?"Prosím, zadajte o jeden znak menej":t>=2&&t<=4?"Prosím, zadajte o "+e[t](!0)+" znaky menej":"Prosím, zadajte o "+t+" znakov menej"},inputTooShort:function(n){var t=n.minimum-n.input.length;return 1==t?"Prosím, zadajte ešte jeden znak":t<=4?"Prosím, zadajte ešte ďalšie "+e[t](!0)+" znaky":"Prosím, zadajte ešte ďalších "+t+" znakov"},loadingMore:function(){return"Načítanie ďalších výsledkov…"},maximumSelected:function(n){return 1==n.maximum?"Môžete zvoliť len jednu položku":n.maximum>=2&&n.maximum<=4?"Môžete zvoliť najviac "+e[n.maximum](!1)+" položky":"Môžete zvoliť najviac "+n.maximum+" položiek"},noResults:function(){return"Nenašli sa žiadne položky"},searching:function(){return"Vyhľadávanie…"},removeAllItems:function(){return"Odstráňte všetky položky"}}}),e.define,e.require}();
--------------------------------------------------------------------------------
/staticfiles/admin/js/vendor/select2/i18n/sl.js:
--------------------------------------------------------------------------------
1 | /*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */
2 |
3 | !function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;e.define("select2/i18n/sl",[],function(){return{errorLoading:function(){return"Zadetkov iskanja ni bilo mogoče naložiti."},inputTooLong:function(e){var n=e.input.length-e.maximum,t="Prosim zbrišite "+n+" znak";return 2==n?t+="a":1!=n&&(t+="e"),t},inputTooShort:function(e){var n=e.minimum-e.input.length,t="Prosim vpišite še "+n+" znak";return 2==n?t+="a":1!=n&&(t+="e"),t},loadingMore:function(){return"Nalagam več zadetkov…"},maximumSelected:function(e){var n="Označite lahko največ "+e.maximum+" predmet";return 2==e.maximum?n+="a":1!=e.maximum&&(n+="e"),n},noResults:function(){return"Ni zadetkov."},searching:function(){return"Iščem…"},removeAllItems:function(){return"Odstranite vse elemente"}}}),e.define,e.require}();
--------------------------------------------------------------------------------
/staticfiles/admin/js/vendor/select2/i18n/sq.js:
--------------------------------------------------------------------------------
1 | /*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */
2 |
3 | !function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;e.define("select2/i18n/sq",[],function(){return{errorLoading:function(){return"Rezultatet nuk mund të ngarkoheshin."},inputTooLong:function(e){var n=e.input.length-e.maximum,t="Të lutem fshi "+n+" karakter";return 1!=n&&(t+="e"),t},inputTooShort:function(e){return"Të lutem shkruaj "+(e.minimum-e.input.length)+" ose më shumë karaktere"},loadingMore:function(){return"Duke ngarkuar më shumë rezultate…"},maximumSelected:function(e){var n="Mund të zgjedhësh vetëm "+e.maximum+" element";return 1!=e.maximum&&(n+="e"),n},noResults:function(){return"Nuk u gjet asnjë rezultat"},searching:function(){return"Duke kërkuar…"},removeAllItems:function(){return"Hiq të gjitha sendet"}}}),e.define,e.require}();
--------------------------------------------------------------------------------
/staticfiles/admin/js/vendor/select2/i18n/sr-Cyrl.js:
--------------------------------------------------------------------------------
1 | /*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */
2 |
3 | !function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var n=jQuery.fn.select2.amd;n.define("select2/i18n/sr-Cyrl",[],function(){function n(n,e,r,u){return n%10==1&&n%100!=11?e:n%10>=2&&n%10<=4&&(n%100<12||n%100>14)?r:u}return{errorLoading:function(){return"Преузимање није успело."},inputTooLong:function(e){var r=e.input.length-e.maximum,u="Обришите "+r+" симбол";return u+=n(r,"","а","а")},inputTooShort:function(e){var r=e.minimum-e.input.length,u="Укуцајте бар још "+r+" симбол";return u+=n(r,"","а","а")},loadingMore:function(){return"Преузимање још резултата…"},maximumSelected:function(e){var r="Можете изабрати само "+e.maximum+" ставк";return r+=n(e.maximum,"у","е","и")},noResults:function(){return"Ништа није пронађено"},searching:function(){return"Претрага…"},removeAllItems:function(){return"Уклоните све ставке"}}}),n.define,n.require}();
--------------------------------------------------------------------------------
/staticfiles/admin/js/vendor/select2/i18n/sr.js:
--------------------------------------------------------------------------------
1 | /*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */
2 |
3 | !function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var n=jQuery.fn.select2.amd;n.define("select2/i18n/sr",[],function(){function n(n,e,r,t){return n%10==1&&n%100!=11?e:n%10>=2&&n%10<=4&&(n%100<12||n%100>14)?r:t}return{errorLoading:function(){return"Preuzimanje nije uspelo."},inputTooLong:function(e){var r=e.input.length-e.maximum,t="Obrišite "+r+" simbol";return t+=n(r,"","a","a")},inputTooShort:function(e){var r=e.minimum-e.input.length,t="Ukucajte bar još "+r+" simbol";return t+=n(r,"","a","a")},loadingMore:function(){return"Preuzimanje još rezultata…"},maximumSelected:function(e){var r="Možete izabrati samo "+e.maximum+" stavk";return r+=n(e.maximum,"u","e","i")},noResults:function(){return"Ništa nije pronađeno"},searching:function(){return"Pretraga…"},removeAllItems:function(){return"Уклоните све ставке"}}}),n.define,n.require}();
--------------------------------------------------------------------------------
/staticfiles/admin/js/vendor/select2/i18n/sv.js:
--------------------------------------------------------------------------------
1 | /*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */
2 |
3 | !function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var n=jQuery.fn.select2.amd;n.define("select2/i18n/sv",[],function(){return{errorLoading:function(){return"Resultat kunde inte laddas."},inputTooLong:function(n){return"Vänligen sudda ut "+(n.input.length-n.maximum)+" tecken"},inputTooShort:function(n){return"Vänligen skriv in "+(n.minimum-n.input.length)+" eller fler tecken"},loadingMore:function(){return"Laddar fler resultat…"},maximumSelected:function(n){return"Du kan max välja "+n.maximum+" element"},noResults:function(){return"Inga träffar"},searching:function(){return"Söker…"},removeAllItems:function(){return"Ta bort alla objekt"}}}),n.define,n.require}();
--------------------------------------------------------------------------------
/staticfiles/admin/js/vendor/select2/i18n/th.js:
--------------------------------------------------------------------------------
1 | /*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */
2 |
3 | !function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var n=jQuery.fn.select2.amd;n.define("select2/i18n/th",[],function(){return{errorLoading:function(){return"ไม่สามารถค้นข้อมูลได้"},inputTooLong:function(n){return"โปรดลบออก "+(n.input.length-n.maximum)+" ตัวอักษร"},inputTooShort:function(n){return"โปรดพิมพ์เพิ่มอีก "+(n.minimum-n.input.length)+" ตัวอักษร"},loadingMore:function(){return"กำลังค้นข้อมูลเพิ่ม…"},maximumSelected:function(n){return"คุณสามารถเลือกได้ไม่เกิน "+n.maximum+" รายการ"},noResults:function(){return"ไม่พบข้อมูล"},searching:function(){return"กำลังค้นข้อมูล…"},removeAllItems:function(){return"ลบรายการทั้งหมด"}}}),n.define,n.require}();
--------------------------------------------------------------------------------
/staticfiles/admin/js/vendor/select2/i18n/tk.js:
--------------------------------------------------------------------------------
1 | /*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */
2 |
3 | !function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;e.define("select2/i18n/tk",[],function(){return{errorLoading:function(){return"Netije ýüklenmedi."},inputTooLong:function(e){return e.input.length-e.maximum+" harp bozuň."},inputTooShort:function(e){return"Ýene-de iň az "+(e.minimum-e.input.length)+" harp ýazyň."},loadingMore:function(){return"Köpräk netije görkezilýär…"},maximumSelected:function(e){return"Diňe "+e.maximum+" sanysyny saýlaň."},noResults:function(){return"Netije tapylmady."},searching:function(){return"Gözlenýär…"},removeAllItems:function(){return"Remove all items"}}}),e.define,e.require}();
--------------------------------------------------------------------------------
/staticfiles/admin/js/vendor/select2/i18n/tr.js:
--------------------------------------------------------------------------------
1 | /*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */
2 |
3 | !function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var n=jQuery.fn.select2.amd;n.define("select2/i18n/tr",[],function(){return{errorLoading:function(){return"Sonuç yüklenemedi"},inputTooLong:function(n){return n.input.length-n.maximum+" karakter daha girmelisiniz"},inputTooShort:function(n){return"En az "+(n.minimum-n.input.length)+" karakter daha girmelisiniz"},loadingMore:function(){return"Daha fazla…"},maximumSelected:function(n){return"Sadece "+n.maximum+" seçim yapabilirsiniz"},noResults:function(){return"Sonuç bulunamadı"},searching:function(){return"Aranıyor…"},removeAllItems:function(){return"Tüm öğeleri kaldır"}}}),n.define,n.require}();
--------------------------------------------------------------------------------
/staticfiles/admin/js/vendor/select2/i18n/uk.js:
--------------------------------------------------------------------------------
1 | /*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */
2 |
3 | !function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var n=jQuery.fn.select2.amd;n.define("select2/i18n/uk",[],function(){function n(n,e,u,r){return n%100>10&&n%100<15?r:n%10==1?e:n%10>1&&n%10<5?u:r}return{errorLoading:function(){return"Неможливо завантажити результати"},inputTooLong:function(e){return"Будь ласка, видаліть "+(e.input.length-e.maximum)+" "+n(e.maximum,"літеру","літери","літер")},inputTooShort:function(n){return"Будь ласка, введіть "+(n.minimum-n.input.length)+" або більше літер"},loadingMore:function(){return"Завантаження інших результатів…"},maximumSelected:function(e){return"Ви можете вибрати лише "+e.maximum+" "+n(e.maximum,"пункт","пункти","пунктів")},noResults:function(){return"Нічого не знайдено"},searching:function(){return"Пошук…"},removeAllItems:function(){return"Видалити всі елементи"}}}),n.define,n.require}();
--------------------------------------------------------------------------------
/staticfiles/admin/js/vendor/select2/i18n/vi.js:
--------------------------------------------------------------------------------
1 | /*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */
2 |
3 | !function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var n=jQuery.fn.select2.amd;n.define("select2/i18n/vi",[],function(){return{inputTooLong:function(n){return"Vui lòng xóa bớt "+(n.input.length-n.maximum)+" ký tự"},inputTooShort:function(n){return"Vui lòng nhập thêm từ "+(n.minimum-n.input.length)+" ký tự trở lên"},loadingMore:function(){return"Đang lấy thêm kết quả…"},maximumSelected:function(n){return"Chỉ có thể chọn được "+n.maximum+" lựa chọn"},noResults:function(){return"Không tìm thấy kết quả"},searching:function(){return"Đang tìm…"},removeAllItems:function(){return"Xóa tất cả các mục"}}}),n.define,n.require}();
--------------------------------------------------------------------------------
/staticfiles/admin/js/vendor/select2/i18n/zh-CN.js:
--------------------------------------------------------------------------------
1 | /*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */
2 |
3 | !function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var n=jQuery.fn.select2.amd;n.define("select2/i18n/zh-CN",[],function(){return{errorLoading:function(){return"无法载入结果。"},inputTooLong:function(n){return"请删除"+(n.input.length-n.maximum)+"个字符"},inputTooShort:function(n){return"请再输入至少"+(n.minimum-n.input.length)+"个字符"},loadingMore:function(){return"载入更多结果…"},maximumSelected:function(n){return"最多只能选择"+n.maximum+"个项目"},noResults:function(){return"未找到结果"},searching:function(){return"搜索中…"},removeAllItems:function(){return"删除所有项目"}}}),n.define,n.require}();
--------------------------------------------------------------------------------
/staticfiles/admin/js/vendor/select2/i18n/zh-TW.js:
--------------------------------------------------------------------------------
1 | /*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */
2 |
3 | !function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var n=jQuery.fn.select2.amd;n.define("select2/i18n/zh-TW",[],function(){return{inputTooLong:function(n){return"請刪掉"+(n.input.length-n.maximum)+"個字元"},inputTooShort:function(n){return"請再輸入"+(n.minimum-n.input.length)+"個字元"},loadingMore:function(){return"載入中…"},maximumSelected:function(n){return"你只能選擇最多"+n.maximum+"項"},noResults:function(){return"沒有找到相符的項目"},searching:function(){return"搜尋中…"},removeAllItems:function(){return"刪除所有項目"}}}),n.define,n.require}();
--------------------------------------------------------------------------------
/staticfiles/admin/js/vendor/xregexp/LICENSE.txt:
--------------------------------------------------------------------------------
1 | The MIT License
2 |
3 | Copyright (c) 2007-2017 Steven Levithan
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in
13 | all copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21 | THE SOFTWARE.
22 |
--------------------------------------------------------------------------------
/staticfiles/build/asset-manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "files": {
3 | "main.css": "/static/css/main.ecc2cd5e.css",
4 | "main.js": "/static/js/main.3ff53e20.js",
5 | "static/js/787.5ad96c4b.chunk.js": "/static/js/787.5ad96c4b.chunk.js",
6 | "index.html": "/index.html",
7 | "main.ecc2cd5e.css.map": "/static/css/main.ecc2cd5e.css.map",
8 | "main.3ff53e20.js.map": "/static/js/main.3ff53e20.js.map",
9 | "787.5ad96c4b.chunk.js.map": "/static/js/787.5ad96c4b.chunk.js.map"
10 | },
11 | "entrypoints": [
12 | "static/css/main.ecc2cd5e.css",
13 | "static/js/main.3ff53e20.js"
14 | ]
15 | }
--------------------------------------------------------------------------------
/staticfiles/build/favicon-16x16.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bluesky-0412/API_Django/2fe694997713372b791572a78e86e2460706f303/staticfiles/build/favicon-16x16.png
--------------------------------------------------------------------------------
/staticfiles/build/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bluesky-0412/API_Django/2fe694997713372b791572a78e86e2460706f303/staticfiles/build/favicon.ico
--------------------------------------------------------------------------------
/staticfiles/build/index.html:
--------------------------------------------------------------------------------
1 | Capture The Moment
--------------------------------------------------------------------------------
/staticfiles/build/logo192.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bluesky-0412/API_Django/2fe694997713372b791572a78e86e2460706f303/staticfiles/build/logo192.png
--------------------------------------------------------------------------------
/staticfiles/build/logo512.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bluesky-0412/API_Django/2fe694997713372b791572a78e86e2460706f303/staticfiles/build/logo512.png
--------------------------------------------------------------------------------
/staticfiles/build/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "short_name": "React App",
3 | "name": "Create React App Sample",
4 | "icons": [
5 | {
6 | "src": "favicon.ico",
7 | "sizes": "64x64 32x32 24x24 16x16",
8 | "type": "image/x-icon"
9 | },
10 | {
11 | "src": "logo192.png",
12 | "type": "image/png",
13 | "sizes": "192x192"
14 | },
15 | {
16 | "src": "logo512.png",
17 | "type": "image/png",
18 | "sizes": "512x512"
19 | }
20 | ],
21 | "start_url": ".",
22 | "display": "standalone",
23 | "theme_color": "#000000",
24 | "background_color": "#ffffff"
25 | }
26 |
--------------------------------------------------------------------------------
/staticfiles/build/robots.txt:
--------------------------------------------------------------------------------
1 | # https://www.robotstxt.org/robotstxt.html
2 | User-agent: *
3 | Disallow:
4 |
--------------------------------------------------------------------------------
/staticfiles/build/static/js/main.3ff53e20.js.LICENSE.txt:
--------------------------------------------------------------------------------
1 | /*
2 | object-assign
3 | (c) Sindre Sorhus
4 | @license MIT
5 | */
6 |
7 | /*!
8 | Copyright (c) 2018 Jed Watson.
9 | Licensed under the MIT License (MIT), see
10 | http://jedwatson.github.io/classnames
11 | */
12 |
13 | /*! *****************************************************************************
14 | Copyright (c) Microsoft Corporation. All rights reserved.
15 | Licensed under the Apache License, Version 2.0 (the "License"); you may not use
16 | this file except in compliance with the License. You may obtain a copy of the
17 | License at http://www.apache.org/licenses/LICENSE-2.0
18 |
19 | THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
20 | KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED
21 | WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE,
22 | MERCHANTABLITY OR NON-INFRINGEMENT.
23 |
24 | See the Apache Version 2.0 License for specific language governing permissions
25 | and limitations under the License.
26 | ***************************************************************************** */
27 |
28 | /** @license React v0.20.2
29 | * scheduler.production.min.js
30 | *
31 | * Copyright (c) Facebook, Inc. and its affiliates.
32 | *
33 | * This source code is licensed under the MIT license found in the
34 | * LICENSE file in the root directory of this source tree.
35 | */
36 |
37 | /** @license React v16.13.1
38 | * react-is.production.min.js
39 | *
40 | * Copyright (c) Facebook, Inc. and its affiliates.
41 | *
42 | * This source code is licensed under the MIT license found in the
43 | * LICENSE file in the root directory of this source tree.
44 | */
45 |
46 | /** @license React v17.0.2
47 | * react-dom.production.min.js
48 | *
49 | * Copyright (c) Facebook, Inc. and its affiliates.
50 | *
51 | * This source code is licensed under the MIT license found in the
52 | * LICENSE file in the root directory of this source tree.
53 | */
54 |
55 | /** @license React v17.0.2
56 | * react-jsx-runtime.production.min.js
57 | *
58 | * Copyright (c) Facebook, Inc. and its affiliates.
59 | *
60 | * This source code is licensed under the MIT license found in the
61 | * LICENSE file in the root directory of this source tree.
62 | */
63 |
64 | /** @license React v17.0.2
65 | * react.production.min.js
66 | *
67 | * Copyright (c) Facebook, Inc. and its affiliates.
68 | *
69 | * This source code is licensed under the MIT license found in the
70 | * LICENSE file in the root directory of this source tree.
71 | */
72 |
--------------------------------------------------------------------------------
/staticfiles/cloudinary/js/canvas-to-blob.min.js:
--------------------------------------------------------------------------------
1 | !function(t){"use strict";var e=t.HTMLCanvasElement&&t.HTMLCanvasElement.prototype,o=t.Blob&&function(){try{return Boolean(new Blob)}catch(t){return!1}}(),n=o&&t.Uint8Array&&function(){try{return 100===new Blob([new Uint8Array(100)]).size}catch(t){return!1}}(),r=t.BlobBuilder||t.WebKitBlobBuilder||t.MozBlobBuilder||t.MSBlobBuilder,a=/^data:((.*?)(;charset=.*?)?)(;base64)?,/,i=(o||r)&&t.atob&&t.ArrayBuffer&&t.Uint8Array&&function(t){var e,i,l,u,c,f,b,d,B;if(!(e=t.match(a)))throw new Error("invalid data URI");for(i=e[2]?e[1]:"text/plain"+(e[3]||";charset=US-ASCII"),l=!!e[4],u=t.slice(e[0].length),c=l?atob(u):decodeURIComponent(u),f=new ArrayBuffer(c.length),b=new Uint8Array(f),d=0;d= 980px wide, so add padding to the body to prevent
2 | content running up underneath it. */
3 |
4 | h1 {
5 | font-weight: 300;
6 | }
7 |
8 | h2, h3 {
9 | font-weight: 300;
10 | }
11 |
12 | .resource-description, .response-info {
13 | margin-bottom: 2em;
14 | }
15 |
16 | .version:before {
17 | content: "v";
18 | opacity: 0.6;
19 | padding-right: 0.25em;
20 | }
21 |
22 | .version {
23 | font-size: 70%;
24 | }
25 |
26 | .format-option {
27 | font-family: Menlo, Consolas, "Andale Mono", "Lucida Console", monospace;
28 | }
29 |
30 | .button-form {
31 | float: right;
32 | margin-right: 1em;
33 | }
34 |
35 | td.nested {
36 | padding: 0 !important;
37 | }
38 |
39 | td.nested > table {
40 | margin: 0;
41 | }
42 |
43 | form select, form input:not([type=checkbox]), form textarea {
44 | width: 90%;
45 | }
46 |
47 | form select[multiple] {
48 | height: 150px;
49 | }
50 |
51 | /* To allow tooltips to work on disabled elements */
52 | .disabled-tooltip-shield {
53 | position: absolute;
54 | top: 0;
55 | right: 0;
56 | bottom: 0;
57 | left: 0;
58 | }
59 |
60 | .errorlist {
61 | margin-top: 0.5em;
62 | }
63 |
64 | pre {
65 | overflow: auto;
66 | word-wrap: normal;
67 | white-space: pre;
68 | font-size: 12px;
69 | }
70 |
71 | .page-header {
72 | border-bottom: none;
73 | padding-bottom: 0px;
74 | }
75 |
76 | #filtersModal form input[type=submit] {
77 | width: auto;
78 | }
79 |
80 | #filtersModal .modal-body h2 {
81 | margin-top: 0
82 | }
83 |
--------------------------------------------------------------------------------
/staticfiles/rest_framework/css/prettify.css:
--------------------------------------------------------------------------------
1 | .com { color: #93a1a1; }
2 | .lit { color: #195f91; }
3 | .pun, .opn, .clo { color: #93a1a1; }
4 | .fun { color: #dc322f; }
5 | .str, .atv { color: #D14; }
6 | .kwd, .prettyprint .tag { color: #1e347b; }
7 | .typ, .atn, .dec, .var { color: teal; }
8 | .pln { color: #48484c; }
9 |
10 | .prettyprint {
11 | padding: 8px;
12 | background-color: #f7f7f9;
13 | border: 1px solid #e1e1e8;
14 | }
15 | .prettyprint.linenums {
16 | -webkit-box-shadow: inset 40px 0 0 #fbfbfc, inset 41px 0 0 #ececf0;
17 | -moz-box-shadow: inset 40px 0 0 #fbfbfc, inset 41px 0 0 #ececf0;
18 | box-shadow: inset 40px 0 0 #fbfbfc, inset 41px 0 0 #ececf0;
19 | }
20 |
21 | /* Specify class=linenums on a pre to get line numbering */
22 | ol.linenums {
23 | margin: 0 0 0 33px; /* IE indents via margin-left */
24 | }
25 | ol.linenums li {
26 | padding-left: 12px;
27 | color: #bebec5;
28 | line-height: 20px;
29 | text-shadow: 0 1px 0 #fff;
30 | }
--------------------------------------------------------------------------------
/staticfiles/rest_framework/docs/css/highlight.css:
--------------------------------------------------------------------------------
1 | /*
2 | This is the GitHub theme for highlight.js
3 |
4 | github.com style (c) Vasily Polovnyov
5 |
6 | */
7 |
8 | .hljs {
9 | display: block;
10 | overflow-x: auto;
11 | padding: 0.5em;
12 | color: #333;
13 | -webkit-text-size-adjust: none;
14 | }
15 |
16 | .hljs-comment,
17 | .diff .hljs-header,
18 | .hljs-javadoc {
19 | color: #998;
20 | font-style: italic;
21 | }
22 |
23 | .hljs-keyword,
24 | .css .rule .hljs-keyword,
25 | .hljs-winutils,
26 | .nginx .hljs-title,
27 | .hljs-subst,
28 | .hljs-request,
29 | .hljs-status {
30 | color: #333;
31 | font-weight: bold;
32 | }
33 |
34 | .hljs-number,
35 | .hljs-hexcolor,
36 | .ruby .hljs-constant {
37 | color: #008080;
38 | }
39 |
40 | .hljs-string,
41 | .hljs-tag .hljs-value,
42 | .hljs-phpdoc,
43 | .hljs-dartdoc,
44 | .tex .hljs-formula {
45 | color: #d14;
46 | }
47 |
48 | .hljs-title,
49 | .hljs-id,
50 | .scss .hljs-preprocessor {
51 | color: #900;
52 | font-weight: bold;
53 | }
54 |
55 | .hljs-list .hljs-keyword,
56 | .hljs-subst {
57 | font-weight: normal;
58 | }
59 |
60 | .hljs-class .hljs-title,
61 | .hljs-type,
62 | .vhdl .hljs-literal,
63 | .tex .hljs-command {
64 | color: #458;
65 | font-weight: bold;
66 | }
67 |
68 | .hljs-tag,
69 | .hljs-tag .hljs-title,
70 | .hljs-rule .hljs-property,
71 | .django .hljs-tag .hljs-keyword {
72 | color: #000080;
73 | font-weight: normal;
74 | }
75 |
76 | .hljs-attribute,
77 | .hljs-variable,
78 | .lisp .hljs-body,
79 | .hljs-name {
80 | color: #008080;
81 | }
82 |
83 | .hljs-regexp {
84 | color: #009926;
85 | }
86 |
87 | .hljs-symbol,
88 | .ruby .hljs-symbol .hljs-string,
89 | .lisp .hljs-keyword,
90 | .clojure .hljs-keyword,
91 | .scheme .hljs-keyword,
92 | .tex .hljs-special,
93 | .hljs-prompt {
94 | color: #990073;
95 | }
96 |
97 | .hljs-built_in {
98 | color: #0086b3;
99 | }
100 |
101 | .hljs-preprocessor,
102 | .hljs-pragma,
103 | .hljs-pi,
104 | .hljs-doctype,
105 | .hljs-shebang,
106 | .hljs-cdata {
107 | color: #999;
108 | font-weight: bold;
109 | }
110 |
111 | .hljs-deletion {
112 | background: #fdd;
113 | }
114 |
115 | .hljs-addition {
116 | background: #dfd;
117 | }
118 |
119 | .diff .hljs-change {
120 | background: #0086b3;
121 | }
122 |
123 | .hljs-chunk {
124 | color: #aaa;
125 | }
126 |
--------------------------------------------------------------------------------
/staticfiles/rest_framework/docs/css/jquery.json-view.min.css:
--------------------------------------------------------------------------------
1 | .json-view{position:relative}
2 | .json-view .collapser{width:20px;height:18px;display:block;position:absolute;left:-1.7em;top:-.2em;z-index:5;background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAgAAAAICAYAAADED76LAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAD1JREFUeNpiYGBgOADE%2F3Hgw0DM4IRHgSsDFOzFInmMAQnY49ONzZRjDFiADT7dMLALiE8y4AGW6LoBAgwAuIkf%2F%2FB7O9sAAAAASUVORK5CYII%3D);background-repeat:no-repeat;background-position:center center;opacity:.5;cursor:pointer}
3 | .json-view .collapsed{-ms-transform:rotate(-90deg);-moz-transform:rotate(-90deg);-khtml-transform:rotate(-90deg);-webkit-transform:rotate(-90deg);-o-transform:rotate(-90deg);transform:rotate(-90deg)}
4 | .json-view .bl{display:block;padding-left:20px;margin-left:-20px;position:relative}
5 | .json-view{font-family:monospace}
6 | .json-view ul{list-style-type:none;padding-left:2em;border-left:1px dotted;margin:.3em}
7 | .json-view ul li{position:relative}
8 | .json-view .comments,.json-view .dots{display:none;-moz-user-select:none;-ms-user-select:none;-khtml-user-select:none;-webkit-user-select:none;-o-user-select:none;user-select:none}
9 | .json-view .comments{padding-left:.8em;font-style:italic;color:#888}
10 | .json-view .bool,.json-view .null,.json-view .num,.json-view .undef{font-weight:700;color:#1A01CC}
11 | .json-view .str{color:#800}
--------------------------------------------------------------------------------
/staticfiles/rest_framework/docs/img/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bluesky-0412/API_Django/2fe694997713372b791572a78e86e2460706f303/staticfiles/rest_framework/docs/img/favicon.ico
--------------------------------------------------------------------------------
/staticfiles/rest_framework/docs/img/grid.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bluesky-0412/API_Django/2fe694997713372b791572a78e86e2460706f303/staticfiles/rest_framework/docs/img/grid.png
--------------------------------------------------------------------------------
/staticfiles/rest_framework/docs/js/jquery.json-view.min.js:
--------------------------------------------------------------------------------
1 | /**
2 | * jquery.json-view - jQuery collapsible JSON plugin
3 | * @version v1.0.0
4 | * @link http://github.com/bazh/jquery.json-view
5 | * @license MIT
6 | */
7 | !function(e){"use strict";var n=function(n){var a=e("",{"class":"collapser",on:{click:function(){var n=e(this);n.toggleClass("collapsed");var a=n.parent().children(".block"),p=a.children("ul");n.hasClass("collapsed")?(p.hide(),a.children(".dots, .comments").show()):(p.show(),a.children(".dots, .comments").hide())}}});return n&&a.addClass("collapsed"),a},a=function(a,p){var t=e.extend({},{nl2br:!0},p),r=function(e){return e.toString()?e.toString().replace(/&/g,"&").replace(/"/g,""").replace(//g,">"):""},s=function(n,a){return e("",{"class":a,html:r(n)})},l=function(a,p){switch(e.type(a)){case"object":p||(p=0);var c=e("",{"class":"block"}),d=Object.keys(a).length;if(!d)return c.append(s("{","b")).append(" ").append(s("}","b"));c.append(s("{","b"));var i=e("",{"class":"obj collapsible level"+p});return e.each(a,function(a,t){d--;var r=e("").append(s('"',"q")).append(a).append(s('"',"q")).append(": ").append(l(t,p+1));-1===["object","array"].indexOf(e.type(t))||e.isEmptyObject(t)||r.prepend(n()),d>0&&r.append(","),i.append(r)}),c.append(i),c.append(s("...","dots")),c.append(s("}","b")),c.append(1===Object.keys(a).length?s("// 1 item","comments"):s("// "+Object.keys(a).length+" items","comments")),c;case"array":p||(p=0);var d=a.length,c=e("",{"class":"block"});if(!d)return c.append(s("[","b")).append(" ").append(s("]","b"));c.append(s("[","b"));var i=e("",{"class":"obj collapsible level"+p});return e.each(a,function(a,t){d--;var r=e("").append(l(t,p+1));-1===["object","array"].indexOf(e.type(t))||e.isEmptyObject(t)||r.prepend(n()),d>0&&r.append(","),i.append(r)}),c.append(i),c.append(s("...","dots")),c.append(s("]","b")),c.append(1===a.length?s("// 1 item","comments"):s("// "+a.length+" items","comments")),c;case"string":if(a=r(a),/^(http|https|file):\/\/[^\s]+$/i.test(a))return e("").append(s('"',"q")).append(e("",{href:a,text:a})).append(s('"',"q"));if(t.nl2br){var o=/\n/g;o.test(a)&&(a=(a+"").replace(o,"
"))}var u=e("",{"class":"str"}).html(a);return e("").append(s('"',"q")).append(u).append(s('"',"q"));case"number":return s(a.toString(),"num");case"undefined":return s("undefined","undef");case"null":return s("null","null");case"boolean":return s(a?"true":"false","bool")}};return l(a)};return e.fn.jsonView=function(n,p){var t=e(this);if(p=e.extend({},{nl2br:!0},p),"string"==typeof n)try{n=JSON.parse(n)}catch(r){}return t.append(e("",{"class":"json-view"}).append(a(n,p))),t}}(jQuery);
--------------------------------------------------------------------------------
/staticfiles/rest_framework/fonts/fontawesome-webfont.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bluesky-0412/API_Django/2fe694997713372b791572a78e86e2460706f303/staticfiles/rest_framework/fonts/fontawesome-webfont.eot
--------------------------------------------------------------------------------
/staticfiles/rest_framework/fonts/fontawesome-webfont.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bluesky-0412/API_Django/2fe694997713372b791572a78e86e2460706f303/staticfiles/rest_framework/fonts/fontawesome-webfont.ttf
--------------------------------------------------------------------------------
/staticfiles/rest_framework/fonts/fontawesome-webfont.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bluesky-0412/API_Django/2fe694997713372b791572a78e86e2460706f303/staticfiles/rest_framework/fonts/fontawesome-webfont.woff
--------------------------------------------------------------------------------
/staticfiles/rest_framework/fonts/glyphicons-halflings-regular.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bluesky-0412/API_Django/2fe694997713372b791572a78e86e2460706f303/staticfiles/rest_framework/fonts/glyphicons-halflings-regular.eot
--------------------------------------------------------------------------------
/staticfiles/rest_framework/fonts/glyphicons-halflings-regular.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bluesky-0412/API_Django/2fe694997713372b791572a78e86e2460706f303/staticfiles/rest_framework/fonts/glyphicons-halflings-regular.ttf
--------------------------------------------------------------------------------
/staticfiles/rest_framework/fonts/glyphicons-halflings-regular.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bluesky-0412/API_Django/2fe694997713372b791572a78e86e2460706f303/staticfiles/rest_framework/fonts/glyphicons-halflings-regular.woff
--------------------------------------------------------------------------------
/staticfiles/rest_framework/fonts/glyphicons-halflings-regular.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bluesky-0412/API_Django/2fe694997713372b791572a78e86e2460706f303/staticfiles/rest_framework/fonts/glyphicons-halflings-regular.woff2
--------------------------------------------------------------------------------
/staticfiles/rest_framework/img/glyphicons-halflings-white.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bluesky-0412/API_Django/2fe694997713372b791572a78e86e2460706f303/staticfiles/rest_framework/img/glyphicons-halflings-white.png
--------------------------------------------------------------------------------
/staticfiles/rest_framework/img/glyphicons-halflings.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bluesky-0412/API_Django/2fe694997713372b791572a78e86e2460706f303/staticfiles/rest_framework/img/glyphicons-halflings.png
--------------------------------------------------------------------------------
/staticfiles/rest_framework/img/grid.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bluesky-0412/API_Django/2fe694997713372b791572a78e86e2460706f303/staticfiles/rest_framework/img/grid.png
--------------------------------------------------------------------------------
/staticfiles/rest_framework/js/csrf.js:
--------------------------------------------------------------------------------
1 | function getCookie(name) {
2 | var cookieValue = null;
3 |
4 | if (document.cookie && document.cookie != '') {
5 | var cookies = document.cookie.split(';');
6 |
7 | for (var i = 0; i < cookies.length; i++) {
8 | var cookie = jQuery.trim(cookies[i]);
9 |
10 | // Does this cookie string begin with the name we want?
11 | if (cookie.substring(0, name.length + 1) == (name + '=')) {
12 | cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
13 | break;
14 | }
15 | }
16 | }
17 |
18 | return cookieValue;
19 | }
20 |
21 | function csrfSafeMethod(method) {
22 | // these HTTP methods do not require CSRF protection
23 | return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method));
24 | }
25 |
26 | function sameOrigin(url) {
27 | // test that a given url is a same-origin URL
28 | // url could be relative or scheme relative or absolute
29 | var host = document.location.host; // host + port
30 | var protocol = document.location.protocol;
31 | var sr_origin = '//' + host;
32 | var origin = protocol + sr_origin;
33 |
34 | // Allow absolute or scheme relative URLs to same origin
35 | return (url == origin || url.slice(0, origin.length + 1) == origin + '/') ||
36 | (url == sr_origin || url.slice(0, sr_origin.length + 1) == sr_origin + '/') ||
37 | // or any other URL that isn't scheme relative or absolute i.e relative.
38 | !(/^(\/\/|http:|https:).*/.test(url));
39 | }
40 |
41 | var csrftoken = window.drf.csrfToken;
42 |
43 | $.ajaxSetup({
44 | beforeSend: function(xhr, settings) {
45 | if (!csrfSafeMethod(settings.type) && sameOrigin(settings.url)) {
46 | // Send the token to same-origin, relative URLs only.
47 | // Send the token only if the method warrants CSRF protection
48 | // Using the CSRFToken value acquired earlier
49 | xhr.setRequestHeader(window.drf.csrfHeaderName, csrftoken);
50 | }
51 | }
52 | });
53 |
--------------------------------------------------------------------------------
/staticfiles/rest_framework/js/default.js:
--------------------------------------------------------------------------------
1 | $(document).ready(function() {
2 | // JSON highlighting.
3 | prettyPrint();
4 |
5 | // Bootstrap tooltips.
6 | $('.js-tooltip').tooltip({
7 | delay: 1000,
8 | container: 'body'
9 | });
10 |
11 | // Deal with rounded tab styling after tab clicks.
12 | $('a[data-toggle="tab"]:first').on('shown', function(e) {
13 | $(e.target).parents('.tabbable').addClass('first-tab-active');
14 | });
15 |
16 | $('a[data-toggle="tab"]:not(:first)').on('shown', function(e) {
17 | $(e.target).parents('.tabbable').removeClass('first-tab-active');
18 | });
19 |
20 | $('a[data-toggle="tab"]').click(function() {
21 | document.cookie = "tabstyle=" + this.name + "; path=/";
22 | });
23 |
24 | // Store tab preference in cookies & display appropriate tab on load.
25 | var selectedTab = null;
26 | var selectedTabName = getCookie('tabstyle');
27 |
28 | if (selectedTabName) {
29 | selectedTabName = selectedTabName.replace(/[^a-z-]/g, '');
30 | }
31 |
32 | if (selectedTabName) {
33 | selectedTab = $('.form-switcher a[name=' + selectedTabName + ']');
34 | }
35 |
36 | if (selectedTab && selectedTab.length > 0) {
37 | // Display whichever tab is selected.
38 | selectedTab.tab('show');
39 | } else {
40 | // If no tab selected, display rightmost tab.
41 | $('.form-switcher a:first').tab('show');
42 | }
43 |
44 | $(window).on('load', function() {
45 | $('#errorModal').modal('show');
46 | });
47 | });
48 |
--------------------------------------------------------------------------------