commit b8c9454ef768b58a87df42e66f02d7eb81785bb2 Author: Lukas Winkler Date: Mon Jun 1 11:03:21 2020 +0200 initial commit diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..9ffeffe --- /dev/null +++ b/.gitignore @@ -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 diff --git a/acronomy/__init__.py b/acronomy/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/acronomy/asgi.py b/acronomy/asgi.py new file mode 100644 index 0000000..9287ba6 --- /dev/null +++ b/acronomy/asgi.py @@ -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() diff --git a/acronomy/settings.py b/acronomy/settings.py new file mode 100644 index 0000000..73a21fa --- /dev/null +++ b/acronomy/settings.py @@ -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 diff --git a/acronomy/urls.py b/acronomy/urls.py new file mode 100644 index 0000000..30defe5 --- /dev/null +++ b/acronomy/urls.py @@ -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), +] diff --git a/acronomy/wsgi.py b/acronomy/wsgi.py new file mode 100644 index 0000000..ecfb5d8 --- /dev/null +++ b/acronomy/wsgi.py @@ -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() diff --git a/acros/__init__.py b/acros/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/acros/admin.py b/acros/admin.py new file mode 100644 index 0000000..f73ee48 --- /dev/null +++ b/acros/admin.py @@ -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) diff --git a/acros/apps.py b/acros/apps.py new file mode 100644 index 0000000..45869db --- /dev/null +++ b/acros/apps.py @@ -0,0 +1,5 @@ +from django.apps import AppConfig + + +class AcrosConfig(AppConfig): + name = 'acros' diff --git a/acros/forms.py b/acros/forms.py new file mode 100644 index 0000000..14e4cbf --- /dev/null +++ b/acros/forms.py @@ -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"] diff --git a/acros/management/commands/markdown.py b/acros/management/commands/markdown.py new file mode 100644 index 0000000..0130d82 --- /dev/null +++ b/acros/management/commands/markdown.py @@ -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) diff --git a/acros/migrations/0001_initial.py b/acros/migrations/0001_initial.py new file mode 100644 index 0000000..343d256 --- /dev/null +++ b/acros/migrations/0001_initial.py @@ -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')), + ], + ), + ] diff --git a/acros/migrations/0002_historicalacronym_historicaldoireference_historicalweblink.py b/acros/migrations/0002_historicalacronym_historicaldoireference_historicalweblink.py new file mode 100644 index 0000000..f739c20 --- /dev/null +++ b/acros/migrations/0002_historicalacronym_historicaldoireference_historicalweblink.py @@ -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), + ), + ] diff --git a/acros/migrations/0003_auto_20200527_0938.py b/acros/migrations/0003_auto_20200527_0938.py new file mode 100644 index 0000000..5e8fe7f --- /dev/null +++ b/acros/migrations/0003_auto_20200527_0938.py @@ -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, + ), + ] diff --git a/acros/migrations/0004_auto_20200527_1922.py b/acros/migrations/0004_auto_20200527_1922.py new file mode 100644 index 0000000..9e9b289 --- /dev/null +++ b/acros/migrations/0004_auto_20200527_1922.py @@ -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), + ), + ] diff --git a/acros/migrations/0005_auto_20200527_1954.py b/acros/migrations/0005_auto_20200527_1954.py new file mode 100644 index 0000000..8230d71 --- /dev/null +++ b/acros/migrations/0005_auto_20200527_1954.py @@ -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', + ), + ] diff --git a/acros/migrations/0006_auto_20200527_1956.py b/acros/migrations/0006_auto_20200527_1956.py new file mode 100644 index 0000000..20537d4 --- /dev/null +++ b/acros/migrations/0006_auto_20200527_1956.py @@ -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), + ), + ] diff --git a/acros/migrations/0007_auto_20200528_1717.py b/acros/migrations/0007_auto_20200528_1717.py new file mode 100644 index 0000000..ff15f21 --- /dev/null +++ b/acros/migrations/0007_auto_20200528_1717.py @@ -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'), + ), + ] diff --git a/acros/migrations/0008_auto_20200528_1827.py b/acros/migrations/0008_auto_20200528_1827.py new file mode 100644 index 0000000..65f8257 --- /dev/null +++ b/acros/migrations/0008_auto_20200528_1827.py @@ -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), + ), + ] diff --git a/acros/migrations/0009_auto_20200529_1728.py b/acros/migrations/0009_auto_20200529_1728.py new file mode 100644 index 0000000..d63c521 --- /dev/null +++ b/acros/migrations/0009_auto_20200529_1728.py @@ -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, + ), + ] diff --git a/acros/migrations/0010_auto_20200529_1859.py b/acros/migrations/0010_auto_20200529_1859.py new file mode 100644 index 0000000..f8c3fc7 --- /dev/null +++ b/acros/migrations/0010_auto_20200529_1859.py @@ -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), + ), + ] diff --git a/acros/migrations/0011_auto_20200529_1900.py b/acros/migrations/0011_auto_20200529_1900.py new file mode 100644 index 0000000..0d7769b --- /dev/null +++ b/acros/migrations/0011_auto_20200529_1900.py @@ -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), + ), + ] diff --git a/acros/migrations/0012_auto_20200529_1943.py b/acros/migrations/0012_auto_20200529_1943.py new file mode 100644 index 0000000..241ee7d --- /dev/null +++ b/acros/migrations/0012_auto_20200529_1943.py @@ -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), + ), + ] diff --git a/acros/migrations/0013_auto_20200531_1616.py b/acros/migrations/0013_auto_20200531_1616.py new file mode 100644 index 0000000..619b57e --- /dev/null +++ b/acros/migrations/0013_auto_20200531_1616.py @@ -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'), + ), + ] diff --git a/acros/migrations/0014_auto_20200531_1616.py b/acros/migrations/0014_auto_20200531_1616.py new file mode 100644 index 0000000..d243886 --- /dev/null +++ b/acros/migrations/0014_auto_20200531_1616.py @@ -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'), + ), + ] diff --git a/acros/migrations/0015_auto_20200531_1638.py b/acros/migrations/0015_auto_20200531_1638.py new file mode 100644 index 0000000..85a55bc --- /dev/null +++ b/acros/migrations/0015_auto_20200531_1638.py @@ -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', + ), + ] diff --git a/acros/migrations/0016_auto_20200531_1704.py b/acros/migrations/0016_auto_20200531_1704.py new file mode 100644 index 0000000..a17b7f9 --- /dev/null +++ b/acros/migrations/0016_auto_20200531_1704.py @@ -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/'), + ), + ] diff --git a/acros/migrations/0017_auto_20200531_1705.py b/acros/migrations/0017_auto_20200531_1705.py new file mode 100644 index 0000000..42198b7 --- /dev/null +++ b/acros/migrations/0017_auto_20200531_1705.py @@ -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'), + ), + ] diff --git a/acros/migrations/0018_auto_20200531_1709.py b/acros/migrations/0018_auto_20200531_1709.py new file mode 100644 index 0000000..b9e1262 --- /dev/null +++ b/acros/migrations/0018_auto_20200531_1709.py @@ -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, + ), + ] diff --git a/acros/migrations/0019_host.py b/acros/migrations/0019_host.py new file mode 100644 index 0000000..b68c7b7 --- /dev/null +++ b/acros/migrations/0019_host.py @@ -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/')), + ], + ), + ] diff --git a/acros/migrations/0020_host_fetched.py b/acros/migrations/0020_host_fetched.py new file mode 100644 index 0000000..c51e968 --- /dev/null +++ b/acros/migrations/0020_host_fetched.py @@ -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), + ), + ] diff --git a/acros/migrations/0021_auto_20200531_1726.py b/acros/migrations/0021_auto_20200531_1726.py new file mode 100644 index 0000000..e3badc2 --- /dev/null +++ b/acros/migrations/0021_auto_20200531_1726.py @@ -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'), + ), + ] diff --git a/acros/migrations/0022_auto_20200531_1728.py b/acros/migrations/0022_auto_20200531_1728.py new file mode 100644 index 0000000..fdf04af --- /dev/null +++ b/acros/migrations/0022_auto_20200531_1728.py @@ -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), + ), + ] diff --git a/acros/migrations/0023_auto_20200531_1835.py b/acros/migrations/0023_auto_20200531_1835.py new file mode 100644 index 0000000..0e40784 --- /dev/null +++ b/acros/migrations/0023_auto_20200531_1835.py @@ -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), + ), + ] diff --git a/acros/migrations/0024_auto_20200531_1838.py b/acros/migrations/0024_auto_20200531_1838.py new file mode 100644 index 0000000..0946e20 --- /dev/null +++ b/acros/migrations/0024_auto_20200531_1838.py @@ -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), + ), + ] diff --git a/acros/migrations/__init__.py b/acros/migrations/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/acros/models/Acronym.py b/acros/models/Acronym.py new file mode 100644 index 0000000..0b5d6d5 --- /dev/null +++ b/acros/models/Acronym.py @@ -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"] diff --git a/acros/models/Host.py b/acros/models/Host.py new file mode 100644 index 0000000..250ff36 --- /dev/null +++ b/acros/models/Host.py @@ -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) diff --git a/acros/models/PaperReference.py b/acros/models/PaperReference.py new file mode 100644 index 0000000..e482f92 --- /dev/null +++ b/acros/models/PaperReference.py @@ -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 diff --git a/acros/models/Tag.py b/acros/models/Tag.py new file mode 100644 index 0000000..9992120 --- /dev/null +++ b/acros/models/Tag.py @@ -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)]) diff --git a/acros/models/Weblink.py b/acros/models/Weblink.py new file mode 100644 index 0000000..d74c8d9 --- /dev/null +++ b/acros/models/Weblink.py @@ -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) diff --git a/acros/models/WikipediaLink.py b/acros/models/WikipediaLink.py new file mode 100644 index 0000000..1a39801 --- /dev/null +++ b/acros/models/WikipediaLink.py @@ -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 diff --git a/acros/models/__init__.py b/acros/models/__init__.py new file mode 100644 index 0000000..23e18e1 --- /dev/null +++ b/acros/models/__init__.py @@ -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 diff --git a/acros/serializers.py b/acros/serializers.py new file mode 100644 index 0000000..6fd3879 --- /dev/null +++ b/acros/serializers.py @@ -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"] diff --git a/acros/templates/SVGs/external.svg b/acros/templates/SVGs/external.svg new file mode 100644 index 0000000..e54af32 --- /dev/null +++ b/acros/templates/SVGs/external.svg @@ -0,0 +1,4 @@ + + + diff --git a/acros/templates/SVGs/icons.html b/acros/templates/SVGs/icons.html new file mode 100644 index 0000000..087d08a --- /dev/null +++ b/acros/templates/SVGs/icons.html @@ -0,0 +1,3 @@ + + + diff --git a/acros/templates/SVGs/pdf.svg b/acros/templates/SVGs/pdf.svg new file mode 100644 index 0000000..f96be3d --- /dev/null +++ b/acros/templates/SVGs/pdf.svg @@ -0,0 +1,7 @@ + + + + diff --git a/acros/templates/acros/add.html b/acros/templates/acros/add.html new file mode 100644 index 0000000..830b12f --- /dev/null +++ b/acros/templates/acros/add.html @@ -0,0 +1,10 @@ +{% extends 'base.html' %} + +{% block content %} + +
{% csrf_token %} + {{ form.as_p }} + +
+ +{% endblock %} diff --git a/acros/templates/acros/detail.html b/acros/templates/acros/detail.html new file mode 100644 index 0000000..caa7940 --- /dev/null +++ b/acros/templates/acros/detail.html @@ -0,0 +1,108 @@ +{% extends 'base.html' %} +{% load static %} + +{% block content %} +

{{ acro.name }}

+

{{ acro.full_name }}

+ {% if acro.description_html %} +
+ {{ acro.description_html|safe }} +
+ {% endif %} + {#