1
0
Fork 0
mirror of https://github.com/Findus23/acronomy.git synced 2024-09-16 12:13:44 +02:00

initial commit

This commit is contained in:
Lukas Winkler 2020-06-01 11:03:21 +02:00
commit b8c9454ef7
Signed by: lukas
GPG key ID: 54DE4D798D244853
70 changed files with 3002 additions and 0 deletions

115
.gitignore vendored Normal file
View file

@ -0,0 +1,115 @@
# Created by https://www.gitignore.io/api/python
# Edit at https://www.gitignore.io/?templates=python
### Python ###
# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
*$py.class
# C extensions
*.so
# Distribution / packaging
.Python
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
wheels/
pip-wheel-metadata/
share/python-wheels/
*.egg-info/
.installed.cfg
*.egg
MANIFEST
# PyInstaller
# Usually these files are written by a python script from a template
# before PyInstaller builds the exe, so as to inject date/other infos into it.
*.manifest
*.spec
# Installer logs
pip-log.txt
pip-delete-this-directory.txt
# Unit test / coverage reports
htmlcov/
.tox/
.nox/
.coverage
.coverage.*
.cache
nosetests.xml
coverage.xml
*.cover
.hypothesis/
.pytest_cache/
# Translations
*.mo
*.pot
# Scrapy stuff:
.scrapy
# Sphinx documentation
docs/_build/
# PyBuilder
target/
# pyenv
.python-version
# pipenv
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
# However, in case of collaboration, if having platform-specific dependencies or dependencies
# having no cross-platform support, pipenv may install dependencies that don't work, or not
# install all needed dependencies.
#Pipfile.lock
# celery beat schedule file
celerybeat-schedule
# SageMath parsed files
*.sage.py
# Spyder project settings
.spyderproject
.spyproject
# Rope project settings
.ropeproject
# Mr Developer
.mr.developer.cfg
.project
.pydevproject
# mkdocs documentation
/site
# mypy
.mypy_cache/
.dmypy.json
dmypy.json
# Pyre type checker
.pyre/
# End of https://www.gitignore.io/api/python
.idea/
node_modules/
acronyms.txt
media/
acronomy/secrets.py

0
acronomy/__init__.py Normal file
View file

16
acronomy/asgi.py Normal file
View file

@ -0,0 +1,16 @@
"""
ASGI config for astroacro project.
It exposes the ASGI callable as a module-level variable named ``application``.
For more information on this file, see
https://docs.djangoproject.com/en/3.0/howto/deployment/asgi/
"""
import os
from django.core.asgi import get_asgi_application
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'acronomy.settings')
application = get_asgi_application()

127
acronomy/settings.py Normal file
View file

@ -0,0 +1,127 @@
"""
Django settings for astroacro project.
Generated by 'django-admin startproject' using Django 3.0.6.
For more information on this file, see
https://docs.djangoproject.com/en/3.0/topics/settings/
For the full list of settings and their values, see
https://docs.djangoproject.com/en/3.0/ref/settings/
"""
import os
# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
# Quick-start development settings - unsuitable for production
# See https://docs.djangoproject.com/en/3.0/howto/deployment/checklist/
ALLOWED_HOSTS = []
# Application definition
INSTALLED_APPS = [
'acros.apps.AcrosConfig',
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'simple_history',
'debug_toolbar',
'rest_framework',
]
MIDDLEWARE = [
'debug_toolbar.middleware.DebugToolbarMiddleware',
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
'simple_history.middleware.HistoryRequestMiddleware'
]
ROOT_URLCONF = 'acronomy.urls'
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [os.path.join(BASE_DIR, 'templates')],
'APP_DIRS': True,
'OPTIONS': {
'context_processors': [
'django.template.context_processors.debug',
'django.template.context_processors.request',
'django.contrib.auth.context_processors.auth',
'django.contrib.messages.context_processors.messages',
],
},
},
]
WSGI_APPLICATION = 'acronomy.wsgi.application'
# Password validation
# https://docs.djangoproject.com/en/3.0/ref/settings/#auth-password-validators
AUTH_PASSWORD_VALIDATORS = [
{
'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
},
{
'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
},
{
'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
},
{
'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
},
]
LOGIN_REDIRECT_URL = "/"
LOGIN_URL = "/login/"
LOGOUT_REDIRECT_URL = LOGIN_URL
# Internationalization
# https://docs.djangoproject.com/en/3.0/topics/i18n/
LANGUAGE_CODE = 'en-us'
TIME_ZONE = 'UTC'
USE_I18N = True
USE_L10N = True
USE_TZ = True
# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/3.0/howto/static-files/
STATIC_URL = '/static/'
MEDIA_URL = '/media/'
STATICFILES_DIRS = [
os.path.join(BASE_DIR, "static"),
os.path.join(BASE_DIR, 'node_modules', 'bootstrap', 'dist'),
os.path.join(BASE_DIR, 'node_modules', 'jquery', 'dist'),
os.path.join(BASE_DIR, 'node_modules', 'popper.js', 'dist'),
os.path.join(BASE_DIR, 'node_modules', '@trevoreyre'),
os.path.join(BASE_DIR, 'node_modules', '@yaireo', 'tagify', 'dist'),
]
INTERNAL_IPS = [
'127.0.0.1',
]
TAGGIT_CASE_INSENSITIVE = True

22
acronomy/urls.py Normal file
View file

@ -0,0 +1,22 @@
"""astroacro URL Configuration
The `urlpatterns` list routes URLs to views. For more information please see:
https://docs.djangoproject.com/en/3.0/topics/http/urls/
Examples:
Function views
1. Add an import: from my_app import views
2. Add a URL to urlpatterns: path('', views.home, name='home')
Class-based views
1. Add an import: from other_app.views import Home
2. Add a URL to urlpatterns: path('', Home.as_view(), name='home')
Including another URLconf
1. Import the include() function: from django.urls import include, path
2. Add a URL to urlpatterns: path('blog/', include('blog.urls'))
"""
from django.contrib import admin
from django.urls import path, include
urlpatterns = [
path('', include('acros.urls')),
path('admin/', admin.site.urls),
]

16
acronomy/wsgi.py Normal file
View file

@ -0,0 +1,16 @@
"""
WSGI config for astroacro project.
It exposes the WSGI callable as a module-level variable named ``application``.
For more information on this file, see
https://docs.djangoproject.com/en/3.0/howto/deployment/wsgi/
"""
import os
from django.core.wsgi import get_wsgi_application
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'acronomy.settings')
application = get_wsgi_application()

0
acros/__init__.py Normal file
View file

61
acros/admin.py Normal file
View file

@ -0,0 +1,61 @@
from django.contrib import admin
# Register your models here.
from simple_history.admin import SimpleHistoryAdmin
from acros.models import Acronym, Weblink, PaperReference, WikipediaLink, Tag, Host
class OwnInline(admin.TabularInline):
extra = 1
class LinkInline(OwnInline):
model = Weblink
class PaperInline(OwnInline):
model = PaperReference
fields = ["bibcode"]
readonly_fields = ["title"]
class WikiInline(OwnInline):
model = WikipediaLink
fields = ["title"]
class TagAdmin(admin.ModelAdmin):
# prepopulated_fields = {'slug': ('name',)}
readonly_fields = ["slug"]
class AcronymAdmin(SimpleHistoryAdmin):
inlines = [
LinkInline, WikiInline, PaperInline
]
filter_horizontal = ["tags"]
readonly_fields = ["slug"]
list_display = ["name", "full_name"]
list_filter = ["tags"]
save_on_top = True
class PaperAdmin(admin.ModelAdmin):
date_hierarchy = "pubdate"
list_display = ["title", "authors"]
class LinkAdmin(admin.ModelAdmin):
readonly_fields = ["host"]
class WikipediaAdmin(admin.ModelAdmin):
readonly_fields = ["thumbnail_height", "thumbnail_width"]
admin.site.register(WikipediaLink, WikipediaAdmin)
admin.site.register(Weblink, LinkAdmin)
admin.site.register(PaperReference, PaperAdmin)
admin.site.register(Tag, TagAdmin)
admin.site.register(Acronym, AcronymAdmin)
admin.site.register(Host)

5
acros/apps.py Normal file
View file

@ -0,0 +1,5 @@
from django.apps import AppConfig
class AcrosConfig(AppConfig):
name = 'acros'

55
acros/forms.py Normal file
View file

@ -0,0 +1,55 @@
from django.core.exceptions import ValidationError
from django.forms import ModelForm, TextInput, CharField
from acros.models import Acronym, Tag
from acros.utils import parse_tags, edit_string_for_tags
class TagWidget(TextInput):
def format_value(self, value):
if value is not None and not isinstance(value, str):
value = edit_string_for_tags(value)
return super().format_value(value)
class TagField(CharField):
"""
based on https://github.com/jazzband/django-taggit/blob/master/taggit/models.py
"""
widget = TagWidget
def clean(self, value):
value = super().clean(value)
try:
tag_strings = parse_tags(value)
tag_ids = []
for tag in tag_strings:
try:
to = Tag.objects.get(name__iexact=tag)
except Tag.DoesNotExist:
to = Tag(name=tag)
to.save()
tag_ids.append(to.pk)
return tag_ids
except ValueError:
raise ValidationError(
"Please provide a comma-separated list of tags."
)
class EditForm(ModelForm):
tags = TagField()
class Meta:
model = Acronym
fields = ['name', 'full_name', "description_md", "tags"]
class AddForm(ModelForm):
tags = TagField()
class Meta:
model = Acronym
fields = ['name', 'full_name', "description_md", "tags"]

View file

@ -0,0 +1,14 @@
from django.core.management.base import BaseCommand
from acros.models import Acronym
from acros.utils import md_to_html
class Command(BaseCommand):
help = 'Updates all Markdown descriptions'
def handle(self, *args, **options):
acronyms = Acronym.objects.all()
for acronym in acronyms:
print(acronym.name)
acronym.description_html = md_to_html(acronym.description_md)

View file

@ -0,0 +1,40 @@
# Generated by Django 3.0.6 on 2020-05-25 19:25
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
initial = True
dependencies = [
]
operations = [
migrations.CreateModel(
name='Acronym',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('name', models.CharField(max_length=100)),
('full_name', models.CharField(max_length=1000)),
('slug', models.SlugField(unique=True)),
],
),
migrations.CreateModel(
name='Weblink',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('url', models.URLField()),
('acronym', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='links', to='acros.Acronym')),
],
),
migrations.CreateModel(
name='DOIReference',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('doi', models.CharField(max_length=255)),
('acronym', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='dois', to='acros.Acronym')),
],
),
]

View file

@ -0,0 +1,75 @@
# Generated by Django 3.0.6 on 2020-05-25 19:35
from django.conf import settings
from django.db import migrations, models
import django.db.models.deletion
import simple_history.models
class Migration(migrations.Migration):
dependencies = [
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
('acros', '0001_initial'),
]
operations = [
migrations.CreateModel(
name='HistoricalWeblink',
fields=[
('id', models.IntegerField(auto_created=True, blank=True, db_index=True, verbose_name='ID')),
('url', models.URLField()),
('history_id', models.AutoField(primary_key=True, serialize=False)),
('history_date', models.DateTimeField()),
('history_change_reason', models.CharField(max_length=100, null=True)),
('history_type', models.CharField(choices=[('+', 'Created'), ('~', 'Changed'), ('-', 'Deleted')], max_length=1)),
('acronym', models.ForeignKey(blank=True, db_constraint=False, null=True, on_delete=django.db.models.deletion.DO_NOTHING, related_name='+', to='acros.Acronym')),
('history_user', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to=settings.AUTH_USER_MODEL)),
],
options={
'verbose_name': 'historical weblink',
'ordering': ('-history_date', '-history_id'),
'get_latest_by': 'history_date',
},
bases=(simple_history.models.HistoricalChanges, models.Model),
),
migrations.CreateModel(
name='HistoricalDOIReference',
fields=[
('id', models.IntegerField(auto_created=True, blank=True, db_index=True, verbose_name='ID')),
('doi', models.CharField(max_length=255)),
('history_id', models.AutoField(primary_key=True, serialize=False)),
('history_date', models.DateTimeField()),
('history_change_reason', models.CharField(max_length=100, null=True)),
('history_type', models.CharField(choices=[('+', 'Created'), ('~', 'Changed'), ('-', 'Deleted')], max_length=1)),
('acronym', models.ForeignKey(blank=True, db_constraint=False, null=True, on_delete=django.db.models.deletion.DO_NOTHING, related_name='+', to='acros.Acronym')),
('history_user', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to=settings.AUTH_USER_MODEL)),
],
options={
'verbose_name': 'historical doi reference',
'ordering': ('-history_date', '-history_id'),
'get_latest_by': 'history_date',
},
bases=(simple_history.models.HistoricalChanges, models.Model),
),
migrations.CreateModel(
name='HistoricalAcronym',
fields=[
('id', models.IntegerField(auto_created=True, blank=True, db_index=True, verbose_name='ID')),
('name', models.CharField(max_length=100)),
('full_name', models.CharField(max_length=1000)),
('slug', models.SlugField()),
('history_id', models.AutoField(primary_key=True, serialize=False)),
('history_date', models.DateTimeField()),
('history_change_reason', models.CharField(max_length=100, null=True)),
('history_type', models.CharField(choices=[('+', 'Created'), ('~', 'Changed'), ('-', 'Deleted')], max_length=1)),
('history_user', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to=settings.AUTH_USER_MODEL)),
],
options={
'verbose_name': 'historical acronym',
'ordering': ('-history_date', '-history_id'),
'get_latest_by': 'history_date',
},
bases=(simple_history.models.HistoricalChanges, models.Model),
),
]

View file

@ -0,0 +1,37 @@
# Generated by Django 3.0.6 on 2020-05-27 09:38
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('acros', '0002_historicalacronym_historicaldoireference_historicalweblink'),
]
operations = [
migrations.AddField(
model_name='acronym',
name='description_html',
field=models.TextField(default='', editable=False),
preserve_default=False,
),
migrations.AddField(
model_name='acronym',
name='description_md',
field=models.TextField(default=''),
preserve_default=False,
),
migrations.AddField(
model_name='historicalacronym',
name='description_html',
field=models.TextField(default='', editable=False),
preserve_default=False,
),
migrations.AddField(
model_name='historicalacronym',
name='description_md',
field=models.TextField(default=''),
preserve_default=False,
),
]

View file

@ -0,0 +1,54 @@
# Generated by Django 3.0.6 on 2020-05-27 19:22
from django.conf import settings
from django.db import migrations, models
import django.db.models.deletion
import simple_history.models
class Migration(migrations.Migration):
dependencies = [
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
('acros', '0003_auto_20200527_0938'),
]
operations = [
migrations.AlterField(
model_name='acronym',
name='description_md',
field=models.TextField(blank=True),
),
migrations.AlterField(
model_name='historicalacronym',
name='description_md',
field=models.TextField(blank=True),
),
migrations.CreateModel(
name='WikipediaLink',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('title', models.CharField(max_length=200)),
('acronym', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='wiki_articles', to='acros.Acronym')),
],
),
migrations.CreateModel(
name='HistoricalWikipediaLink',
fields=[
('id', models.IntegerField(auto_created=True, blank=True, db_index=True, verbose_name='ID')),
('title', models.CharField(max_length=200)),
('history_id', models.AutoField(primary_key=True, serialize=False)),
('history_date', models.DateTimeField()),
('history_change_reason', models.CharField(max_length=100, null=True)),
('history_type', models.CharField(choices=[('+', 'Created'), ('~', 'Changed'), ('-', 'Deleted')], max_length=1)),
('acronym', models.ForeignKey(blank=True, db_constraint=False, null=True, on_delete=django.db.models.deletion.DO_NOTHING, related_name='+', to='acros.Acronym')),
('history_user', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to=settings.AUTH_USER_MODEL)),
],
options={
'verbose_name': 'historical wikipedia link',
'ordering': ('-history_date', '-history_id'),
'get_latest_by': 'history_date',
},
bases=(simple_history.models.HistoricalChanges, models.Model),
),
]

View file

@ -0,0 +1,62 @@
# Generated by Django 3.0.6 on 2020-05-27 19:54
from django.conf import settings
from django.db import migrations, models
import django.db.models.deletion
import simple_history.models
class Migration(migrations.Migration):
dependencies = [
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
('acros', '0004_auto_20200527_1922'),
]
operations = [
migrations.CreateModel(
name='HistoricalPaperReference',
fields=[
('id', models.IntegerField(auto_created=True, blank=True, db_index=True, verbose_name='ID')),
('title', models.CharField(max_length=500)),
('bibcode', models.CharField(max_length=255)),
('arxiv_id', models.CharField(blank=True, max_length=20)),
('history_id', models.AutoField(primary_key=True, serialize=False)),
('history_date', models.DateTimeField()),
('history_change_reason', models.CharField(max_length=100, null=True)),
('history_type', models.CharField(choices=[('+', 'Created'), ('~', 'Changed'), ('-', 'Deleted')], max_length=1)),
('acronym', models.ForeignKey(blank=True, db_constraint=False, null=True, on_delete=django.db.models.deletion.DO_NOTHING, related_name='+', to='acros.Acronym')),
('history_user', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to=settings.AUTH_USER_MODEL)),
],
options={
'verbose_name': 'historical paper reference',
'ordering': ('-history_date', '-history_id'),
'get_latest_by': 'history_date',
},
bases=(simple_history.models.HistoricalChanges, models.Model),
),
migrations.CreateModel(
name='PaperReference',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('title', models.CharField(max_length=500)),
('bibcode', models.CharField(max_length=255)),
('arxiv_id', models.CharField(blank=True, max_length=20)),
('acronym', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='papers', to='acros.Acronym')),
],
),
migrations.RemoveField(
model_name='historicaldoireference',
name='acronym',
),
migrations.RemoveField(
model_name='historicaldoireference',
name='history_user',
),
migrations.DeleteModel(
name='DOIReference',
),
migrations.DeleteModel(
name='HistoricalDOIReference',
),
]

View file

@ -0,0 +1,23 @@
# Generated by Django 3.0.6 on 2020-05-27 19:56
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('acros', '0005_auto_20200527_1954'),
]
operations = [
migrations.AddField(
model_name='historicalpaperreference',
name='doi',
field=models.CharField(blank=True, max_length=255),
),
migrations.AddField(
model_name='paperreference',
name='doi',
field=models.CharField(blank=True, max_length=255),
),
]

View file

@ -0,0 +1,26 @@
# Generated by Django 3.0.6 on 2020-05-28 17:17
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('acros', '0006_auto_20200527_1956'),
]
operations = [
migrations.CreateModel(
name='Tag',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('name', models.CharField(max_length=100)),
('slug', models.CharField(max_length=100)),
],
),
migrations.AddField(
model_name='acronym',
name='tags',
field=models.ManyToManyField(related_name='acronyms', to='acros.Tag'),
),
]

View file

@ -0,0 +1,18 @@
# Generated by Django 3.0.6 on 2020-05-28 18:27
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('acros', '0007_auto_20200528_1717'),
]
operations = [
migrations.AlterField(
model_name='tag',
name='slug',
field=models.CharField(editable=False, max_length=100),
),
]

View file

@ -0,0 +1,79 @@
# Generated by Django 3.0.6 on 2020-05-29 17:28
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('acros', '0008_auto_20200528_1827'),
]
operations = [
migrations.AddField(
model_name='historicalwikipedialink',
name='extract',
field=models.TextField(blank=True),
),
migrations.AddField(
model_name='historicalwikipedialink',
name='extract_html',
field=models.TextField(blank=True),
),
migrations.AddField(
model_name='historicalwikipedialink',
name='thumbnail',
field=models.TextField(blank=True, max_length=100),
),
migrations.AddField(
model_name='historicalwikipedialink',
name='thumbnail_height',
field=models.IntegerField(blank=True, default=0),
preserve_default=False,
),
migrations.AddField(
model_name='historicalwikipedialink',
name='thumbnail_width',
field=models.IntegerField(blank=True, default=0),
preserve_default=False,
),
migrations.AddField(
model_name='historicalwikipedialink',
name='timestamp',
field=models.DateTimeField(default='2020-01-01 00:00'),
preserve_default=False,
),
migrations.AddField(
model_name='wikipedialink',
name='extract',
field=models.TextField(blank=True),
),
migrations.AddField(
model_name='wikipedialink',
name='extract_html',
field=models.TextField(blank=True),
),
migrations.AddField(
model_name='wikipedialink',
name='thumbnail',
field=models.FileField(blank=True, upload_to='wikipedia_thumbnails/'),
),
migrations.AddField(
model_name='wikipedialink',
name='thumbnail_height',
field=models.IntegerField(blank=True, default=0),
preserve_default=False,
),
migrations.AddField(
model_name='wikipedialink',
name='thumbnail_width',
field=models.IntegerField(blank=True, default=0),
preserve_default=False,
),
migrations.AddField(
model_name='wikipedialink',
name='timestamp',
field=models.DateTimeField(default='2020-01-01 00:00'),
preserve_default=False,
),
]

View file

@ -0,0 +1,60 @@
# Generated by Django 3.0.6 on 2020-05-29 18:59
from django.db import migrations, models
import django.utils.timezone
class Migration(migrations.Migration):
dependencies = [
('acros', '0009_auto_20200529_1728'),
]
operations = [
migrations.AddField(
model_name='historicalpaperreference',
name='authors',
field=models.CharField(default='', max_length=1000),
preserve_default=False,
),
migrations.AddField(
model_name='historicalpaperreference',
name='pubdate',
field=models.DateTimeField(default=django.utils.timezone.now),
preserve_default=False,
),
migrations.AddField(
model_name='historicalpaperreference',
name='year',
field=models.IntegerField(default=1),
preserve_default=False,
),
migrations.AddField(
model_name='paperreference',
name='authors',
field=models.CharField(default='', max_length=1000),
preserve_default=False,
),
migrations.AddField(
model_name='paperreference',
name='pubdate',
field=models.DateTimeField(default=django.utils.timezone.now),
preserve_default=False,
),
migrations.AddField(
model_name='paperreference',
name='year',
field=models.IntegerField(default=0),
preserve_default=False,
),
migrations.AlterField(
model_name='historicalwikipedialink',
name='timestamp',
field=models.DateTimeField(blank=True),
),
migrations.AlterField(
model_name='wikipedialink',
name='timestamp',
field=models.DateTimeField(blank=True),
),
]

View file

@ -0,0 +1,73 @@
# Generated by Django 3.0.6 on 2020-05-29 19:00
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('acros', '0010_auto_20200529_1859'),
]
operations = [
migrations.AlterField(
model_name='historicalpaperreference',
name='arxiv_id',
field=models.CharField(max_length=20, null=True),
),
migrations.AlterField(
model_name='historicalpaperreference',
name='authors',
field=models.CharField(max_length=1000, null=True),
),
migrations.AlterField(
model_name='historicalpaperreference',
name='doi',
field=models.CharField(max_length=255, null=True),
),
migrations.AlterField(
model_name='historicalpaperreference',
name='pubdate',
field=models.DateTimeField(null=True),
),
migrations.AlterField(
model_name='historicalpaperreference',
name='title',
field=models.CharField(max_length=500, null=True),
),
migrations.AlterField(
model_name='historicalpaperreference',
name='year',
field=models.IntegerField(null=True),
),
migrations.AlterField(
model_name='paperreference',
name='arxiv_id',
field=models.CharField(max_length=20, null=True),
),
migrations.AlterField(
model_name='paperreference',
name='authors',
field=models.CharField(max_length=1000, null=True),
),
migrations.AlterField(
model_name='paperreference',
name='doi',
field=models.CharField(max_length=255, null=True),
),
migrations.AlterField(
model_name='paperreference',
name='pubdate',
field=models.DateTimeField(null=True),
),
migrations.AlterField(
model_name='paperreference',
name='title',
field=models.CharField(max_length=500, null=True),
),
migrations.AlterField(
model_name='paperreference',
name='year',
field=models.IntegerField(null=True),
),
]

View file

@ -0,0 +1,93 @@
# Generated by Django 3.0.6 on 2020-05-29 19:43
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('acros', '0011_auto_20200529_1900'),
]
operations = [
migrations.AddField(
model_name='historicalpaperreference',
name='fetched',
field=models.BooleanField(default=False),
),
migrations.AddField(
model_name='historicalwikipedialink',
name='fetched',
field=models.BooleanField(default=False),
),
migrations.AddField(
model_name='paperreference',
name='fetched',
field=models.BooleanField(default=False),
),
migrations.AddField(
model_name='wikipedialink',
name='fetched',
field=models.BooleanField(default=False),
),
migrations.AlterField(
model_name='historicalpaperreference',
name='arxiv_id',
field=models.CharField(blank=True, max_length=20, null=True),
),
migrations.AlterField(
model_name='historicalpaperreference',
name='authors',
field=models.CharField(blank=True, max_length=1000, null=True),
),
migrations.AlterField(
model_name='historicalpaperreference',
name='doi',
field=models.CharField(blank=True, max_length=255, null=True),
),
migrations.AlterField(
model_name='historicalpaperreference',
name='pubdate',
field=models.DateTimeField(blank=True, null=True),
),
migrations.AlterField(
model_name='historicalpaperreference',
name='title',
field=models.CharField(blank=True, max_length=500, null=True),
),
migrations.AlterField(
model_name='historicalpaperreference',
name='year',
field=models.IntegerField(blank=True, null=True),
),
migrations.AlterField(
model_name='paperreference',
name='arxiv_id',
field=models.CharField(blank=True, max_length=20, null=True),
),
migrations.AlterField(
model_name='paperreference',
name='authors',
field=models.CharField(blank=True, max_length=1000, null=True),
),
migrations.AlterField(
model_name='paperreference',
name='doi',
field=models.CharField(blank=True, max_length=255, null=True),
),
migrations.AlterField(
model_name='paperreference',
name='pubdate',
field=models.DateTimeField(blank=True, null=True),
),
migrations.AlterField(
model_name='paperreference',
name='title',
field=models.CharField(blank=True, max_length=500, null=True),
),
migrations.AlterField(
model_name='paperreference',
name='year',
field=models.IntegerField(blank=True, null=True),
),
]

View file

@ -0,0 +1,37 @@
# Generated by Django 3.0.6 on 2020-05-31 16:16
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('acros', '0012_auto_20200529_1943'),
]
operations = [
migrations.CreateModel(
name='Author',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('name', models.CharField(max_length=100)),
],
),
migrations.AlterModelOptions(
name='acronym',
options={'ordering': ['name']},
),
migrations.RemoveField(
model_name='historicalpaperreference',
name='authors',
),
migrations.RemoveField(
model_name='paperreference',
name='authors',
),
migrations.AddField(
model_name='paperreference',
name='authors',
field=models.ManyToManyField(null=True, to='acros.Author'),
),
]

View file

@ -0,0 +1,18 @@
# Generated by Django 3.0.6 on 2020-05-31 16:16
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('acros', '0013_auto_20200531_1616'),
]
operations = [
migrations.AlterField(
model_name='paperreference',
name='authors',
field=models.ManyToManyField(to='acros.Author'),
),
]

View file

@ -0,0 +1,30 @@
# Generated by Django 3.0.6 on 2020-05-31 16:38
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('acros', '0014_auto_20200531_1616'),
]
operations = [
migrations.AddField(
model_name='historicalpaperreference',
name='authors',
field=models.CharField(blank=True, max_length=1000, null=True),
),
migrations.RemoveField(
model_name='paperreference',
name='authors',
),
migrations.AddField(
model_name='paperreference',
name='authors',
field=models.CharField(blank=True, max_length=1000, null=True),
),
migrations.DeleteModel(
name='Author',
),
]

View file

@ -0,0 +1,18 @@
# Generated by Django 3.0.6 on 2020-05-31 17:04
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('acros', '0015_auto_20200531_1638'),
]
operations = [
migrations.AlterField(
model_name='wikipedialink',
name='thumbnail',
field=models.ImageField(blank=True, upload_to='wikipedia_thumbnails/'),
),
]

View file

@ -0,0 +1,34 @@
# Generated by Django 3.0.6 on 2020-05-31 17:05
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('acros', '0016_auto_20200531_1704'),
]
operations = [
migrations.RemoveField(
model_name='historicalwikipedialink',
name='thumbnail_height',
),
migrations.RemoveField(
model_name='historicalwikipedialink',
name='thumbnail_width',
),
migrations.RemoveField(
model_name='wikipedialink',
name='thumbnail_height',
),
migrations.RemoveField(
model_name='wikipedialink',
name='thumbnail_width',
),
migrations.AlterField(
model_name='wikipedialink',
name='thumbnail',
field=models.ImageField(blank=True, height_field='thumbnail_height', upload_to='wikipedia_thumbnails/', width_field='thumbnail_width'),
),
]

View file

@ -0,0 +1,37 @@
# Generated by Django 3.0.6 on 2020-05-31 17:09
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('acros', '0017_auto_20200531_1705'),
]
operations = [
migrations.AddField(
model_name='historicalwikipedialink',
name='thumbnail_height',
field=models.IntegerField(blank=True, default=1, editable=False),
preserve_default=False,
),
migrations.AddField(
model_name='historicalwikipedialink',
name='thumbnail_width',
field=models.IntegerField(blank=True, default=1, editable=False),
preserve_default=False,
),
migrations.AddField(
model_name='wikipedialink',
name='thumbnail_height',
field=models.IntegerField(blank=True, default=1, editable=False),
preserve_default=False,
),
migrations.AddField(
model_name='wikipedialink',
name='thumbnail_width',
field=models.IntegerField(blank=True, default=1, editable=False),
preserve_default=False,
),
]

View file

@ -0,0 +1,21 @@
# Generated by Django 3.0.6 on 2020-05-31 17:19
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('acros', '0018_auto_20200531_1709'),
]
operations = [
migrations.CreateModel(
name='Host',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('host', models.CharField(max_length=100)),
('icon', models.ImageField(blank=True, upload_to='host_icons/')),
],
),
]

View file

@ -0,0 +1,18 @@
# Generated by Django 3.0.6 on 2020-05-31 17:19
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('acros', '0019_host'),
]
operations = [
migrations.AddField(
model_name='host',
name='fetched',
field=models.BooleanField(default=False),
),
]

View file

@ -0,0 +1,42 @@
# Generated by Django 3.0.6 on 2020-05-31 17:26
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('acros', '0020_host_fetched'),
]
operations = [
migrations.AddField(
model_name='historicalweblink',
name='host',
field=models.ForeignKey(blank=True, db_constraint=False, editable=False, null=True, on_delete=django.db.models.deletion.DO_NOTHING, related_name='+', to='acros.Host'),
),
migrations.AddField(
model_name='host',
name='icon_height',
field=models.IntegerField(blank=True, default=1, editable=False),
preserve_default=False,
),
migrations.AddField(
model_name='host',
name='icon_width',
field=models.IntegerField(blank=True, default=1, editable=False),
preserve_default=False,
),
migrations.AddField(
model_name='weblink',
name='host',
field=models.ForeignKey(default=1, editable=False, on_delete=django.db.models.deletion.CASCADE, to='acros.Host'),
preserve_default=False,
),
migrations.AlterField(
model_name='host',
name='icon',
field=models.ImageField(blank=True, height_field='icon_height', upload_to='host_icons/', width_field='icon_width'),
),
]

View file

@ -0,0 +1,23 @@
# Generated by Django 3.0.6 on 2020-05-31 17:28
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('acros', '0021_auto_20200531_1726'),
]
operations = [
migrations.AlterField(
model_name='host',
name='icon_height',
field=models.IntegerField(blank=True, editable=False, null=True),
),
migrations.AlterField(
model_name='host',
name='icon_width',
field=models.IntegerField(blank=True, editable=False, null=True),
),
]

View file

@ -0,0 +1,23 @@
# Generated by Django 3.0.6 on 2020-05-31 18:35
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('acros', '0022_auto_20200531_1728'),
]
operations = [
migrations.AlterField(
model_name='historicalpaperreference',
name='authors',
field=models.CharField(blank=True, max_length=10000, null=True),
),
migrations.AlterField(
model_name='paperreference',
name='authors',
field=models.CharField(blank=True, max_length=10000, null=True),
),
]

View file

@ -0,0 +1,23 @@
# Generated by Django 3.0.6 on 2020-05-31 18:38
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('acros', '0023_auto_20200531_1835'),
]
operations = [
migrations.AlterField(
model_name='historicalpaperreference',
name='authors',
field=models.CharField(blank=True, max_length=500, null=True),
),
migrations.AlterField(
model_name='paperreference',
name='authors',
field=models.CharField(blank=True, max_length=500, null=True),
),
]

View file

32
acros/models/Acronym.py Normal file
View file

@ -0,0 +1,32 @@
from django.db import models
from django.urls import reverse
from django.utils.text import slugify
from simple_history.models import HistoricalRecords
from acros.models import Tag
from acros.utils import md_to_html
class Acronym(models.Model):
name = models.CharField(max_length=100)
full_name = models.CharField(max_length=1000)
slug = models.SlugField(null=False, unique=True)
description_md = models.TextField(blank=True)
description_html = models.TextField(editable=False)
history = HistoricalRecords()
tags = models.ManyToManyField(Tag, related_name="acronyms")
def save(self, *args, **kwargs):
self.description_html = md_to_html(self.description_md)
if not self.slug:
self.slug = slugify(self.name)
super(Acronym, self).save(*args, **kwargs)
def __str__(self):
return self.name
def get_absolute_url(self):
return reverse('detail', args=[str(self.slug)])
class Meta:
ordering = ["name"]

37
acros/models/Host.py Normal file
View file

@ -0,0 +1,37 @@
from io import BytesIO
from tempfile import TemporaryFile
import requests
from PIL import Image
from django.core.files.base import ContentFile
from django.db import models
class Host(models.Model):
host = models.CharField(max_length=100)
icon = models.ImageField(upload_to="host_icons/", blank=True,
height_field="icon_height", width_field="icon_width")
icon_width = models.IntegerField(blank=True, null=True, editable=False)
icon_height = models.IntegerField(blank=True, null=True, editable=False)
fetched = models.BooleanField(default=False)
def __str__(self):
return self.host
def save(self, *args, **kwargs):
if not self.fetched or True:
with TemporaryFile("rb+") as fd:
r = requests.get(f"https://external-content.duckduckgo.com/ip3/{self.host}.ico")
if r.status_code == 200:
filename = self.host + ".png"
for chunk in r.iter_content(chunk_size=128):
fd.write(chunk)
image = Image.open(fd)
image_io = BytesIO()
image.save(image_io, format='PNG', quality=9)
self.icon.save(filename, ContentFile(image_io.getvalue()), save=False)
else:
self.icon = None
self.fetched = True
super(Host, self).save(*args, **kwargs)

View file

@ -0,0 +1,68 @@
import ads
from ads.search import Article
from django.db import models
from simple_history.models import HistoricalRecords
from acros.models import Acronym
from acronomy.settings import ADS_AUTH_TOKEN
class PaperReference(models.Model):
acronym = models.ForeignKey(Acronym, on_delete=models.CASCADE, related_name="papers")
bibcode = models.CharField(max_length=255)
title = models.CharField(max_length=500, null=True, blank=True)
authors = models.CharField(max_length=500, null=True, blank=True)
year = models.IntegerField(null=True, blank=True)
pubdate = models.DateTimeField(null=True, blank=True)
arxiv_id = models.CharField(max_length=20, null=True, blank=True)
doi = models.CharField(max_length=255, null=True, blank=True)
fetched = models.BooleanField(default=False)
history = HistoricalRecords()
def __str__(self):
return self.title
def save(self, *args, **kwargs):
if not self.fetched:
ads.config.token = ADS_AUTH_TOKEN
cols = ["title", "author", "year", "pubdate", "doi", "identifier"]
papers = ads.SearchQuery(bibcode=self.bibcode, fl=cols)
paper: Article = next(papers)
self.title = paper.title[0]
if len(paper.author) > 3:
self.authors = paper.author[0] + " et al."
else:
self.authors = ", ".join(paper.author)
self.year = paper.year
self.pubdate = paper.pubdate.replace("-00", "-01")
if paper.doi and len(paper.doi) > 0:
self.doi = paper.doi[0]
else:
self.doi = None
arxiv_papers = [ident for ident in paper.identifier if "arXiv:" in ident]
if len(arxiv_papers) > 0:
self.arxiv_id = [ident for ident in paper.identifier if "arXiv:" in ident][0].split("arXiv:")[-1]
else:
self.arxiv_id = None
self.fetched = True
super(PaperReference, self).save(*args, **kwargs)
@property
def ads_url(self):
return f"https://ui.adsabs.harvard.edu/abs/{self.bibcode}/abstract"
@property
def arxiv_url(self):
return "https://arxiv.org/abs/" + self.arxiv_id
@property
def doi_url(self):
return "https://doi.org/" + self.doi
@property
def publisher_url(self):
return f"https://ui.adsabs.harvard.edu/link_gateway/{self.bibcode}/PUB_PDF"
@property
def preprint_url(self):
return "https://arxiv.org/pdf/" + self.arxiv_id

18
acros/models/Tag.py Normal file
View file

@ -0,0 +1,18 @@
from django.db import models
from django.urls import reverse
from django.utils.text import slugify
class Tag(models.Model):
name = models.CharField(max_length=100)
slug = models.CharField(max_length=100, editable=False)
def __str__(self):
return self.name
def save(self, *args, **kwargs):
self.slug = slugify(self.name)
super(Tag, self).save()
def get_absolute_url(self):
return reverse('tag', args=[str(self.slug)])

23
acros/models/Weblink.py Normal file
View file

@ -0,0 +1,23 @@
from urllib.parse import urlparse
from django.db import models
from simple_history.models import HistoricalRecords
from acros.models import Acronym, Host
class Weblink(models.Model):
acronym = models.ForeignKey(Acronym, on_delete=models.CASCADE, related_name="links")
url = models.URLField()
host = models.ForeignKey(Host, on_delete=models.CASCADE, editable=False)
history = HistoricalRecords()
def __str__(self):
return self.url
def save(self, *args, **kwargs):
uri = urlparse(self.url)
self.host, created = Host.objects.get_or_create(host=uri.hostname)
super(Weblink, self).save(*args, **kwargs)

View file

@ -0,0 +1,44 @@
from tempfile import TemporaryFile
import requests
from django.core.files import File
from django.db import models
from simple_history.models import HistoricalRecords
from acros.models import Acronym
from acros.utils import fetch_wikipedia_summary
class WikipediaLink(models.Model):
acronym = models.ForeignKey(Acronym, on_delete=models.CASCADE, related_name="wiki_articles")
title = models.CharField(max_length=200)
extract = models.TextField(blank=True)
extract_html = models.TextField(blank=True)
thumbnail = models.ImageField(upload_to="wikipedia_thumbnails/", blank=True,
height_field="thumbnail_height", width_field="thumbnail_width")
thumbnail_width = models.IntegerField(blank=True, editable=False)
thumbnail_height = models.IntegerField(blank=True, editable=False)
timestamp = models.DateTimeField(blank=True)
fetched = models.BooleanField(default=False)
history = HistoricalRecords()
def save(self, *args, **kwargs):
if not self.fetched:
self.extract, self.extract_html, self.timestamp, thumbnail = fetch_wikipedia_summary(self.title)
with TemporaryFile("rb+") as fd:
r = requests.get(thumbnail["source"])
filename = thumbnail["source"].split("/")[-1]
for chunk in r.iter_content(chunk_size=128):
fd.write(chunk)
image_file = File(fd)
self.thumbnail.save(filename, image_file, save=False)
self.fetched = True
super(WikipediaLink, self).save(*args, **kwargs)
@property
def url(self):
return f"https://en.wikipedia.org/wiki/{self.title}"
def __str__(self):
return self.title

6
acros/models/__init__.py Normal file
View file

@ -0,0 +1,6 @@
from .Tag import Tag
from .Acronym import Acronym
from .Host import Host
from .PaperReference import PaperReference
from .Weblink import Weblink
from .WikipediaLink import WikipediaLink

56
acros/serializers.py Normal file
View file

@ -0,0 +1,56 @@
from rest_framework import serializers
from acros.models import Acronym, Weblink, PaperReference, Tag, WikipediaLink
class WeblinkSerializer(serializers.ModelSerializer):
class Meta:
model = Weblink
exclude = ["acronym"]
class PaperSerializer(serializers.ModelSerializer):
class Meta:
model = PaperReference
fields = ["title", "bibcode", "arxiv_id", "doi", "ads_url", "arxiv_url", "doi_url"]
class WikipediaSerializer(serializers.ModelSerializer):
class Meta:
model = WikipediaLink
fields = ["title", "url"]
class AcronymListSerializer(serializers.HyperlinkedModelSerializer):
tags = serializers.SlugRelatedField(
many=True,
read_only=True,
slug_field='name'
)
class Meta:
model = Acronym
exclude = ['description_md']
class AcronymSerializer(serializers.HyperlinkedModelSerializer):
# links = serializers.SlugRelatedField(many=True,read_only=True,slug_field="url")
links = WeblinkSerializer(many=True)
papers = PaperSerializer(many=True)
wiki_articles = WikipediaSerializer(many=True)
tags = serializers.SlugRelatedField(
many=True,
read_only=True,
slug_field='name'
)
class Meta:
model = Acronym
exclude = ['description_md']
# fields = ["name", "links","dois"]
class TagSerializer(serializers.ModelSerializer):
class Meta:
model = Tag
fields = ["name"]

View file

@ -0,0 +1,4 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100">
<path fill="#FFF" stroke="black" stroke-width="10"
d="m43,35H5v60h60V57M45,5v10l10,10-30,30 20,20 30-30 10,10h10V5z"/>
</svg>

After

Width:  |  Height:  |  Size: 203 B

View file

@ -0,0 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" stroke-miterlimit="10" fill-rule="evenodd" viewBox="0 0 128 128">
<path d="M 120.85,29.21 C 120.85,29.62 120.72,29.99 120.47,30.33 C 120.21,30.66 119.94,30.83 119.63,30.83 C 117.14,31.07 115.09,31.87 113.51,33.24 C 111.92,34.6 110.29,37.21 108.6,41.05 L 82.8,99.19 C 82.63,99.73 82.16,100 81.38,100 C 80.77,100 80.3,99.73 79.96,99.19 L 65.49,68.93 L 48.85,99.19 C 48.51,99.73 48.04,100 47.43,100 C 46.69,100 46.2,99.73 45.96,99.19 L 20.61,41.05 C 19.03,37.44 17.36,34.92 15.6,33.49 C 13.85,32.06 11.4,31.17 8.27,30.83 C 8,30.83 7.74,30.69 7.51,30.4 C 7.27,30.12 7.15,29.79 7.15,29.42 C 7.15,28.47 7.42,28 7.96,28 C 10.22,28 12.58,28.1 15.05,28.3 C 17.34,28.51 19.5,28.61 21.52,28.61 C 23.58,28.61 26.01,28.51 28.81,28.3 C 31.74,28.1 34.34,28 36.6,28 C 37.14,28 37.41,28.47 37.41,29.42 C 37.41,30.36 37.24,30.83 36.91,30.83 C 34.65,31 32.87,31.58 31.57,32.55 C 30.27,33.53 29.62,34.81 29.62,36.4 C 29.62,37.21 29.89,38.22 30.43,39.43 L 51.38,86.74 L 63.27,64.28 L 52.19,41.05 C 50.2,36.91 48.56,34.23 47.28,33.03 C 46,31.84 44.06,31.1 41.46,30.83 C 41.22,30.83 41,30.69 40.78,30.4 C 40.56,30.12 40.45,29.79 40.45,29.42 C 40.45,28.47 40.68,28 41.16,28 C 43.42,28 45.49,28.1 47.38,28.3 C 49.2,28.51 51.14,28.61 53.2,28.61 C 55.22,28.61 57.36,28.51 59.62,28.3 C 61.95,28.1 64.24,28 66.5,28 C 67.04,28 67.31,28.47 67.31,29.42 C 67.31,30.36 67.15,30.83 66.81,30.83 C 62.29,31.14 60.03,32.42 60.03,34.68 C 60.03,35.69 60.55,37.26 61.6,39.38 L 68.93,54.26 L 76.22,40.65 C 77.23,38.73 77.74,37.11 77.74,35.79 C 77.74,32.69 75.48,31.04 70.96,30.83 C 70.55,30.83 70.35,30.36 70.35,29.42 C 70.35,29.08 70.45,28.76 70.65,28.46 C 70.86,28.15 71.06,28 71.26,28 C 72.88,28 74.87,28.1 77.23,28.3 C 79.49,28.51 81.35,28.61 82.8,28.61 C 83.84,28.61 85.38,28.52 87.4,28.35 C 89.96,28.12 92.11,28 93.83,28 C 94.23,28 94.43,28.4 94.43,29.21 C 94.43,30.29 94.06,30.83 93.32,30.83 C 90.69,31.1 88.57,31.83 86.97,33.01 C 85.37,34.19 83.37,36.87 80.98,41.05 L 71.26,59.02 L 84.42,85.83 L 103.85,40.65 C 104.52,39 104.86,37.48 104.86,36.1 C 104.86,32.79 102.6,31.04 98.08,30.83 C 97.67,30.83 97.47,30.36 97.47,29.42 C 97.47,28.47 97.77,28 98.38,28 C 100.03,28 101.99,28.1 104.25,28.3 C 106.34,28.51 108.1,28.61 109.51,28.61 C 111,28.61 112.72,28.51 114.67,28.3 C 116.7,28.1 118.52,28 120.14,28 C 120.61,28 120.85,28.4 120.85,29.21 z"></path>
</svg>

After

Width:  |  Height:  |  Size: 2.3 KiB

View file

@ -0,0 +1,7 @@
<!--
Font Awesome Free 5.2.0 by @fontawesome - https://fontawesome.com
License - https://fontawesome.com/license (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License)
-->
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 384 512">
<path d="M369.9 97.9L286 14C277 5 264.8-.1 252.1-.1H48C21.5 0 0 21.5 0 48v416c0 26.5 21.5 48 48 48h288c26.5 0 48-21.5 48-48V131.9c0-12.7-5.1-25-14.1-34zM332.1 128H256V51.9l76.1 76.1zM48 464V48h160v104c0 13.3 10.7 24 24 24h104v288H48zm250.2-143.7c-12.2-12-47-8.7-64.4-6.5-17.2-10.5-28.7-25-36.8-46.3 3.9-16.1 10.1-40.6 5.4-56-4.2-26.2-37.8-23.6-42.6-5.9-4.4 16.1-.4 38.5 7 67.1-10 23.9-24.9 56-35.4 74.4-20 10.3-47 26.2-51 46.2-3.3 15.8 26 55.2 76.1-31.2 22.4-7.4 46.8-16.5 68.4-20.1 18.9 10.2 41 17 55.8 17 25.5 0 28-28.2 17.5-38.7zm-198.1 77.8c5.1-13.7 24.5-29.5 30.4-35-19 30.3-30.4 35.7-30.4 35zm81.6-190.6c7.4 0 6.7 32.1 1.8 40.8-4.4-13.9-4.3-40.8-1.8-40.8zm-24.4 136.6c9.7-16.9 18-37 24.7-54.7 8.3 15.1 18.9 27.2 30.1 35.5-20.8 4.3-38.9 13.1-54.8 19.2zm131.6-5s-5 6-37.3-7.8c35.1-2.6 40.9 5.4 37.3 7.8z"></path>
</svg>

After

Width:  |  Height:  |  Size: 1 KiB

View file

@ -0,0 +1,10 @@
{% extends 'base.html' %}
{% block content %}
<form method="post">{% csrf_token %}
{{ form.as_p }}
<input type="submit" value="Add">
</form>
{% endblock %}

View file

@ -0,0 +1,108 @@
{% extends 'base.html' %}
{% load static %}
{% block content %}
<h1 class="acronym">{{ acro.name }}</h1>
<p class="fullName">{{ acro.full_name }}</p>
{% if acro.description_html %}
<div class="description">
{{ acro.description_html|safe }}
</div>
{% endif %}
{# <div class="linkwrapper">#}
{# {% for link in acro.links.all %}#}
{# <div><a href="{{ link.url }}">{{ link.url }}</a></div>#}
{# {% endfor %}#}
{# {% for paper in acro.papers.all %}#}
{# <div>#}
{# <a href="{{ paper.ads_url }}">ADS</a>#}
{# <a href="{{ paper.arxiv_url }}">Arxiv</a>#}
{# <a href="{{ paper.doi_url }}">DOI</a>#}
{# </div>#}
{# {% endfor %}#}
<div class="tags">
{% for tag in acro.tags.all %}
<a href="{% url "tag" tag.slug %}" class="badge badge-primary">{{ tag.name }}</a>
{% endfor %}
</div>
<div class="row">
{% for link in acro.wiki_articles.all %}
<div class="mb-4 col-md-4">
<div class="card">
<img src="{{ link.thumbnail.url }}" class="card-img-top"
width="{{ link.thumbnail_width }}" height="{{ link.thumbnail_height }}">
<div class="card-body">
<h5 class="card-title">{{ link.title }}</h5>
{#<p class="card-text">{{ link.extract_html|safe }}</p>#}
<p class="card-text">{{ link.extract }}</p>
<a href="{{ link.url }}" class="btn btn-primary stretched-link">
Read on Wikipedia
</a>
<a href="https://en.wikipedia.org/wiki/Wikipedia:Text_of_Creative_Commons_Attribution-ShareAlike_3.0_Unported_License"
data-toggle="tooltip"
target="_blank" rel="noopener"
class="text-muted"
title="This snippet and thumbnail is from the English Wikipedia and licensed under the under the CC-BY-SA 3.0 license">
License
</a>
</div>
</div>
</div>
{# <div>#}
{# <a href="{{ link.url }}">{% include 'SVGs/icons.html' with list=list1 %}</a>#}
{# <a href="{{ link.url }}">{{ link.title }}</a>#}
{# </div>#}
{% endfor %}
{% for paper in acro.papers.all %}
<div class="mb-4 col-md-4">
<div class="card ">
<div class="card-body">
<h5 class="card-title">{{ paper.title }} ({{ paper.year }})</h5>
<p>{{ paper.authors }}</p>
<div class="linkbar">
<a href="{{ paper.ads_url }}" data-toggle="tooltip" title="view on ADS">
<img src="{% static "ads.ico" %}">
</a>
{% if paper.arxiv_id %}
<a href="{{ paper.arxiv_url }}" data-toggle="tooltip" title="view on arXiv.org">
<img src="{% static "arxiv.ico" %}">
</a>
{% endif %}
{% if paper.doi %}
<a href="{{ paper.doi_url }}" data-toggle="tooltip" title="Publisher Website">
{% include 'SVGs/external.svg' %}
</a>
{% endif %}
<a href="{{ paper.publisher_url }}" data-toggle="tooltip" title="Publisher PDF">
{% include 'SVGs/pdf.svg' %}
</a>
{% if paper.arxiv_id %}
<a href="{{ paper.preprint_url }}" data-toggle="tooltip" title="arXiv.org PDF">
{% include 'SVGs/pdf.svg' %}
</a>
{% endif %}
</div>
</div>
</div>
</div>
{% endfor %}
{% for link in acro.links.all %}
<div class="mb-4 col-md-4">
<div class="card ">
<div class="card-body">
<h5 class="card-title">
{{ link.host.host }}
{% if link.host.icon %}
<img src="{{ link.host.icon.url }}"
width="{{ link.host.icon_width }}" height="{{ link.host.icon_height }}">
{% endif %}
</h5>
<a class="btn btn-primary stretched-link " href="{{ link.url }}">test</a>
</div>
</div>
</div>
{% endfor %}
</div>
<a href="{% url 'admin:acros_acronym_change' acro.id %}">Admin-Edit</a>
{# <a href="{% url 'edit' acro.slug %}">Edit</a>#}
{% endblock %}

View file

@ -0,0 +1,10 @@
{% extends 'base.html' %}
{% block content %}
<form method="post">{% csrf_token %}
{{ form.as_p }}
<input type="submit" value="Update">
</form>
{% endblock %}

View file

@ -0,0 +1,7 @@
{% extends 'base.html' %}
{% block content %}
<h1>Search</h1>
{% endblock %}
{% block searchInput %}autofocus{% endblock %}

View file

@ -0,0 +1,13 @@
{% extends 'base.html' %}
{% block content %}
<dl>
{% for acro in acros %}
<dt><a href="{% url "detail" acro.slug %}">{{ acro.name }}</a></dt>
<dd>{{ acro.full_name }}</dd>
{% endfor %}
</dl>
{% endblock %}

View file

@ -0,0 +1,10 @@
{% extends 'base.html' %}
{% block content %}
<dl>
{% for acro in acros %}
<dt><a href="{% url "detail" acro.slug %}">{{ acro.name }}</a></dt>
<dd>{{ acro.full_name }}</dd>
{% endfor %}
</dl>
{% endblock %}

View file

@ -0,0 +1,9 @@
{% extends 'base.html' %}
{% block content %}
<div class="taglist">
{% for tag in tags %}
<a href="{% url "tag" tag.slug %}" class="badge badge-primary">{{ tag.name }}</a>
{% endfor %}
</div>
{% endblock %}

3
acros/tests.py Normal file
View file

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

35
acros/urls.py Normal file
View file

@ -0,0 +1,35 @@
from django.conf.urls.static import static
from django.urls import path, include
from django.views.generic import RedirectView
from rest_framework import routers
from acronomy import settings
from . import views
router = routers.DefaultRouter()
router.register(r'acronym', views.AcronymViewSet)
router.register(r'tag', views.TagViewSet)
urlpatterns = [
path('', include('django.contrib.auth.urls')),
path('api/', include(router.urls)),
path('', views.IndexView.as_view(), name='index'),
path('acro', RedirectView.as_view(pattern_name="overview")),
path('acro/add', views.AddView.as_view(), name="add"),
path('acro/<str:slug>', views.DetailView.as_view(), name='detail'),
path('acro/<str:slug>/edit', views.EditView.as_view(), name='edit'),
path('acros', views.OverView.as_view(), name='overview'),
path('tags', views.TagListView.as_view(), name='tags'),
path('tag', RedirectView.as_view(pattern_name="tags")),
path('tag/<str:slug>', views.TagAcroView.as_view(), name='tag'),
]
if settings.DEBUG:
import debug_toolbar
urlpatterns = [
path('__debug__/', include(debug_toolbar.urls)),
] + urlpatterns
urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)

137
acros/utils.py Normal file
View file

@ -0,0 +1,137 @@
import markdown
import requests
def md_to_html(md: str) -> str:
html = markdown.markdown(
md,
output_format="html5",
extensions=[
"nl2br"
]
)
return html
def parse_tags(tagstring):
"""
from https://github.com/jazzband/django-taggit/blob/master/taggit/utils.py
django-taggit by Alex Gaynor under BSD License
Parses tag input, with multiple word input being activated and
delineated by commas and double quotes. Quotes take precedence, so
they may contain commas.
Returns a sorted list of unique tag names.
Ported from Jonathan Buchanan's `django-tagging
<http://django-tagging.googlecode.com/>`_
"""
if not tagstring:
return []
# Special case - if there are no commas or double quotes in the
# input, we don't *do* a recall... I mean, we know we only need to
# split on spaces.
if "," not in tagstring and '"' not in tagstring:
words = list(set(split_strip(tagstring, " ")))
words.sort()
return words
words = []
buffer = []
# Defer splitting of non-quoted sections until we know if there are
# any unquoted commas.
to_be_split = []
saw_loose_comma = False
open_quote = False
i = iter(tagstring)
try:
while True:
c = next(i)
if c == '"':
if buffer:
to_be_split.append("".join(buffer))
buffer = []
# Find the matching quote
open_quote = True
c = next(i)
while c != '"':
buffer.append(c)
c = next(i)
if buffer:
word = "".join(buffer).strip()
if word:
words.append(word)
buffer = []
open_quote = False
else:
if not saw_loose_comma and c == ",":
saw_loose_comma = True
buffer.append(c)
except StopIteration:
# If we were parsing an open quote which was never closed treat
# the buffer as unquoted.
if buffer:
if open_quote and "," in buffer:
saw_loose_comma = True
to_be_split.append("".join(buffer))
if to_be_split:
if saw_loose_comma:
delimiter = ","
else:
delimiter = " "
for chunk in to_be_split:
words.extend(split_strip(chunk, delimiter))
words = list(set(words))
words.sort()
return words
def split_strip(string, delimiter=","):
"""
from https://github.com/jazzband/django-taggit/blob/master/taggit/utils.py
django-taggit by Alex Gaynor under BSD License
Splits ``string`` on ``delimiter``, stripping each resulting string
and returning a list of non-empty strings.
Ported from Jonathan Buchanan's `django-tagging
<http://django-tagging.googlecode.com/>`_
"""
if not string:
return []
words = [w.strip() for w in string.split(delimiter)]
return [w for w in words if w]
def edit_string_for_tags(tags):
"""
from https://github.com/jazzband/django-taggit/blob/master/taggit/utils.py
django-taggit by Alex Gaynor under BSD License
Given list of ``Tag`` instances, creates a string representation of
the list suitable for editing by the user, such that submitting the
given string representation back without changing it will give the
same list of tags.
Tag names which contain commas will be double quoted.
If any tag name which isn't being quoted contains whitespace, the
resulting string of tag names will be comma-delimited, otherwise
it will be space-delimited.
Ported from Jonathan Buchanan's `django-tagging
<http://django-tagging.googlecode.com/>`_
"""
names = []
for tag in tags:
name = tag.name
# if "," in name or " " in name:
# names.append(f'"{name}"')
# else:
names.append(name)
return ", ".join(sorted(names))
def fetch_wikipedia_summary(title: str):
r = requests.get("https://en.wikipedia.org/api/rest_v1/page/summary/" + title)
if r.status_code != 200:
raise FileNotFoundError
data = r.json()
print(data)
return data["extract"], data["extract_html"], data["timestamp"], data["thumbnail"]

81
acros/views.py Normal file
View file

@ -0,0 +1,81 @@
from django.contrib.auth.mixins import LoginRequiredMixin
from django.views import generic
from rest_framework import viewsets, filters
from acros.forms import EditForm, AddForm
from acros.models import Acronym, Tag
from acros.serializers import AcronymSerializer, AcronymListSerializer, TagSerializer
class IndexView(generic.TemplateView):
template_name = "acros/index.html"
class OverView(generic.ListView):
template_name = "acros/overview.html"
model = Acronym
context_object_name = 'acros'
ordering = "name"
class DetailView(generic.DetailView):
template_name = 'acros/detail.html'
context_object_name = 'acro'
model = Acronym
class EditView(LoginRequiredMixin, generic.UpdateView):
template_name = 'acros/edit.html'
context_object_name = 'acro'
model = Acronym
# fields = ['name', 'full_name', "description_md", "tags"]
form_class = EditForm
class AddView(LoginRequiredMixin, generic.CreateView):
template_name = "acros/add.html"
form_class = AddForm
model = Acronym
class TagListView(generic.ListView):
template_name = "acros/taglist.html"
model = Tag
context_object_name = 'tags'
ordering = "name"
class TagAcroView(generic.ListView):
template_name = "acros/tagacro.html"
context_object_name = 'acros'
ordering = "name"
def get_queryset(self):
return Acronym.objects.filter(tags__slug__exact=self.kwargs['slug'])
#### API Views ####
class AcronymViewSet(viewsets.ReadOnlyModelViewSet):
"""
API endpoint for viewing Acronyms
"""
queryset = Acronym.objects.all().order_by('name')
serializer_class = AcronymSerializer
serializer_classes = {
'list': AcronymListSerializer,
'retrieve': AcronymSerializer,
}
default_serializer_class = AcronymListSerializer
filter_backends = [filters.SearchFilter]
search_fields = ['name']
def get_serializer_class(self):
return self.serializer_classes.get(self.action, self.default_serializer_class)
class TagViewSet(viewsets.ReadOnlyModelViewSet):
queryset = Tag.objects.all().order_by("name")
serializer_class = TagSerializer

21
manage.py Executable file
View file

@ -0,0 +1,21 @@
#!/usr/bin/env python
"""Django's command-line utility for administrative tasks."""
import os
import sys
def main():
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'acronomy.settings')
try:
from django.core.management import execute_from_command_line
except ImportError as exc:
raise ImportError(
"Couldn't import Django. Are you sure it's installed and "
"available on your PYTHONPATH environment variable? Did you "
"forget to activate a virtual environment?"
) from exc
execute_from_command_line(sys.argv)
if __name__ == '__main__':
main()

9
package.json Normal file
View file

@ -0,0 +1,9 @@
{
"dependencies": {
"@trevoreyre/autocomplete-js": "^2.1.1",
"@yaireo/tagify": "^3.9.3",
"bootstrap": "^4.5.0",
"jquery": "^3.5.1",
"popper.js": "^1.16.1"
}
}

536
poetry.lock generated Normal file
View file

@ -0,0 +1,536 @@
[[package]]
category = "main"
description = "A Python module for NASA's ADS that doesn't suck."
name = "ads"
optional = false
python-versions = "*"
version = "0.12.3"
[package.dependencies]
httpretty = "0.8.10"
mock = "*"
requests = "*"
six = "*"
werkzeug = "*"
[[package]]
category = "main"
description = "The secure Argon2 password hashing algorithm."
name = "argon2-cffi"
optional = false
python-versions = "*"
version = "20.1.0"
[package.dependencies]
cffi = ">=1.0.0"
six = "*"
[package.extras]
dev = ["coverage (>=5.0.2)", "hypothesis", "pytest", "sphinx", "wheel", "pre-commit"]
docs = ["sphinx"]
tests = ["coverage (>=5.0.2)", "hypothesis", "pytest"]
[[package]]
category = "main"
description = "ASGI specs, helper code, and adapters"
name = "asgiref"
optional = false
python-versions = ">=3.5"
version = "3.2.7"
[package.extras]
tests = ["pytest (>=4.3.0,<4.4.0)", "pytest-asyncio (>=0.10.0,<0.11.0)"]
[[package]]
category = "dev"
description = "A thin, practical wrapper around terminal coloring, styling, and positioning"
name = "blessings"
optional = false
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
version = "1.7"
[package.dependencies]
six = "*"
[[package]]
category = "dev"
description = "Fancy Interface to the Python Interpreter"
name = "bpython"
optional = false
python-versions = "*"
version = "0.19"
[package.dependencies]
curtsies = ">=0.1.18"
greenlet = "*"
pygments = "*"
requests = "*"
six = ">=1.5"
[package.extras]
jedi = ["jedi"]
urwid = ["urwid"]
watch = ["watchdog"]
[[package]]
category = "main"
description = "Python package for providing Mozilla's CA Bundle."
name = "certifi"
optional = false
python-versions = "*"
version = "2020.4.5.1"
[[package]]
category = "main"
description = "Foreign Function Interface for Python calling C code."
name = "cffi"
optional = false
python-versions = "*"
version = "1.14.0"
[package.dependencies]
pycparser = "*"
[[package]]
category = "main"
description = "Universal encoding detector for Python 2 and 3"
name = "chardet"
optional = false
python-versions = "*"
version = "3.0.4"
[[package]]
category = "dev"
description = "Curses-like terminal wrapper, with colored strings!"
name = "curtsies"
optional = false
python-versions = "*"
version = "0.3.1"
[package.dependencies]
blessings = ">=1.5"
wcwidth = ">=0.1.4"
[[package]]
category = "main"
description = "A high-level Python Web framework that encourages rapid development and clean, pragmatic design."
name = "django"
optional = false
python-versions = ">=3.6"
version = "3.0.6"
[package.dependencies]
asgiref = ">=3.2,<4.0"
pytz = "*"
sqlparse = ">=0.2.2"
[package.dependencies.argon2-cffi]
optional = true
version = ">=16.1.0"
[package.extras]
argon2 = ["argon2-cffi (>=16.1.0)"]
bcrypt = ["bcrypt"]
[[package]]
category = "main"
description = "A configurable set of panels that display various debug information about the current request/response."
name = "django-debug-toolbar"
optional = false
python-versions = ">=3.5"
version = "2.2"
[package.dependencies]
Django = ">=1.11"
sqlparse = ">=0.2.0"
[[package]]
category = "main"
description = "Store model history and view/revert changes from admin site."
name = "django-simple-history"
optional = false
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
version = "2.10.0"
[package.dependencies]
six = "*"
[[package]]
category = "main"
description = "Web APIs for Django, made easy."
name = "djangorestframework"
optional = false
python-versions = ">=3.5"
version = "3.11.0"
[package.dependencies]
django = ">=1.11"
[[package]]
category = "dev"
description = "Lightweight in-process concurrent programming"
name = "greenlet"
optional = false
python-versions = "*"
version = "0.4.15"
[[package]]
category = "main"
description = "HTTP client mock for Python"
name = "httpretty"
optional = false
python-versions = "*"
version = "0.8.10"
[[package]]
category = "main"
description = "Internationalized Domain Names in Applications (IDNA)"
name = "idna"
optional = false
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
version = "2.9"
[[package]]
category = "main"
description = "Python implementation of Markdown."
name = "markdown"
optional = false
python-versions = ">=3.5"
version = "3.2.2"
[package.extras]
testing = ["coverage", "pyyaml"]
[[package]]
category = "main"
description = "Rolling backport of unittest.mock for all Pythons"
name = "mock"
optional = false
python-versions = ">=3.6"
version = "4.0.2"
[package.extras]
build = ["twine", "wheel", "blurb"]
docs = ["sphinx"]
test = ["pytest", "pytest-cov"]
[[package]]
category = "main"
description = "Python Imaging Library (Fork)"
name = "pillow"
optional = false
python-versions = ">=3.5"
version = "7.1.2"
[[package]]
category = "main"
description = "psycopg2 - Python-PostgreSQL Database Adapter"
name = "psycopg2"
optional = false
python-versions = ">=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*"
version = "2.8.5"
[[package]]
category = "main"
description = "C parser in Python"
name = "pycparser"
optional = false
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
version = "2.20"
[[package]]
category = "dev"
description = "Pygments is a syntax highlighting package written in Python."
name = "pygments"
optional = false
python-versions = ">=3.5"
version = "2.6.1"
[[package]]
category = "main"
description = "World timezone definitions, modern and historical"
name = "pytz"
optional = false
python-versions = "*"
version = "2020.1"
[[package]]
category = "main"
description = "Python HTTP for Humans."
name = "requests"
optional = false
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
version = "2.23.0"
[package.dependencies]
certifi = ">=2017.4.17"
chardet = ">=3.0.2,<4"
idna = ">=2.5,<3"
urllib3 = ">=1.21.1,<1.25.0 || >1.25.0,<1.25.1 || >1.25.1,<1.26"
[package.extras]
security = ["pyOpenSSL (>=0.14)", "cryptography (>=1.3.4)"]
socks = ["PySocks (>=1.5.6,<1.5.7 || >1.5.7)", "win-inet-pton"]
[[package]]
category = "main"
description = "Python 2 and 3 compatibility utilities"
name = "six"
optional = false
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*"
version = "1.15.0"
[[package]]
category = "main"
description = "Non-validating SQL parser"
name = "sqlparse"
optional = false
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
version = "0.3.1"
[[package]]
category = "main"
description = "HTTP library with thread-safe connection pooling, file post, and more."
name = "urllib3"
optional = false
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, <4"
version = "1.25.9"
[package.extras]
brotli = ["brotlipy (>=0.6.0)"]
secure = ["certifi", "cryptography (>=1.3.4)", "idna (>=2.0.0)", "pyOpenSSL (>=0.14)", "ipaddress"]
socks = ["PySocks (>=1.5.6,<1.5.7 || >1.5.7,<2.0)"]
[[package]]
category = "dev"
description = "Measures number of Terminal column cells of wide-character codes"
name = "wcwidth"
optional = false
python-versions = "*"
version = "0.1.9"
[[package]]
category = "main"
description = "The comprehensive WSGI web application library."
name = "werkzeug"
optional = false
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
version = "1.0.1"
[package.extras]
dev = ["pytest", "pytest-timeout", "coverage", "tox", "sphinx", "pallets-sphinx-themes", "sphinx-issues"]
watchdog = ["watchdog"]
[metadata]
content-hash = "497bc3dd469c7cd0db589529e5e7ee0cba2fa9fec713ee7967bc7ba8490e26ab"
python-versions = "^3.8"
[metadata.files]
ads = [
{file = "ads-0.12.3.tar.gz", hash = "sha256:ce523f266f6b815bf1d6371b6e7791b4d10989ebe743681b27bd54301f7cdcc9"},
]
argon2-cffi = [
{file = "argon2-cffi-20.1.0.tar.gz", hash = "sha256:d8029b2d3e4b4cea770e9e5a0104dd8fa185c1724a0f01528ae4826a6d25f97d"},
{file = "argon2_cffi-20.1.0-cp27-cp27m-macosx_10_6_intel.whl", hash = "sha256:6ea92c980586931a816d61e4faf6c192b4abce89aa767ff6581e6ddc985ed003"},
{file = "argon2_cffi-20.1.0-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:05a8ac07c7026542377e38389638a8a1e9b78f1cd8439cd7493b39f08dd75fbf"},
{file = "argon2_cffi-20.1.0-cp27-cp27m-win32.whl", hash = "sha256:0bf066bc049332489bb2d75f69216416329d9dc65deee127152caeb16e5ce7d5"},
{file = "argon2_cffi-20.1.0-cp27-cp27m-win_amd64.whl", hash = "sha256:57358570592c46c420300ec94f2ff3b32cbccd10d38bdc12dc6979c4a8484fbc"},
{file = "argon2_cffi-20.1.0-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:7d455c802727710e9dfa69b74ccaab04568386ca17b0ad36350b622cd34606fe"},
{file = "argon2_cffi-20.1.0-cp35-abi3-manylinux1_x86_64.whl", hash = "sha256:b160416adc0f012fb1f12588a5e6954889510f82f698e23ed4f4fa57f12a0647"},
{file = "argon2_cffi-20.1.0-cp35-cp35m-win32.whl", hash = "sha256:9bee3212ba4f560af397b6d7146848c32a800652301843df06b9e8f68f0f7361"},
{file = "argon2_cffi-20.1.0-cp35-cp35m-win_amd64.whl", hash = "sha256:392c3c2ef91d12da510cfb6f9bae52512a4552573a9e27600bdb800e05905d2b"},
{file = "argon2_cffi-20.1.0-cp36-cp36m-win32.whl", hash = "sha256:ba7209b608945b889457f949cc04c8e762bed4fe3fec88ae9a6b7765ae82e496"},
{file = "argon2_cffi-20.1.0-cp36-cp36m-win_amd64.whl", hash = "sha256:da7f0445b71db6d3a72462e04f36544b0de871289b0bc8a7cc87c0f5ec7079fa"},
{file = "argon2_cffi-20.1.0-cp37-abi3-macosx_10_6_intel.whl", hash = "sha256:cc0e028b209a5483b6846053d5fd7165f460a1f14774d79e632e75e7ae64b82b"},
{file = "argon2_cffi-20.1.0-cp37-cp37m-win32.whl", hash = "sha256:18dee20e25e4be86680b178b35ccfc5d495ebd5792cd00781548d50880fee5c5"},
{file = "argon2_cffi-20.1.0-cp37-cp37m-win_amd64.whl", hash = "sha256:6678bb047373f52bcff02db8afab0d2a77d83bde61cfecea7c5c62e2335cb203"},
{file = "argon2_cffi-20.1.0-cp38-cp38-win32.whl", hash = "sha256:77e909cc756ef81d6abb60524d259d959bab384832f0c651ed7dcb6e5ccdbb78"},
{file = "argon2_cffi-20.1.0-cp38-cp38-win_amd64.whl", hash = "sha256:9dfd5197852530294ecb5795c97a823839258dfd5eb9420233c7cfedec2058f2"},
]
asgiref = [
{file = "asgiref-3.2.7-py2.py3-none-any.whl", hash = "sha256:9ca8b952a0a9afa61d30aa6d3d9b570bb3fd6bafcf7ec9e6bed43b936133db1c"},
{file = "asgiref-3.2.7.tar.gz", hash = "sha256:8036f90603c54e93521e5777b2b9a39ba1bad05773fcf2d208f0299d1df58ce5"},
]
blessings = [
{file = "blessings-1.7-py2-none-any.whl", hash = "sha256:caad5211e7ba5afe04367cdd4cfc68fa886e2e08f6f35e76b7387d2109ccea6e"},
{file = "blessings-1.7-py3-none-any.whl", hash = "sha256:b1fdd7e7a675295630f9ae71527a8ebc10bfefa236b3d6aa4932ee4462c17ba3"},
{file = "blessings-1.7.tar.gz", hash = "sha256:98e5854d805f50a5b58ac2333411b0482516a8210f23f43308baeb58d77c157d"},
]
bpython = [
{file = "bpython-0.19-py2.py3-none-any.whl", hash = "sha256:95d95783bfadfa0a25300a648de5aba4423b0ee76b034022a81dde2b5e853c00"},
{file = "bpython-0.19.tar.gz", hash = "sha256:476ce09a896c4d34bf5e56aca64650c56fdcfce45781a20dc1521221df8cc49c"},
]
certifi = [
{file = "certifi-2020.4.5.1-py2.py3-none-any.whl", hash = "sha256:1d987a998c75633c40847cc966fcf5904906c920a7f17ef374f5aa4282abd304"},
{file = "certifi-2020.4.5.1.tar.gz", hash = "sha256:51fcb31174be6e6664c5f69e3e1691a2d72a1a12e90f872cbdb1567eb47b6519"},
]
cffi = [
{file = "cffi-1.14.0-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:1cae98a7054b5c9391eb3249b86e0e99ab1e02bb0cc0575da191aedadbdf4384"},
{file = "cffi-1.14.0-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:cf16e3cf6c0a5fdd9bc10c21687e19d29ad1fe863372b5543deaec1039581a30"},
{file = "cffi-1.14.0-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:f2b0fa0c01d8a0c7483afd9f31d7ecf2d71760ca24499c8697aeb5ca37dc090c"},
{file = "cffi-1.14.0-cp27-cp27m-win32.whl", hash = "sha256:99f748a7e71ff382613b4e1acc0ac83bf7ad167fb3802e35e90d9763daba4d78"},
{file = "cffi-1.14.0-cp27-cp27m-win_amd64.whl", hash = "sha256:c420917b188a5582a56d8b93bdd8e0f6eca08c84ff623a4c16e809152cd35793"},
{file = "cffi-1.14.0-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:399aed636c7d3749bbed55bc907c3288cb43c65c4389964ad5ff849b6370603e"},
{file = "cffi-1.14.0-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:cab50b8c2250b46fe738c77dbd25ce017d5e6fb35d3407606e7a4180656a5a6a"},
{file = "cffi-1.14.0-cp35-cp35m-macosx_10_9_x86_64.whl", hash = "sha256:001bf3242a1bb04d985d63e138230802c6c8d4db3668fb545fb5005ddf5bb5ff"},
{file = "cffi-1.14.0-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:e56c744aa6ff427a607763346e4170629caf7e48ead6921745986db3692f987f"},
{file = "cffi-1.14.0-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:b8c78301cefcf5fd914aad35d3c04c2b21ce8629b5e4f4e45ae6812e461910fa"},
{file = "cffi-1.14.0-cp35-cp35m-win32.whl", hash = "sha256:8c0ffc886aea5df6a1762d0019e9cb05f825d0eec1f520c51be9d198701daee5"},
{file = "cffi-1.14.0-cp35-cp35m-win_amd64.whl", hash = "sha256:8a6c688fefb4e1cd56feb6c511984a6c4f7ec7d2a1ff31a10254f3c817054ae4"},
{file = "cffi-1.14.0-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:95cd16d3dee553f882540c1ffe331d085c9e629499ceadfbda4d4fde635f4b7d"},
{file = "cffi-1.14.0-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:66e41db66b47d0d8672d8ed2708ba91b2f2524ece3dee48b5dfb36be8c2f21dc"},
{file = "cffi-1.14.0-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:028a579fc9aed3af38f4892bdcc7390508adabc30c6af4a6e4f611b0c680e6ac"},
{file = "cffi-1.14.0-cp36-cp36m-win32.whl", hash = "sha256:cef128cb4d5e0b3493f058f10ce32365972c554572ff821e175dbc6f8ff6924f"},
{file = "cffi-1.14.0-cp36-cp36m-win_amd64.whl", hash = "sha256:337d448e5a725bba2d8293c48d9353fc68d0e9e4088d62a9571def317797522b"},
{file = "cffi-1.14.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:e577934fc5f8779c554639376beeaa5657d54349096ef24abe8c74c5d9c117c3"},
{file = "cffi-1.14.0-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:62ae9af2d069ea2698bf536dcfe1e4eed9090211dbaafeeedf5cb6c41b352f66"},
{file = "cffi-1.14.0-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:14491a910663bf9f13ddf2bc8f60562d6bc5315c1f09c704937ef17293fb85b0"},
{file = "cffi-1.14.0-cp37-cp37m-win32.whl", hash = "sha256:c43866529f2f06fe0edc6246eb4faa34f03fe88b64a0a9a942561c8e22f4b71f"},
{file = "cffi-1.14.0-cp37-cp37m-win_amd64.whl", hash = "sha256:2089ed025da3919d2e75a4d963d008330c96751127dd6f73c8dc0c65041b4c26"},
{file = "cffi-1.14.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:3b911c2dbd4f423b4c4fcca138cadde747abdb20d196c4a48708b8a2d32b16dd"},
{file = "cffi-1.14.0-cp38-cp38-manylinux1_i686.whl", hash = "sha256:7e63cbcf2429a8dbfe48dcc2322d5f2220b77b2e17b7ba023d6166d84655da55"},
{file = "cffi-1.14.0-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:3d311bcc4a41408cf5854f06ef2c5cab88f9fded37a3b95936c9879c1640d4c2"},
{file = "cffi-1.14.0-cp38-cp38-win32.whl", hash = "sha256:675686925a9fb403edba0114db74e741d8181683dcf216be697d208857e04ca8"},
{file = "cffi-1.14.0-cp38-cp38-win_amd64.whl", hash = "sha256:00789914be39dffba161cfc5be31b55775de5ba2235fe49aa28c148236c4e06b"},
{file = "cffi-1.14.0.tar.gz", hash = "sha256:2d384f4a127a15ba701207f7639d94106693b6cd64173d6c8988e2c25f3ac2b6"},
]
chardet = [
{file = "chardet-3.0.4-py2.py3-none-any.whl", hash = "sha256:fc323ffcaeaed0e0a02bf4d117757b98aed530d9ed4531e3e15460124c106691"},
{file = "chardet-3.0.4.tar.gz", hash = "sha256:84ab92ed1c4d4f16916e05906b6b75a6c0fb5db821cc65e70cbd64a3e2a5eaae"},
]
curtsies = [
{file = "curtsies-0.3.1-py2.py3-none-any.whl", hash = "sha256:9169d734323a1356e7563b1ca0bff3c5358c1b1dcce52506a9d4d8ab8a8f5604"},
{file = "curtsies-0.3.1.tar.gz", hash = "sha256:b2c913a8113c4382e1a221679f2338139b112839deb16c00ee873e57a4b33bd4"},
]
django = [
{file = "Django-3.0.6-py3-none-any.whl", hash = "sha256:051ba55d42daa3eeda3944a8e4df2bc96d4c62f94316dea217248a22563c3621"},
{file = "Django-3.0.6.tar.gz", hash = "sha256:9aaa6a09678e1b8f0d98a948c56482eac3e3dd2ddbfb8de70a868135ef3b5e01"},
]
django-debug-toolbar = [
{file = "django-debug-toolbar-2.2.tar.gz", hash = "sha256:eabbefe89881bbe4ca7c980ff102e3c35c8e8ad6eb725041f538988f2f39a943"},
{file = "django_debug_toolbar-2.2-py3-none-any.whl", hash = "sha256:ff94725e7aae74b133d0599b9bf89bd4eb8f5d2c964106e61d11750228c8774c"},
]
django-simple-history = [
{file = "django-simple-history-2.10.0.tar.gz", hash = "sha256:1b970298e743270e5715c88b17209421c6954603d31da5cd9a11825b016ebd26"},
{file = "django_simple_history-2.10.0-py2.py3-none-any.whl", hash = "sha256:8585bd0d0145df816657348ad62f753444b3b9a970a2064fb92dc4cb876c5049"},
]
djangorestframework = [
{file = "djangorestframework-3.11.0-py3-none-any.whl", hash = "sha256:05809fc66e1c997fd9a32ea5730d9f4ba28b109b9da71fccfa5ff241201fd0a4"},
{file = "djangorestframework-3.11.0.tar.gz", hash = "sha256:e782087823c47a26826ee5b6fa0c542968219263fb3976ec3c31edab23a4001f"},
]
greenlet = [
{file = "greenlet-0.4.15-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:99a26afdb82ea83a265137a398f570402aa1f2b5dfb4ac3300c026931817b163"},
{file = "greenlet-0.4.15-cp27-cp27m-win32.whl", hash = "sha256:beeabe25c3b704f7d56b573f7d2ff88fc99f0138e43480cecdfcaa3b87fe4f87"},
{file = "greenlet-0.4.15-cp27-cp27m-win_amd64.whl", hash = "sha256:9854f612e1b59ec66804931df5add3b2d5ef0067748ea29dc60f0efdcda9a638"},
{file = "greenlet-0.4.15-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:ac57fcdcfb0b73bb3203b58a14501abb7e5ff9ea5e2edfa06bb03035f0cff248"},
{file = "greenlet-0.4.15-cp33-cp33m-win32.whl", hash = "sha256:d634a7ea1fc3380ff96f9e44d8d22f38418c1c381d5fac680b272d7d90883720"},
{file = "greenlet-0.4.15-cp33-cp33m-win_amd64.whl", hash = "sha256:0d48200bc50cbf498716712129eef819b1729339e34c3ae71656964dac907c28"},
{file = "greenlet-0.4.15-cp34-cp34m-manylinux1_x86_64.whl", hash = "sha256:bcb530089ff24f6458a81ac3fa699e8c00194208a724b644ecc68422e1111939"},
{file = "greenlet-0.4.15-cp34-cp34m-win32.whl", hash = "sha256:8b4572c334593d449113f9dc8d19b93b7b271bdbe90ba7509eb178923327b625"},
{file = "greenlet-0.4.15-cp34-cp34m-win_amd64.whl", hash = "sha256:a9f145660588187ff835c55a7d2ddf6abfc570c2651c276d3d4be8a2766db490"},
{file = "greenlet-0.4.15-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:51503524dd6f152ab4ad1fbd168fc6c30b5795e8c70be4410a64940b3abb55c0"},
{file = "greenlet-0.4.15-cp35-cp35m-win32.whl", hash = "sha256:a19bf883b3384957e4a4a13e6bd1ae3d85ae87f4beb5957e35b0be287f12f4e4"},
{file = "greenlet-0.4.15-cp35-cp35m-win_amd64.whl", hash = "sha256:853da4f9563d982e4121fed8c92eea1a4594a2299037b3034c3c898cb8e933d6"},
{file = "greenlet-0.4.15-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:23d12eacffa9d0f290c0fe0c4e81ba6d5f3a5b7ac3c30a5eaf0126bf4deda5c8"},
{file = "greenlet-0.4.15-cp36-cp36m-win32.whl", hash = "sha256:000546ad01e6389e98626c1367be58efa613fa82a1be98b0c6fc24b563acc6d0"},
{file = "greenlet-0.4.15-cp36-cp36m-win_amd64.whl", hash = "sha256:d97b0661e1aead761f0ded3b769044bb00ed5d33e1ec865e891a8b128bf7c656"},
{file = "greenlet-0.4.15-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:8041e2de00e745c0e05a502d6e6db310db7faa7c979b3a5877123548a4c0b214"},
{file = "greenlet-0.4.15-cp37-cp37m-win32.whl", hash = "sha256:81fcd96a275209ef117e9ec91f75c731fa18dcfd9ffaa1c0adbdaa3616a86043"},
{file = "greenlet-0.4.15-cp37-cp37m-win_amd64.whl", hash = "sha256:37c9ba82bd82eb6a23c2e5acc03055c0e45697253b2393c9a50cef76a3985304"},
{file = "greenlet-0.4.15-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:e538b8dae561080b542b0f5af64d47ef859f22517f7eca617bb314e0e03fd7ef"},
{file = "greenlet-0.4.15-cp38-cp38-win32.whl", hash = "sha256:51155342eb4d6058a0ffcd98a798fe6ba21195517da97e15fca3db12ab201e6e"},
{file = "greenlet-0.4.15-cp38-cp38-win_amd64.whl", hash = "sha256:7457d685158522df483196b16ec648b28f8e847861adb01a55d41134e7734122"},
{file = "greenlet-0.4.15.tar.gz", hash = "sha256:9416443e219356e3c31f1f918a91badf2e37acf297e2fa13d24d1cc2380f8fbc"},
]
httpretty = [
{file = "httpretty-0.8.10-py2-none-any.whl", hash = "sha256:77cbd62e20cb47f1c66125531aedcb80c3141dc10c5b24779389693cfc8bc3a2"},
{file = "httpretty-0.8.10.tar.gz", hash = "sha256:474a72722d66841f0e59cee285d837e1c6263be5be7bf2f8e824fc849a99adda"},
]
idna = [
{file = "idna-2.9-py2.py3-none-any.whl", hash = "sha256:a068a21ceac8a4d63dbfd964670474107f541babbd2250d61922f029858365fa"},
{file = "idna-2.9.tar.gz", hash = "sha256:7588d1c14ae4c77d74036e8c22ff447b26d0fde8f007354fd48a7814db15b7cb"},
]
markdown = [
{file = "Markdown-3.2.2-py3-none-any.whl", hash = "sha256:c467cd6233885534bf0fe96e62e3cf46cfc1605112356c4f9981512b8174de59"},
{file = "Markdown-3.2.2.tar.gz", hash = "sha256:1fafe3f1ecabfb514a5285fca634a53c1b32a81cb0feb154264d55bf2ff22c17"},
]
mock = [
{file = "mock-4.0.2-py3-none-any.whl", hash = "sha256:3f9b2c0196c60d21838f307f5825a7b86b678cedc58ab9e50a8988187b4d81e0"},
{file = "mock-4.0.2.tar.gz", hash = "sha256:dd33eb70232b6118298d516bbcecd26704689c386594f0f3c4f13867b2c56f72"},
]
pillow = [
{file = "Pillow-7.1.2-cp35-cp35m-macosx_10_10_intel.whl", hash = "sha256:ae2b270f9a0b8822b98655cb3a59cdb1bd54a34807c6c56b76dd2e786c3b7db3"},
{file = "Pillow-7.1.2-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:d23e2aa9b969cf9c26edfb4b56307792b8b374202810bd949effd1c6e11ebd6d"},
{file = "Pillow-7.1.2-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:b532bcc2f008e96fd9241177ec580829dee817b090532f43e54074ecffdcd97f"},
{file = "Pillow-7.1.2-cp35-cp35m-win32.whl", hash = "sha256:12e4bad6bddd8546a2f9771485c7e3d2b546b458ae8ff79621214119ac244523"},
{file = "Pillow-7.1.2-cp35-cp35m-win_amd64.whl", hash = "sha256:9744350687459234867cbebfe9df8f35ef9e1538f3e729adbd8fde0761adb705"},
{file = "Pillow-7.1.2-cp36-cp36m-macosx_10_10_x86_64.whl", hash = "sha256:f54be399340aa602066adb63a86a6a5d4f395adfdd9da2b9a0162ea808c7b276"},
{file = "Pillow-7.1.2-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:1f694e28c169655c50bb89a3fa07f3b854d71eb47f50783621de813979ba87f3"},
{file = "Pillow-7.1.2-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:f784aad988f12c80aacfa5b381ec21fd3f38f851720f652b9f33facc5101cf4d"},
{file = "Pillow-7.1.2-cp36-cp36m-win32.whl", hash = "sha256:b37bb3bd35edf53125b0ff257822afa6962649995cbdfde2791ddb62b239f891"},
{file = "Pillow-7.1.2-cp36-cp36m-win_amd64.whl", hash = "sha256:b67a6c47ed963c709ed24566daa3f95a18f07d3831334da570c71da53d97d088"},
{file = "Pillow-7.1.2-cp37-cp37m-macosx_10_10_x86_64.whl", hash = "sha256:eaa83729eab9c60884f362ada982d3a06beaa6cc8b084cf9f76cae7739481dfa"},
{file = "Pillow-7.1.2-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:f46e0e024346e1474083c729d50de909974237c72daca05393ee32389dabe457"},
{file = "Pillow-7.1.2-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:0e2a3bceb0fd4e0cb17192ae506d5f082b309ffe5fc370a5667959c9b2f85fa3"},
{file = "Pillow-7.1.2-cp37-cp37m-win32.whl", hash = "sha256:ccc9ad2460eb5bee5642eaf75a0438d7f8887d484490d5117b98edd7f33118b7"},
{file = "Pillow-7.1.2-cp37-cp37m-win_amd64.whl", hash = "sha256:b943e71c2065ade6fef223358e56c167fc6ce31c50bc7a02dd5c17ee4338e8ac"},
{file = "Pillow-7.1.2-cp38-cp38-macosx_10_10_x86_64.whl", hash = "sha256:04766c4930c174b46fd72d450674612ab44cca977ebbcc2dde722c6933290107"},
{file = "Pillow-7.1.2-cp38-cp38-manylinux1_i686.whl", hash = "sha256:f455efb7a98557412dc6f8e463c1faf1f1911ec2432059fa3e582b6000fc90e2"},
{file = "Pillow-7.1.2-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:ee94fce8d003ac9fd206496f2707efe9eadcb278d94c271f129ab36aa7181344"},
{file = "Pillow-7.1.2-cp38-cp38-win32.whl", hash = "sha256:4b02b9c27fad2054932e89f39703646d0c543f21d3cc5b8e05434215121c28cd"},
{file = "Pillow-7.1.2-cp38-cp38-win_amd64.whl", hash = "sha256:3d25dd8d688f7318dca6d8cd4f962a360ee40346c15893ae3b95c061cdbc4079"},
{file = "Pillow-7.1.2-pp373-pypy36_pp73-win32.whl", hash = "sha256:0f01e63c34f0e1e2580cc0b24e86a5ccbbfa8830909a52ee17624c4193224cd9"},
{file = "Pillow-7.1.2-py3.8-macosx-10.9-x86_64.egg", hash = "sha256:70e3e0d99a0dcda66283a185f80697a9b08806963c6149c8e6c5f452b2aa59c0"},
{file = "Pillow-7.1.2.tar.gz", hash = "sha256:a0b49960110bc6ff5fead46013bcb8825d101026d466f3a4de3476defe0fb0dd"},
]
psycopg2 = [
{file = "psycopg2-2.8.5-cp27-cp27m-win32.whl", hash = "sha256:a0984ff49e176062fcdc8a5a2a670c9bb1704a2f69548bce8f8a7bad41c661bf"},
{file = "psycopg2-2.8.5-cp27-cp27m-win_amd64.whl", hash = "sha256:acf56d564e443e3dea152efe972b1434058244298a94348fc518d6dd6a9fb0bb"},
{file = "psycopg2-2.8.5-cp34-cp34m-win32.whl", hash = "sha256:440a3ea2c955e89321a138eb7582aa1d22fe286c7d65e26a2c5411af0a88ae72"},
{file = "psycopg2-2.8.5-cp34-cp34m-win_amd64.whl", hash = "sha256:6b306dae53ec7f4f67a10942cf8ac85de930ea90e9903e2df4001f69b7833f7e"},
{file = "psycopg2-2.8.5-cp35-cp35m-win32.whl", hash = "sha256:d3b29d717d39d3580efd760a9a46a7418408acebbb784717c90d708c9ed5f055"},
{file = "psycopg2-2.8.5-cp35-cp35m-win_amd64.whl", hash = "sha256:6a471d4d2a6f14c97a882e8d3124869bc623f3df6177eefe02994ea41fd45b52"},
{file = "psycopg2-2.8.5-cp36-cp36m-win32.whl", hash = "sha256:27c633f2d5db0fc27b51f1b08f410715b59fa3802987aec91aeb8f562724e95c"},
{file = "psycopg2-2.8.5-cp36-cp36m-win_amd64.whl", hash = "sha256:2df2bf1b87305bd95eb3ac666ee1f00a9c83d10927b8144e8e39644218f4cf81"},
{file = "psycopg2-2.8.5-cp37-cp37m-win32.whl", hash = "sha256:ac5b23d0199c012ad91ed1bbb971b7666da651c6371529b1be8cbe2a7bf3c3a9"},
{file = "psycopg2-2.8.5-cp37-cp37m-win_amd64.whl", hash = "sha256:2c0afb40cfb4d53487ee2ebe128649028c9a78d2476d14a67781e45dc287f080"},
{file = "psycopg2-2.8.5-cp38-cp38-win32.whl", hash = "sha256:2327bf42c1744a434ed8ed0bbaa9168cac7ee5a22a9001f6fc85c33b8a4a14b7"},
{file = "psycopg2-2.8.5-cp38-cp38-win_amd64.whl", hash = "sha256:132efc7ee46a763e68a815f4d26223d9c679953cd190f1f218187cb60decf535"},
{file = "psycopg2-2.8.5.tar.gz", hash = "sha256:f7d46240f7a1ae1dd95aab38bd74f7428d46531f69219954266d669da60c0818"},
]
pycparser = [
{file = "pycparser-2.20-py2.py3-none-any.whl", hash = "sha256:7582ad22678f0fcd81102833f60ef8d0e57288b6b5fb00323d101be910e35705"},
{file = "pycparser-2.20.tar.gz", hash = "sha256:2d475327684562c3a96cc71adf7dc8c4f0565175cf86b6d7a404ff4c771f15f0"},
]
pygments = [
{file = "Pygments-2.6.1-py3-none-any.whl", hash = "sha256:ff7a40b4860b727ab48fad6360eb351cc1b33cbf9b15a0f689ca5353e9463324"},
{file = "Pygments-2.6.1.tar.gz", hash = "sha256:647344a061c249a3b74e230c739f434d7ea4d8b1d5f3721bc0f3558049b38f44"},
]
pytz = [
{file = "pytz-2020.1-py2.py3-none-any.whl", hash = "sha256:a494d53b6d39c3c6e44c3bec237336e14305e4f29bbf800b599253057fbb79ed"},
{file = "pytz-2020.1.tar.gz", hash = "sha256:c35965d010ce31b23eeb663ed3cc8c906275d6be1a34393a1d73a41febf4a048"},
]
requests = [
{file = "requests-2.23.0-py2.py3-none-any.whl", hash = "sha256:43999036bfa82904b6af1d99e4882b560e5e2c68e5c4b0aa03b655f3d7d73fee"},
{file = "requests-2.23.0.tar.gz", hash = "sha256:b3f43d496c6daba4493e7c431722aeb7dbc6288f52a6e04e7b6023b0247817e6"},
]
six = [
{file = "six-1.15.0-py2.py3-none-any.whl", hash = "sha256:8b74bedcbbbaca38ff6d7491d76f2b06b3592611af620f8426e82dddb04a5ced"},
{file = "six-1.15.0.tar.gz", hash = "sha256:30639c035cdb23534cd4aa2dd52c3bf48f06e5f4a941509c8bafd8ce11080259"},
]
sqlparse = [
{file = "sqlparse-0.3.1-py2.py3-none-any.whl", hash = "sha256:022fb9c87b524d1f7862b3037e541f68597a730a8843245c349fc93e1643dc4e"},
{file = "sqlparse-0.3.1.tar.gz", hash = "sha256:e162203737712307dfe78860cc56c8da8a852ab2ee33750e33aeadf38d12c548"},
]
urllib3 = [
{file = "urllib3-1.25.9-py2.py3-none-any.whl", hash = "sha256:88206b0eb87e6d677d424843ac5209e3fb9d0190d0ee169599165ec25e9d9115"},
{file = "urllib3-1.25.9.tar.gz", hash = "sha256:3018294ebefce6572a474f0604c2021e33b3fd8006ecd11d62107a5d2a963527"},
]
wcwidth = [
{file = "wcwidth-0.1.9-py2.py3-none-any.whl", hash = "sha256:cafe2186b3c009a04067022ce1dcd79cb38d8d65ee4f4791b8888d6599d1bbe1"},
{file = "wcwidth-0.1.9.tar.gz", hash = "sha256:ee73862862a156bf77ff92b09034fc4825dd3af9cf81bc5b360668d425f3c5f1"},
]
werkzeug = [
{file = "Werkzeug-1.0.1-py2.py3-none-any.whl", hash = "sha256:2de2a5db0baeae7b2d2664949077c2ac63fbd16d98da0ff71837f7d1dea3fd43"},
{file = "Werkzeug-1.0.1.tar.gz", hash = "sha256:6c80b1e5ad3665290ea39320b91e1be1e0d5f60652b964a3070216de83d2e47c"},
]

24
pyproject.toml Normal file
View file

@ -0,0 +1,24 @@
[tool.poetry]
name = "acronomy"
version = "0.1.0"
description = ""
authors = ["Lukas Winkler <git@lw1.at>"]
[tool.poetry.dependencies]
python = "^3.8"
django = {extras = ["argon2"], version = "^3.0.6"}
psycopg2 = "^2.8.5"
django-simple-history = "^2.10.0"
markdown = "^3.2.2"
django-debug-toolbar = "^2.2"
djangorestframework = "^3.11.0"
requests = "^2.23.0"
ads = "^0.12.3"
Pillow = "^7.1.2"
[tool.poetry.dev-dependencies]
bpython = "^0.19"
[build-system]
requires = ["poetry>=0.12"]
build-backend = "poetry.masonry.api"

BIN
static/ads.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.3 KiB

71
static/app.js Normal file
View file

@ -0,0 +1,71 @@
$(function () {
$('[data-toggle="tooltip"]').tooltip()
})
new Autocomplete('#autocomplete', {
// Search function can return a promise
// which resolves with an array of
// results. In this case we're using
// the Wikipedia search API.
search: input => {
const url = "/api/acronym/?search=" + input
return new Promise(resolve => {
if (input.length < 1) {
return resolve([])
}
fetch(url)
.then(response => response.json())
.then(data => {
resolve(data)
})
})
},
getResultValue: result => (result.name + ": " + result.full_name),
// Open the selected article in
// a new window
onSubmit: result => {
console.log(result)
window.location = "/acro/" + result.slug
},
autoSelect: true,
})
const input = document.querySelector('input[name="tags"]')
document.querySelector("form").addEventListener("submit", function () {
const list = JSON.parse(input.value).map(function (item) {
return item['value'];
})
input.value = JSON.parse(input.value).map(function (item) {
return item['value'];
})
console.log(input.value)
return false;
})
const tagify = new Tagify(input, {
whitelist: [],
maxTags: 10,
dropdown: {
maxItems: 20,
enabled: 0
}
})
fetch("/api/tag/")
.then(response => response.json())
.then(data =>
data.map(function (item) {
return item['name'];
})
)
.then(data => {
tagify.settings.whitelist = data
})

BIN
static/arxiv.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB

51
static/login.css Normal file
View file

@ -0,0 +1,51 @@
/** from https://getbootstrap.com/docs/4.3/examples/sign-in/signin.css */
html,
body {
height: 100%;
}
body {
display: -ms-flexbox;
display: flex;
-ms-flex-align: center;
align-items: center;
padding-top: 40px;
padding-bottom: 40px;
background-color: #f5f5f5;
}
.form-signin {
width: 100%;
max-width: 330px;
padding: 15px;
margin: auto;
}
.form-signin .checkbox {
font-weight: 400;
}
.form-signin .form-control {
position: relative;
box-sizing: border-box;
height: auto;
padding: 10px;
font-size: 16px;
}
.form-signin .form-control:focus {
z-index: 2;
}
.form-signin input[type="email"] {
margin-bottom: -1px;
border-bottom-right-radius: 0;
border-bottom-left-radius: 0;
}
.form-signin input[type="password"] {
margin-bottom: 10px;
border-top-left-radius: 0;
border-top-right-radius: 0;
}

75
static/style.css Normal file
View file

@ -0,0 +1,75 @@
.accountStatus {
position: absolute;
top: 20px;
right: 20px;
}
h1 {
text-align: center;
}
h1.acronym {
font-size: 4rem;
}
.fullName {
text-align: center;
font-size: 2rem;
}
/*.linkwrapper {*/
/* display: flex;*/
/* flex-direction: column;*/
/*}*/
/*.linkwrapper div {*/
/* display: flex;*/
/* align-items: center;*/
/*}*/
.card-title {
text-align: center;
}
.card-title img {
max-width: 32px;
height: auto;
}
.card-img-top {
height: auto;
}
.card-body a {
display: block;
text-align: center;
}
.linkbar {
display: flex;
justify-content: space-between;
}
.linkbar a {
display: block;
}
.linkbar img, .linkbar svg {
width: 26px;
height: 26px;
padding: 5px;
}
.tags{
margin-bottom: 2rem;
}
.taglist {
display: flex;
flex-wrap: wrap;
justify-content: space-around;
}
.taglist .badge {
font-size: 150%;
margin: 5px;
}

42
templates/base.html Normal file
View file

@ -0,0 +1,42 @@
{% load static %}
<!DOCTYPE html>
<html lang="de">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<!-- The above 3 meta tags *must* come first in the head; any other head content must come *after* these tags -->
<title>{% block title %}Acronomy{% endblock %}</title>
<!-- Bootstrap -->
<link rel="stylesheet" href="{% static "css/bootstrap.min.css" %}">
<link rel="stylesheet" href="{% static "autocomplete-js/dist/style.css" %}">
<link rel="stylesheet" href="{% static "tagify.css" %}">
<link rel="stylesheet" href="{% static "style.css" %}">
{% block extra_head %}
{% endblock %}
</head>
<body>
{# <div class="container {{ referrers is defined ? "edit" }}">#}
<div class="container {% block containerclasses %}{% endblock %}">
{% if user.is_authenticated %}
<div class="accountStatus">
Hello {{ user.get_username }}, <a href="{% url 'logout' %}">Log out</a>
</div>
{% endif %}
<div id="autocomplete" class="autocomplete">
<input class="autocomplete-input" {% block searchInput %}{% endblock %}/>
<ul class="autocomplete-result-list"></ul>
</div>
{% block content %}
{% endblock %}
</div>
<script src="{% static "jquery.min.js" %}"></script>
<script src="{% static "umd/popper.min.js" %}"></script>
<script src="{% static "js/bootstrap.min.js" %}"></script>
<script src="{% static "tagify.min.js" %}"></script>
<script src="{% static "autocomplete-js/dist/autocomplete.min.js" %}"></script>
<script src="{% static "app.js" %}"></script>
</body>
</html>

View file

@ -0,0 +1,29 @@
{% extends "base.html" %}
{% load static %}
{% block containerclasses %}text-center{% endblock %}
{% block extra_head %}
<link rel="stylesheet" href="{% static "login.css" %}">
{% endblock %}
{% block content %}
<form class="form-signin" method="post" action="{% url 'login' %}">
{% csrf_token %}
<h1 class="h3 mb-3 font-weight-normal">Anmeldung</h1>
<label for="{{ form.username.id_for_label }}" class="sr-only">Benutzername</label>
<input class="form-control" id="{{ form.username.id_for_label }}" maxlength="30"
name="{{ form.username.html_name }}" type="text"
placeholder="Benutzername"/>
{# <input type="email" id="inputEmail" class="form-control" placeholder="Email address" required autofocus>#}
<label for="{{ form.password.id_for_label }}" class="sr-only">Passwort</label>
<input type="password" id="{{ form.password.id_for_label }}" name="{{ form.password.html_name }}"
class="form-control" placeholder="Passwort" required>
<input type="hidden" name="next" value="{{ next }}">
<button class="btn btn-lg btn-primary btn-block" type="submit">Sign in</button>
{{ form.non_field_errors }}
</form>
{% endblock %}

28
yarn.lock Normal file
View file

@ -0,0 +1,28 @@
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
# yarn lockfile v1
"@trevoreyre/autocomplete-js@^2.1.1":
version "2.1.1"
resolved "https://registry.yarnpkg.com/@trevoreyre/autocomplete-js/-/autocomplete-js-2.1.1.tgz#7a4af9b8612c852e05f2e33a4649ad1353af4a86"
integrity sha512-G9I3Z3jYfVYUkz7XS49Mp/LMLaVcW1wVj4V/COqHq4Nk3rOgGG5ONlLGzCKpElqTIPm5p+7V7/92Mo/xsvPRvQ==
"@yaireo/tagify@^3.9.3":
version "3.9.3"
resolved "https://registry.yarnpkg.com/@yaireo/tagify/-/tagify-3.9.3.tgz#a6671345b9a3a38eb4a7b18728db2526023e1662"
integrity sha512-cS6WyMYY4YD8Op6qwsm1jE2zIxf9RQGJvYkuye4hOzgm4p77aZyByfz1+hmpAWXJZStSpff2iDn7aOB97Smoeg==
bootstrap@^4.5.0:
version "4.5.0"
resolved "https://registry.yarnpkg.com/bootstrap/-/bootstrap-4.5.0.tgz#97d9dbcb5a8972f8722c9962483543b907d9b9ec"
integrity sha512-Z93QoXvodoVslA+PWNdk23Hze4RBYIkpb5h8I2HY2Tu2h7A0LpAgLcyrhrSUyo2/Oxm2l1fRZPs1e5hnxnliXA==
jquery@^3.5.1:
version "3.5.1"
resolved "https://registry.yarnpkg.com/jquery/-/jquery-3.5.1.tgz#d7b4d08e1bfdb86ad2f1a3d039ea17304717abb5"
integrity sha512-XwIBPqcMn57FxfT+Go5pzySnm4KWkT1Tv7gjrpT1srtf8Weynl6R273VJ5GjkRb51IzMp5nbaPjJXMWeju2MKg==
popper.js@^1.16.1:
version "1.16.1"
resolved "https://registry.yarnpkg.com/popper.js/-/popper.js-1.16.1.tgz#2a223cb3dc7b6213d740e40372be40de43e65b1b"
integrity sha512-Wb4p1J4zyFTbM+u6WuO4XstYx4Ky9Cewe4DWrel7B0w6VVICvPwdOpotjzcf6eD8TsckVnIMNONQyPIUFOUbCQ==