diff --git a/.gitignore b/.gitignore index 39749e8..dc8c6f4 100644 --- a/.gitignore +++ b/.gitignore @@ -18,4 +18,4 @@ htmlcov .idea .tox node_modules -.vscode \ No newline at end of file +.vscode diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml new file mode 100644 index 0000000..3c7886e --- /dev/null +++ b/.pre-commit-config.yaml @@ -0,0 +1,56 @@ +# See https://pre-commit.com for more information +# See https://pre-commit.com/hooks.html for more hooks +exclude: "^package.json|^package-lock.json" +repos: + - repo: https://github.com/pre-commit/pre-commit-hooks + rev: v4.4.0 + hooks: + # syntax + - id: check-yaml + - id: check-json + - id: check-toml + - id: check-xml + - id: pretty-format-json + # git & filesystem + - id: check-added-large-files + - id: check-symlinks + - id: detect-private-key + - id: check-merge-conflict + - id: check-case-conflict # file conflicts: a.txt vs. A.txt + # formatters + - id: mixed-line-ending + - id: trailing-whitespace + exclude: "(.*\\.html|.*\\.md)$" + - id: end-of-file-fixer + exclude: "(.*\\.xml|.*\\.svg)$" + # python + - id: check-ast # abstract syntax tree + - id: check-builtin-literals # no {} and [], but dict() and list() + - id: debug-statements + - id: name-tests-test + args: [--pytest-test-first] + exclude: "(\/tests\/(settings|utils\/django_utils|urls).py)$" + # django-upgrade suggestions + - repo: https://github.com/adamchainz/django-upgrade + rev: "1.14.0" + hooks: + - id: django-upgrade + args: [--target-version, "4.2"] + # tha black + - repo: https://github.com/psf/black-pre-commit-mirror + rev: "23.7.0" + hooks: + - id: black + # flake8 replacement (&more) + - repo: https://github.com/charliermarsh/ruff-pre-commit + rev: "v0.0.284" + hooks: + - id: ruff + args: [--fix] + # js/sass/etc formatter + - repo: https://github.com/pre-commit/mirrors-prettier + rev: v3.0.2 + hooks: + - id: prettier + args: [--list-different] + exclude: "(.*\\.html|.*\\.md)$" diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..076df12 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,6 @@ +# django-socials Changelog + +## May 2024 + +- added pre-commit +- Django 4.2 compat diff --git a/README.md b/README.md index 3948ce9..51cb7b1 100644 --- a/README.md +++ b/README.md @@ -2,4 +2,4 @@ pre alpha -If you use django < 3.1, you must generate migrations on your own, ie with settings.MIGRATION_MODULES. \ No newline at end of file +If you use django < 3.1, you must generate migrations on your own, ie with settings.MIGRATION_MODULES. diff --git a/manage.py b/manage.py index 6a12243..cc97295 100755 --- a/manage.py +++ b/manage.py @@ -3,8 +3,7 @@ import sys if __name__ == "__main__": - os.environ.setdefault('DJANGO_SETTINGS_MODULE', - 'socials.tests.settings') + os.environ.setdefault("DJANGO_SETTINGS_MODULE", "socials.tests.settings") from django.core.management import execute_from_command_line diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..1b5780f --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,85 @@ +[tool.ruff] +# Enable the pycodestyle (`E`) and Pyflakes (`F`) rules by default. +# Unlike Flake8, Ruff doesn't enable pycodestyle warnings (`W`) or +# McCabe complexity (`C901`) by default. +# B = Bugbear +# DJ = django +# T20 = print +select = [ + # pyflakes, pycodestyle + "F", "E", "W", + # mmcabe + "C90", + # isort + "I", + # pep8-naming + # "N", + # pyupgrade + # "UP", + # flake8-2020 + "YTT", + # flake8-boolean-trap + # "FBT", + # flake8-bugbear + # "B", + # flake8-comprehensions + "C4", + # flake8-django + "DJ", + # flake8-pie + # "PIE", + # flake8-simplify + # "SIM", + # flake8-gettext + "INT", + # pygrep-hooks + # "PGH", + # pylint + # "PL", + # unused noqa + "RUF100", + # flake8-print + "T20", +] +ignore = [] +# Avoid trying to fix flake8-bugbear (`B`) violations. +unfixable = ["B"] + +# Exclude a variety of commonly ignored directories. +exclude = [ + ".bzr", + ".direnv", + ".eggs", + ".git", + ".git-rewrite", + ".hg", + ".mypy_cache", + ".nox", + ".pants.d", + ".pytype", + ".ruff_cache", + ".svn", + ".tox", + ".venv", + "__pypackages__", + "_build", + "buck-out", + "build", + "dist", + "node_modules", + "venv", + # "migrations", +] +per-file-ignores = {} + +# Same as Black. +line-length = 88 + +# Allow unused variables when underscore-prefixed. +dummy-variable-rgx = "^(_+|(_+[a-zA-Z0-9_]*[a-zA-Z0-9]+?))$" + +# Assume Python 3.9 +target-version = "py311" + +[tool.ruff.mccabe] +max-complexity = 15 diff --git a/requirements.txt b/requirements.txt index be1b524..e8884a8 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,2 +1,2 @@ django >= 2.2 -requests \ No newline at end of file +requests diff --git a/requirements_dev.txt b/requirements_dev.txt new file mode 100644 index 0000000..2042059 --- /dev/null +++ b/requirements_dev.txt @@ -0,0 +1,2 @@ +pre-commit +black diff --git a/setup.py b/setup.py index 5395da7..4d9260a 100644 --- a/setup.py +++ b/setup.py @@ -1,9 +1,9 @@ import os -from setuptools import setup, find_packages +from setuptools import find_packages, setup # not so bad: http://joebergantine.com/blog/2015/jul/17/releasing-package-pypi/ -version = __import__('socials').__version__ +version = __import__("socials").__version__ def read(fname): @@ -14,28 +14,28 @@ def read(fname): setup( name="django-socials", version=version, - url='https://github.com/rouxcode/django-socials', - license='MIT', - platforms=['OS Independent'], + url="https://github.com/rouxcode/django-socials", + license="MIT", + platforms=["OS Independent"], description="fetch posts from various social media", - long_description='none yet', - author=u'Alaric Mägerle, Ben Stähli', - author_email='info@rouxcode.ch', + long_description="none yet", + author="Alaric Mägerle, Ben Stähli", + author_email="info@rouxcode.ch", packages=find_packages(), install_requires=( - 'django>=1.11', - 'requests', - 'Pillow', + "django>=1.11", + "requests", + "Pillow", ), include_package_data=True, zip_safe=False, classifiers=[ - 'Development Status :: 4 - Beta', - 'Framework :: Django', - 'Intended Audience :: Developers', - 'License :: OSI Approved :: MIT License', - 'Operating System :: OS Independent', - 'Programming Language :: Python', - 'Topic :: Internet :: WWW/HTTP', + "Development Status :: 4 - Beta", + "Framework :: Django", + "Intended Audience :: Developers", + "License :: OSI Approved :: MIT License", + "Operating System :: OS Independent", + "Programming Language :: Python", + "Topic :: Internet :: WWW/HTTP", ], ) diff --git a/socials/__init__.py b/socials/__init__.py index 3789b40..f102a9c 100644 --- a/socials/__init__.py +++ b/socials/__init__.py @@ -1,2 +1 @@ -__version__ = '0.0.1' -default_app_config = 'socials.apps.SocialsConfig' +__version__ = "0.0.1" diff --git a/socials/admin/__init__.py b/socials/admin/__init__.py index 78977e9..a8e580f 100644 --- a/socials/admin/__init__.py +++ b/socials/admin/__init__.py @@ -1,9 +1,8 @@ from django.contrib import admin +from ..models import Post from .instagram_configuration import InstagramConfiguration, InstagramConfigurationAdmin from .post import PostAdmin -from ..models import Post - admin.site.register(InstagramConfiguration, InstagramConfigurationAdmin) admin.site.register(Post, PostAdmin) diff --git a/socials/admin/configuration.py b/socials/admin/configuration.py index ad851ae..bf195d7 100644 --- a/socials/admin/configuration.py +++ b/socials/admin/configuration.py @@ -5,24 +5,20 @@ class ConfigurationAdminForm(forms.ModelForm): - class Meta: - fields = '__all__' + fields = "__all__" # noqa model = Configuration labels = {} - widgets = { - 'url': forms.TextInput - } + widgets = {"url": forms.TextInput} class ConfigurationAdmin(admin.ModelAdmin): - form = ConfigurationAdminForm list_display = [ - 'name', + "name", ] readonly_fields = [ - 'date_added', - 'date_changed', - 'date_changed', + "date_added", + "date_changed", + "date_changed", ] diff --git a/socials/admin/instagram_configuration.py b/socials/admin/instagram_configuration.py index c50d5a3..7899e57 100644 --- a/socials/admin/instagram_configuration.py +++ b/socials/admin/instagram_configuration.py @@ -6,59 +6,55 @@ class InstagramConfigurationAdminForm(forms.ModelForm): - new_token = forms.CharField( required=False, - help_text='get it from instagram, must be entered only once.', + help_text="get it from instagram, must be entered only once.", ) def __init__(self, *args, **kwargs): super_result = super().__init__(*args, **kwargs) show_new = False - if kwargs.get('initial', None): + if kwargs.get("initial", None): # creation. need a token! show_new = True elif not self.instance.token_ok: # whatever reaseon...a long lived token is again needed. show_new = True if not show_new: - self.fields['new_token'].widget = self.fields['new_token'].hidden_widget() + self.fields["new_token"].widget = self.fields["new_token"].hidden_widget() return super_result def save(self, *args, **kwargs): if not self.errors: - if not self.instance.token_ok and self.cleaned_data.get('new_token', None): - self.instance.token = self.cleaned_data.get('new_token', None) + if not self.instance.token_ok and self.cleaned_data.get("new_token", None): + self.instance.token = self.cleaned_data.get("new_token", None) # assume it works! self.instance.token_refresh_date = timezone.now() self.instance.token_ok = True return super().save(*args, **kwargs) class Meta: - fields = '__all__' + fields = "__all__" # noqa model = InstagramConfiguration labels = {} - widgets = { - 'url': forms.TextInput - } + widgets = {"url": forms.TextInput} class InstagramConfigurationAdmin(admin.ModelAdmin): - form = InstagramConfigurationAdminForm list_display = [ - 'name', - 'active', - 'posts_refresh_date', - 'token_ok', - 'token_refresh_date', + "name", + "active", + "posts_refresh_date", + "token_ok", + "token_refresh_date", ] - list_filters = ('active', ) + list_filters = ("active",) readonly_fields = [ - 'date_added', - 'date_changed', - 'token', - 'token_ok', - 'token_refresh_date', - 'posts_refresh_date', + "date_added", + "date_changed", + "token", + # 'token_ok', + "token_refresh_date", + "posts_refresh_date", ] diff --git a/socials/admin/post.py b/socials/admin/post.py index 852d1e7..56e193a 100644 --- a/socials/admin/post.py +++ b/socials/admin/post.py @@ -2,26 +2,28 @@ class PostAdmin(admin.ModelAdmin): - list_links = [ - 'get_admin_thumbnail', - 'date', + "get_admin_thumbnail", + "date", ] list_display = [ - 'get_admin_thumbnail', - 'date', - 'get_admin_title', - 'published', - 'configuration', + "get_admin_thumbnail", + "date", + "get_admin_title", + "published", + "configuration", + ] + list_editable = [ + "published", ] list_filter = [ - 'published', - 'configuration', + "published", + "configuration", ] readonly_fields = [ - 'get_admin_thumbnail', - 'date', - 'configuration', - 'original_id', - 'original_data', + "get_admin_thumbnail", + "date", + "configuration", + "original_id", + "original_data", ] diff --git a/socials/apps.py b/socials/apps.py index d110cd1..7db139e 100644 --- a/socials/apps.py +++ b/socials/apps.py @@ -1,8 +1,7 @@ from django.apps import AppConfig -from django.utils.translation import ugettext_lazy as _ +from django.utils.translation import gettext_lazy as _ class SocialsConfig(AppConfig): - - name = 'socials' - verbose_name = _('Socials') + name = "socials" + verbose_name = _("Socials") diff --git a/socials/conf.py b/socials/conf.py index f9f0743..90d0377 100644 --- a/socials/conf.py +++ b/socials/conf.py @@ -4,14 +4,14 @@ from socials.utils import check_settings - # globals ENABLE_TAGS = False # parse hashtags? -DATE_FORMAT = '%d.%m.%Y' # output date format +DATE_FORMAT = "%d.%m.%Y" # output date format LOCAL_IMAGES = True # save images to local media folder +DEBUG = False # insta -INSTAGRAM_API = 'https://graph.instagram.com/' +INSTAGRAM_API = "https://graph.instagram.com/" INSTAGRAM_TITLE_TRUNCATE = 60 # not yet?! INSTAGRAM_REFRESH_TOKEN_BEFORE_EXPIRE = 1209600 # 14 days @@ -20,4 +20,4 @@ # tweetie -check_settings('SOCIALS', sys.modules[__name__], settings) +check_settings("SOCIALS", sys.modules[__name__], settings) diff --git a/socials/contrib/cms_socials/cms_plugins.py b/socials/contrib/cms_socials/cms_plugins.py index 970108b..7d4879f 100644 --- a/socials/contrib/cms_socials/cms_plugins.py +++ b/socials/contrib/cms_socials/cms_plugins.py @@ -1,19 +1,18 @@ -from django.utils.translation import ugettext_lazy as _ -from cms.plugin_pool import plugin_pool from cms.plugin_base import CMSPluginBase +from cms.plugin_pool import plugin_pool +from django.utils.translation import gettext_lazy as _ from .models import SocialFeed @plugin_pool.register_plugin class SocialFeedPlugin(CMSPluginBase): - model = SocialFeed - module = _('Social') - name = _('Social Feed') - render_template = 'socials/plugins/social_feed.html' + module = _("Social") + name = _("Social Feed") + render_template = "socials/plugins/social_feed.html" text_enabled = False def render(self, context, instance, placeholder): - context.update({'object': instance}) + context.update({"object": instance}) return context diff --git a/socials/contrib/cms_socials/models.py b/socials/contrib/cms_socials/models.py index ddbf702..0f1a6f7 100644 --- a/socials/contrib/cms_socials/models.py +++ b/socials/contrib/cms_socials/models.py @@ -1,34 +1,28 @@ -from django.db import models -from django.utils.translation import ugettext_lazy as _ -from django.utils.translation import ugettext as __ - from cms.models import CMSPlugin +from django.db import models +from django.utils.translation import gettext as __ +from django.utils.translation import gettext_lazy as _ from socials.models import Post class SocialFeed(CMSPlugin): - amount = models.SmallIntegerField( default=20, ) configurations = models.ManyToManyField( - 'socials.Configuration', - blank=True, - verbose_name=_('Source Configurations') + "socials.Configuration", blank=True, verbose_name=_("Source Configurations") ) hash_tags = models.ManyToManyField( - 'socials.Tag', - blank=True, - verbose_name=_('Hashtags') + "socials.Tag", blank=True, verbose_name=_("Hashtags") ) class Meta: - verbose_name = _('Social Feed') - verbose_name_plural = _('Social Feeds') + verbose_name = _("Social Feed") + verbose_name_plural = _("Social Feeds") def __str__(self): - return __('Social Feed') + return __("Social Feed") def get_posts(self): posts = Post.objects.filter(published=True) @@ -36,5 +30,5 @@ def get_posts(self): posts = posts.filter(configuration__in=self.configurations.all()) if self.hash_tags.all().count(): posts = posts.filter(tags__in=self.hash_tags.all()) - posts = posts[:self.amount] + posts = posts[: self.amount] return posts diff --git a/socials/management/commands/socials_refresh.py b/socials/management/commands/socials_refresh.py index 2e741c7..affe3f6 100644 --- a/socials/management/commands/socials_refresh.py +++ b/socials/management/commands/socials_refresh.py @@ -1,11 +1,11 @@ from django.core.management.base import BaseCommand -# from django.utils.timezone import now +# from django.utils.timezone import now from socials.models import Configuration class Command(BaseCommand): - help = 'Get latest social posts' + help = "Get latest social posts" def handle(self, *args, **options): for configuration in Configuration.objects.filter(active=True): diff --git a/socials/migrations/0001_initial.py b/socials/migrations/0001_initial.py index c309f79..a88c776 100644 --- a/socials/migrations/0001_initial.py +++ b/socials/migrations/0001_initial.py @@ -1,65 +1,133 @@ # Generated by Django 3.1.2 on 2020-10-20 04:48 -from django.db import migrations, models import django.db.models.deletion +from django.db import migrations, models class Migration(migrations.Migration): - initial = True - dependencies = [ - ] + dependencies = [] operations = [ migrations.CreateModel( - name='Configuration', + name="Configuration", fields=[ - ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('date_added', models.DateTimeField(auto_now_add=True)), - ('date_changed', models.DateTimeField(auto_now=True)), - ('name', models.CharField(default='', max_length=255, verbose_name='Name')), + ( + "id", + models.AutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ("date_added", models.DateTimeField(auto_now_add=True)), + ("date_changed", models.DateTimeField(auto_now=True)), + ( + "name", + models.CharField(default="", max_length=255, verbose_name="Name"), + ), ], options={ - 'verbose_name': 'Configuration', - 'verbose_name_plural': 'Configurations', - 'ordering': ['name'], + "verbose_name": "Configuration", + "verbose_name_plural": "Configurations", + "ordering": ["name"], }, ), migrations.CreateModel( - name='InstagramConfiguration', + name="InstagramConfiguration", fields=[ - ('configuration_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='socials.configuration')), - ('username', models.URLField(blank=True, verbose_name='Instagram Username')), - ('app_id', models.CharField(blank=True, max_length=255, verbose_name='App ID')), - ('app_secret', models.CharField(blank=True, max_length=255, verbose_name='App Secret')), - ('long_token', models.CharField(blank=True, max_length=255, verbose_name='Long-lived access token')), - ('refresh_date', models.DateTimeField(verbose_name='Last long token refresh')), + ( + "configuration_ptr", + models.OneToOneField( + auto_created=True, + on_delete=django.db.models.deletion.CASCADE, + parent_link=True, + primary_key=True, + serialize=False, + to="socials.configuration", + ), + ), + ( + "username", + models.URLField(blank=True, verbose_name="Instagram Username"), + ), + ( + "app_id", + models.CharField(blank=True, max_length=255, verbose_name="App ID"), + ), + ( + "app_secret", + models.CharField( + blank=True, max_length=255, verbose_name="App Secret" + ), + ), + ( + "long_token", + models.CharField( + blank=True, + max_length=255, + verbose_name="Long-lived access token", + ), + ), + ( + "refresh_date", + models.DateTimeField(verbose_name="Last long token refresh"), + ), ], options={ - 'verbose_name': 'Configuration', - 'verbose_name_plural': 'Configurations', - 'ordering': ['name'], + "verbose_name": "Configuration", + "verbose_name_plural": "Configurations", + "ordering": ["name"], }, - bases=('socials.configuration',), + bases=("socials.configuration",), ), migrations.CreateModel( - name='Post', + name="Post", fields=[ - ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('date_added', models.DateTimeField(auto_now_add=True)), - ('date_changed', models.DateTimeField(auto_now=True)), - ('date', models.DateTimeField(verbose_name='Date')), - ('is_visible', models.BooleanField(default=True, verbose_name='Is visible')), - ('originalid', models.BigIntegerField(blank=True, default=None, null=True, verbose_name='Original ID')), - ('data', models.JSONField(blank=True, default=dict, verbose_name='Original Data')), - ('configuration', models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, to='socials.configuration')), + ( + "id", + models.AutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ("date_added", models.DateTimeField(auto_now_add=True)), + ("date_changed", models.DateTimeField(auto_now=True)), + ("date", models.DateTimeField(verbose_name="Date")), + ( + "is_visible", + models.BooleanField(default=True, verbose_name="Is visible"), + ), + ( + "originalid", + models.BigIntegerField( + blank=True, default=None, null=True, verbose_name="Original ID" + ), + ), + ( + "data", + models.JSONField( + blank=True, default=dict, verbose_name="Original Data" + ), + ), + ( + "configuration", + models.ForeignKey( + null=True, + on_delete=django.db.models.deletion.CASCADE, + to="socials.configuration", + ), + ), ], options={ - 'verbose_name': 'Posts', - 'verbose_name_plural': 'Posts', - 'ordering': ['-date'], - 'unique_together': {('configuration', 'originalid')}, + "verbose_name": "Posts", + "verbose_name_plural": "Posts", + "ordering": ["-date"], + "unique_together": {("configuration", "originalid")}, }, ), ] diff --git a/socials/migrations/0002_auto_20201020_0453.py b/socials/migrations/0002_auto_20201020_0453.py index 507317d..4091bde 100644 --- a/socials/migrations/0002_auto_20201020_0453.py +++ b/socials/migrations/0002_auto_20201020_0453.py @@ -1,33 +1,39 @@ # Generated by Django 3.1.2 on 2020-10-20 04:53 -from django.db import migrations, models import django.utils.timezone +from django.db import migrations, models class Migration(migrations.Migration): - dependencies = [ - ('socials', '0001_initial'), + ("socials", "0001_initial"), ] operations = [ migrations.AlterModelOptions( - name='instagramconfiguration', - options={'ordering': ['name'], 'verbose_name': 'Instagram Configuration', 'verbose_name_plural': 'Instagram Configurations'}, + name="instagramconfiguration", + options={ + "ordering": ["name"], + "verbose_name": "Instagram Configuration", + "verbose_name_plural": "Instagram Configurations", + }, ), migrations.RenameField( - model_name='instagramconfiguration', - old_name='long_token', - new_name='token', + model_name="instagramconfiguration", + old_name="long_token", + new_name="token", ), migrations.RemoveField( - model_name='instagramconfiguration', - name='refresh_date', + model_name="instagramconfiguration", + name="refresh_date", ), migrations.AddField( - model_name='instagramconfiguration', - name='token_refresh_date', - field=models.DateTimeField(default=django.utils.timezone.now, verbose_name='Last long-lived token refresh'), + model_name="instagramconfiguration", + name="token_refresh_date", + field=models.DateTimeField( + default=django.utils.timezone.now, + verbose_name="Last long-lived token refresh", + ), preserve_default=False, ), ] diff --git a/socials/migrations/0003_auto_20201020_0453.py b/socials/migrations/0003_auto_20201020_0453.py index ccf6164..fabb9c3 100644 --- a/socials/migrations/0003_auto_20201020_0453.py +++ b/socials/migrations/0003_auto_20201020_0453.py @@ -4,20 +4,26 @@ class Migration(migrations.Migration): - dependencies = [ - ('socials', '0002_auto_20201020_0453'), + ("socials", "0002_auto_20201020_0453"), ] operations = [ migrations.AlterField( - model_name='instagramconfiguration', - name='token', - field=models.CharField(blank=True, default='', max_length=255, verbose_name='Long-lived access token'), + model_name="instagramconfiguration", + name="token", + field=models.CharField( + blank=True, + default="", + max_length=255, + verbose_name="Long-lived access token", + ), ), migrations.AlterField( - model_name='instagramconfiguration', - name='token_refresh_date', - field=models.DateTimeField(null=True, verbose_name='Last long-lived token refresh'), + model_name="instagramconfiguration", + name="token_refresh_date", + field=models.DateTimeField( + null=True, verbose_name="Last long-lived token refresh" + ), ), ] diff --git a/socials/migrations/0004_auto_20201020_0454.py b/socials/migrations/0004_auto_20201020_0454.py index 0e9d06b..9add92b 100644 --- a/socials/migrations/0004_auto_20201020_0454.py +++ b/socials/migrations/0004_auto_20201020_0454.py @@ -4,15 +4,16 @@ class Migration(migrations.Migration): - dependencies = [ - ('socials', '0003_auto_20201020_0453'), + ("socials", "0003_auto_20201020_0453"), ] operations = [ migrations.AlterField( - model_name='instagramconfiguration', - name='username', - field=models.CharField(default='', max_length=64, verbose_name='Instagram Username'), + model_name="instagramconfiguration", + name="username", + field=models.CharField( + default="", max_length=64, verbose_name="Instagram Username" + ), ), ] diff --git a/socials/migrations/0005_instagramconfiguration_token_ok.py b/socials/migrations/0005_instagramconfiguration_token_ok.py index 6844b05..abc2785 100644 --- a/socials/migrations/0005_instagramconfiguration_token_ok.py +++ b/socials/migrations/0005_instagramconfiguration_token_ok.py @@ -4,15 +4,14 @@ class Migration(migrations.Migration): - dependencies = [ - ('socials', '0004_auto_20201020_0454'), + ("socials", "0004_auto_20201020_0454"), ] operations = [ migrations.AddField( - model_name='instagramconfiguration', - name='token_ok', + model_name="instagramconfiguration", + name="token_ok", field=models.BooleanField(default=False), ), ] diff --git a/socials/migrations/0006_instagramconfiguration_posts_refresh_date.py b/socials/migrations/0006_instagramconfiguration_posts_refresh_date.py index 2e9f5c5..11f91a0 100644 --- a/socials/migrations/0006_instagramconfiguration_posts_refresh_date.py +++ b/socials/migrations/0006_instagramconfiguration_posts_refresh_date.py @@ -4,15 +4,14 @@ class Migration(migrations.Migration): - dependencies = [ - ('socials', '0005_instagramconfiguration_token_ok'), + ("socials", "0005_instagramconfiguration_token_ok"), ] operations = [ migrations.AddField( - model_name='instagramconfiguration', - name='posts_refresh_date', - field=models.DateTimeField(null=True, verbose_name='Last posts refresh'), + model_name="instagramconfiguration", + name="posts_refresh_date", + field=models.DateTimeField(null=True, verbose_name="Last posts refresh"), ), ] diff --git a/socials/migrations/0007_auto_20201020_0756.py b/socials/migrations/0007_auto_20201020_0756.py index 2c063c8..d9b49a6 100644 --- a/socials/migrations/0007_auto_20201020_0756.py +++ b/socials/migrations/0007_auto_20201020_0756.py @@ -4,25 +4,28 @@ class Migration(migrations.Migration): - dependencies = [ - ('socials', '0006_instagramconfiguration_posts_refresh_date'), + ("socials", "0006_instagramconfiguration_posts_refresh_date"), ] operations = [ migrations.AddField( - model_name='configuration', - name='active', + model_name="configuration", + name="active", field=models.BooleanField(default=True), ), migrations.AlterField( - model_name='instagramconfiguration', - name='app_id', - field=models.CharField(blank=True, max_length=255, verbose_name='Instagram App ID'), + model_name="instagramconfiguration", + name="app_id", + field=models.CharField( + blank=True, max_length=255, verbose_name="Instagram App ID" + ), ), migrations.AlterField( - model_name='instagramconfiguration', - name='app_secret', - field=models.CharField(blank=True, max_length=255, verbose_name='Instagram App Secret'), + model_name="instagramconfiguration", + name="app_secret", + field=models.CharField( + blank=True, max_length=255, verbose_name="Instagram App Secret" + ), ), ] diff --git a/socials/migrations/0008_auto_20201020_0805.py b/socials/migrations/0008_auto_20201020_0805.py index 1b092cf..d2812f1 100644 --- a/socials/migrations/0008_auto_20201020_0805.py +++ b/socials/migrations/0008_auto_20201020_0805.py @@ -4,42 +4,47 @@ class Migration(migrations.Migration): - dependencies = [ - ('socials', '0007_auto_20201020_0756'), + ("socials", "0007_auto_20201020_0756"), ] operations = [ migrations.AlterModelOptions( - name='post', - options={'ordering': ['-date'], 'verbose_name': 'Post', 'verbose_name_plural': 'Posts'}, + name="post", + options={ + "ordering": ["-date"], + "verbose_name": "Post", + "verbose_name_plural": "Posts", + }, ), migrations.AddField( - model_name='post', - name='original_id', - field=models.CharField(default='dddd', max_length=128, verbose_name='Original ID'), + model_name="post", + name="original_id", + field=models.CharField( + default="dddd", max_length=128, verbose_name="Original ID" + ), preserve_default=False, ), migrations.AddField( - model_name='post', - name='published', - field=models.BooleanField(default=True, verbose_name='published/visible'), + model_name="post", + name="published", + field=models.BooleanField(default=True, verbose_name="published/visible"), ), migrations.AlterField( - model_name='post', - name='date', - field=models.DateTimeField(verbose_name='Post Date'), + model_name="post", + name="date", + field=models.DateTimeField(verbose_name="Post Date"), ), migrations.AlterUniqueTogether( - name='post', - unique_together={('configuration', 'original_id')}, + name="post", + unique_together={("configuration", "original_id")}, ), migrations.RemoveField( - model_name='post', - name='is_visible', + model_name="post", + name="is_visible", ), migrations.RemoveField( - model_name='post', - name='originalid', + model_name="post", + name="originalid", ), ] diff --git a/socials/migrations/0009_auto_20201020_0817.py b/socials/migrations/0009_auto_20201020_0817.py index 379155b..493284b 100644 --- a/socials/migrations/0009_auto_20201020_0817.py +++ b/socials/migrations/0009_auto_20201020_0817.py @@ -4,28 +4,35 @@ class Migration(migrations.Migration): - dependencies = [ - ('socials', '0008_auto_20201020_0805'), + ("socials", "0008_auto_20201020_0805"), ] operations = [ migrations.CreateModel( - name='Tag', + name="Tag", fields=[ - ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('published', models.BooleanField(default=True)), - ('name', models.CharField(max_length=64)), + ( + "id", + models.AutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ("published", models.BooleanField(default=True)), + ("name", models.CharField(max_length=64)), ], options={ - 'verbose_name': 'Tag', - 'verbose_name_plural': 'Tags', - 'ordering': ['name'], + "verbose_name": "Tag", + "verbose_name_plural": "Tags", + "ordering": ["name"], }, ), migrations.AddField( - model_name='post', - name='tags', - field=models.ManyToManyField(to='socials.Tag'), + model_name="post", + name="tags", + field=models.ManyToManyField(to="socials.Tag"), ), ] diff --git a/socials/migrations/0010_auto_20201020_1017.py b/socials/migrations/0010_auto_20201020_1017.py index ef7c021..a7d18a8 100644 --- a/socials/migrations/0010_auto_20201020_1017.py +++ b/socials/migrations/0010_auto_20201020_1017.py @@ -4,20 +4,19 @@ class Migration(migrations.Migration): - dependencies = [ - ('socials', '0009_auto_20201020_0817'), + ("socials", "0009_auto_20201020_0817"), ] operations = [ migrations.AlterField( - model_name='post', - name='date', - field=models.DateTimeField(null=True, verbose_name='Post Date'), + model_name="post", + name="date", + field=models.DateTimeField(null=True, verbose_name="Post Date"), ), migrations.AlterField( - model_name='post', - name='tags', - field=models.ManyToManyField(blank=True, to='socials.Tag'), + model_name="post", + name="tags", + field=models.ManyToManyField(blank=True, to="socials.Tag"), ), ] diff --git a/socials/migrations/0011_auto_20201020_1123.py b/socials/migrations/0011_auto_20201020_1123.py index b4c3da9..f14d84f 100644 --- a/socials/migrations/0011_auto_20201020_1123.py +++ b/socials/migrations/0011_auto_20201020_1123.py @@ -4,40 +4,43 @@ class Migration(migrations.Migration): - dependencies = [ - ('socials', '0010_auto_20201020_1017'), + ("socials", "0010_auto_20201020_1017"), ] operations = [ migrations.RenameField( - model_name='post', - old_name='data', - new_name='original_data', + model_name="post", + old_name="data", + new_name="original_data", ), migrations.AddField( - model_name='post', - name='description', - field=models.TextField(blank=True, default='', verbose_name='Description'), + model_name="post", + name="description", + field=models.TextField(blank=True, default="", verbose_name="Description"), ), migrations.AddField( - model_name='post', - name='image', - field=models.ImageField(blank=True, null=True, upload_to='post-images'), + model_name="post", + name="image", + field=models.ImageField(blank=True, null=True, upload_to="post-images"), ), migrations.AddField( - model_name='post', - name='image_url', - field=models.URLField(blank=True, default='', verbose_name='Image URL'), + model_name="post", + name="image_url", + field=models.URLField(blank=True, default="", verbose_name="Image URL"), ), migrations.AddField( - model_name='post', - name='title', - field=models.CharField(blank=True, default='', max_length=128, verbose_name='Title'), + model_name="post", + name="title", + field=models.CharField( + blank=True, default="", max_length=128, verbose_name="Title" + ), ), migrations.AddField( - model_name='post', - name='url', - field=models.URLField(blank=True, default='', verbose_name='Post URL (permalink)'), + model_name="post", + name="url", + field=models.URLField( + blank=True, default="", verbose_name="Post URL (permalink)" + ), ), ] diff --git a/socials/migrations/0012_auto_20201021_0747.py b/socials/migrations/0012_auto_20201021_0747.py index 8048c8a..09604b7 100644 --- a/socials/migrations/0012_auto_20201021_0747.py +++ b/socials/migrations/0012_auto_20201021_0747.py @@ -4,18 +4,17 @@ class Migration(migrations.Migration): - dependencies = [ - ('socials', '0011_auto_20201020_1123'), + ("socials", "0011_auto_20201020_1123"), ] operations = [ migrations.RemoveField( - model_name='instagramconfiguration', - name='app_id', + model_name="instagramconfiguration", + name="app_id", ), migrations.RemoveField( - model_name='instagramconfiguration', - name='app_secret', + model_name="instagramconfiguration", + name="app_secret", ), ] diff --git a/socials/migrations/0013_auto_20201021_1026.py b/socials/migrations/0013_auto_20201021_1026.py index e848b17..360d3d5 100644 --- a/socials/migrations/0013_auto_20201021_1026.py +++ b/socials/migrations/0013_auto_20201021_1026.py @@ -4,15 +4,19 @@ class Migration(migrations.Migration): - dependencies = [ - ('socials', '0012_auto_20201021_0747'), + ("socials", "0012_auto_20201021_0747"), ] operations = [ migrations.AlterField( - model_name='instagramconfiguration', - name='username', - field=models.CharField(default='', help_text='get posts of one user is possible. no hashtags, no special things. username is only for visual help - the only relevant thing is the token', max_length=64, verbose_name='Instagram Username'), + model_name="instagramconfiguration", + name="username", + field=models.CharField( + default="", + help_text="get posts of one user is possible. no hashtags, no special things. username is only for visual help - the only relevant thing is the token", # noqa + max_length=64, + verbose_name="Instagram Username", + ), ), ] diff --git a/socials/migrations/0014_auto_20201021_1033.py b/socials/migrations/0014_auto_20201021_1033.py index d4d4ec6..1a8289a 100644 --- a/socials/migrations/0014_auto_20201021_1033.py +++ b/socials/migrations/0014_auto_20201021_1033.py @@ -4,20 +4,26 @@ class Migration(migrations.Migration): - dependencies = [ - ('socials', '0013_auto_20201021_1026'), + ("socials", "0013_auto_20201021_1026"), ] operations = [ migrations.AlterField( - model_name='post', - name='image_url', - field=models.URLField(blank=True, default='', max_length=256, verbose_name='Image URL'), + model_name="post", + name="image_url", + field=models.URLField( + blank=True, default="", max_length=256, verbose_name="Image URL" + ), ), migrations.AlterField( - model_name='post', - name='url', - field=models.URLField(blank=True, default='', max_length=256, verbose_name='Post URL (permalink)'), + model_name="post", + name="url", + field=models.URLField( + blank=True, + default="", + max_length=256, + verbose_name="Post URL (permalink)", + ), ), ] diff --git a/socials/models/__init__.py b/socials/models/__init__.py index 383611a..1ffe47a 100644 --- a/socials/models/__init__.py +++ b/socials/models/__init__.py @@ -3,10 +3,9 @@ from .post import Post from .tag import Tag - __all__ = [ - 'Configuration', - 'InstagramConfiguration', - 'Post', - 'Tag', + "Configuration", + "InstagramConfiguration", + "Post", + "Tag", ] diff --git a/socials/models/configuration.py b/socials/models/configuration.py index b196814..55b0142 100644 --- a/socials/models/configuration.py +++ b/socials/models/configuration.py @@ -1,14 +1,13 @@ from django.db import models from django.utils import timezone -from django.utils.translation import ugettext_lazy as _ +from django.utils.translation import gettext_lazy as _ from .. import conf -from .tag import Tag from .post import Post +from .tag import Tag class Configuration(models.Model): - active = models.BooleanField( default=True, ) @@ -20,17 +19,17 @@ class Configuration(models.Model): ) name = models.CharField( max_length=255, - default='', - verbose_name=_('Name'), + default="", + verbose_name=_("Name"), ) class Meta: - ordering = ['name'] - verbose_name = _('Configuration') - verbose_name_plural = _('Configurations') + ordering = ["name"] + verbose_name = _("Configuration") + verbose_name_plural = _("Configurations") def __str__(self): - return '{}'.format(self.name) + return "{}".format(self.name) def get_data_dict(self, post): data_dict = None @@ -41,25 +40,37 @@ def get_data_dict(self, post): return {} def persist_post(self, post_data): - original_id = post_data.get('original_id', None) - if (original_id): + original_id = post_data.get("original_id", None) + if original_id: post, created = Post.objects.get_or_create( original_id=original_id, configuration=self, ) - post.original_data = post_data['original_data'] - post.date = post_data.get('date', timezone.now()) - post.title = post_data.get('title', '',)[:128] - post.description = post_data.get('description', '',) - post.image_url = post_data.get('image_url', '',)[:512] - post.url = post_data.get('url', '',)[:256] + post.original_data = post_data["original_data"] + post.date = post_data.get("date", timezone.now()) + post.title = post_data.get( + "title", + "", + )[:128] + post.description = post_data.get( + "description", + "", + ) + post.image_url = post_data.get( + "image_url", + "", + )[:512] + post.url = post_data.get( + "url", + "", + )[:256] # TODO: save image? if conf.LOCAL_IMAGES: pass post.save() if conf.ENABLE_TAGS: tags = [] - for tag_name in post_data.get('tags', []): + for tag_name in post_data.get("tags", []): tag, created = Tag.objects.get_or_create( name=tag_name[:64], ) diff --git a/socials/models/instagram_configuration.py b/socials/models/instagram_configuration.py index ec980d6..011eb88 100644 --- a/socials/models/instagram_configuration.py +++ b/socials/models/instagram_configuration.py @@ -1,52 +1,52 @@ -import requests - -from datetime import timedelta, datetime +from datetime import datetime, timedelta -from django.conf import settings +import requests from django.db import models from django.template.defaultfilters import truncatechars from django.utils import timezone -from django.utils.translation import ugettext_lazy as _ +from django.utils.translation import gettext_lazy as _ from .. import conf -from . import Configuration from ..utils import parse_to_tags +from . import Configuration class InstagramConfiguration(Configuration): - username = models.CharField( max_length=64, - default='', + default="", blank=False, - verbose_name=_('Instagram Username'), - help_text=_('get posts of one user is possible. no hashtags, no special things. username is only for visual help - the only relevant thing is the token'), + verbose_name=_("Instagram Username"), + help_text=_( + "get posts of one user is possible. no hashtags, no special things. " + "username is only for visual help - the only relevant thing is the token" + ), ) token = models.CharField( max_length=255, blank=True, - verbose_name=_('Long-lived access token'), - default='' + verbose_name=_("Long-lived access token"), + default="", ) token_refresh_date = models.DateTimeField( - verbose_name=_('Last long-lived token refresh'), + verbose_name=_("Last long-lived token refresh"), null=True, ) token_ok = models.BooleanField( default=False, ) posts_refresh_date = models.DateTimeField( - verbose_name=_('Last posts refresh'), + verbose_name=_("Last posts refresh"), null=True, ) class Meta: - ordering = ['name'] - verbose_name = _('Instagram Configuration') - verbose_name_plural = _('Instagram Configurations') + ordering = ["name"] + verbose_name = _("Instagram Configuration") + verbose_name_plural = _("Instagram Configurations") def __str__(self): - return '{}'.format(self.name) + return "{}".format(self.name) # def get_set_token(self, short_token): # """ @@ -61,7 +61,7 @@ def __str__(self): # 'client_secret': self.app_secret, # 'access_token': short_token # } - # response = requests.get(url, params=params) # NOQA + # response = requests.get(url, params=params) # print(response.json()) # """ # should return: @@ -88,42 +88,41 @@ def refresh_token(self): now = timezone.now() limit = now - timedelta(days=20) # TODO: use expires_in from response data? - print(self.token_refresh_date) - print(limit) + if conf.DEBUG: + print(self.token_refresh_date) # noqa + print(limit) # noqa if self.token_refresh_date < limit: - url = '{}refresh_access_token'.format(conf.INSTAGRAM_API) - params = { - 'grant_type': 'ig_refresh_token', - 'access_token': self.token - } + url = "{}refresh_access_token".format(conf.INSTAGRAM_API) + params = {"grant_type": "ig_refresh_token", "access_token": self.token} response = requests.get(url, params=params) data = response.json() else: - print('no need to get a fresch token yet') + if conf.DEBUG: + print("no need to get a fresch token yet") # noqa return if response.status_code == 200 and data: - self.token = data.get('access_token') + self.token = data.get("access_token") self.token_refresh_date = now self.token_ok = True self.save() - elif settings.DEBUG: + elif conf.DEBUG: self.token_ok = False self.save() - print('could not refresh token') + print("could not refresh token") # noqa return def get_media(self): - url = '{}/me/media'.format(conf.INSTAGRAM_API) + url = "{}/me/media".format(conf.INSTAGRAM_API) params = { - 'access_token': self.token, - 'fields': ( - 'id' - ',timestamp' - ',permalink' - ',media_type' - ',media_url' - ',caption' - ',thumbnail_url' + "access_token": self.token, + "fields": ( + "id" + ",timestamp" + ",permalink" + ",media_type" + ",media_url" + ",caption" + ",thumbnail_url" ), } try: @@ -134,20 +133,21 @@ def get_media(self): ConnectionAbortedError, ConnectionResetError, ) as e: - if conf.settings.DEBUG: - print(e) + if conf.DEBUG: + print(e) # noqa return if response.status_code == 400: # bad request! self.token_ok = False self.save() + if conf.DEBUG: + print("error 400 when getting media") # noqa return json = response.json() - print(json) - if response.status_code == 200 and json.get('data', None): - return json['data'] - elif conf.settings.DEBUG: - print(json.get('error')) + if response.status_code == 200 and json.get("data", None): + return json["data"] + elif conf.DEBUG: + print(json.get("error")) # noqa return def refresh_media(self): @@ -160,28 +160,32 @@ def refresh_media(self): post_data = self.get_data_dict(m) tags = [] if conf.ENABLE_TAGS: - tags = parse_to_tags(m.get('caption', '')) - post_data['tags'] = tags - post_data['original_data'] = m + tags = parse_to_tags(m.get("caption", "")) + post_data["tags"] = tags + post_data["original_data"] = m self.configuration_ptr.persist_post(post_data) self.posts_refresh_date = timezone.now() + if conf.DEBUG: + print("refresh media: SUCCESS") # noqa self.save() def get_data_dict(self, json_data): - if json_data.get('timestamp', None): - string = json_data['timestamp'] - date = datetime.strptime(string, '%Y-%m-%dT%H:%M:%S+%f') - if json_data['media_type'] == 'VIDEO': - image_url = json_data['thumbnail_url'] + if json_data.get("timestamp", None): + string = json_data["timestamp"] + date = datetime.strptime(string, "%Y-%m-%dT%H:%M:%S+%f") + if json_data["media_type"] == "VIDEO": + image_url = json_data["thumbnail_url"] else: # naive fallback. know at least about "VIDEO"... - image_url = json_data['media_url'] + image_url = json_data["media_url"] return { - 'original_id': truncatechars(json_data.get('id', ''), ''), - 'title': truncatechars(json_data.get('caption', ''), conf.INSTAGRAM_TITLE_TRUNCATE), - 'description': json_data.get('caption', ''), - 'image_url': image_url, - 'date': date, - 'url': json_data.get('permalink', ''), + "original_id": truncatechars(json_data.get("id", ""), ""), + "title": truncatechars( + json_data.get("caption", ""), conf.INSTAGRAM_TITLE_TRUNCATE + ), + "description": json_data.get("caption", ""), + "image_url": image_url, + "date": date, + "url": json_data.get("permalink", ""), } def get_posts(self, amount=None): diff --git a/socials/models/post.py b/socials/models/post.py index 7676a42..3166f92 100644 --- a/socials/models/post.py +++ b/socials/models/post.py @@ -1,22 +1,16 @@ -from datetime import datetime - from django.db import models from django.utils.html import mark_safe -from django.utils.timezone import now -from django.utils.translation import ugettext_lazy as _ - -from socials import conf +from django.utils.translation import gettext_lazy as _ try: # django >= 3 from django.db.models import JSONField except Exception: # django <= 2.2 - from django.contrib.postgres.fields import JSONField + from django.db.models import JSONField class Post(models.Model): - date_added = models.DateTimeField( auto_now_add=True, ) @@ -25,79 +19,84 @@ class Post(models.Model): ) published = models.BooleanField( default=True, - verbose_name=_('published/visible'), + verbose_name=_("published/visible"), ) configuration = models.ForeignKey( - 'socials.Configuration', + "socials.Configuration", null=True, on_delete=models.CASCADE, ) original_id = models.CharField( max_length=128, blank=False, - verbose_name=_('Original ID'), + verbose_name=_("Original ID"), ) original_data = JSONField( blank=True, default=dict, - verbose_name=_('Original Data'), + verbose_name=_("Original Data"), ) - # to add: title / description / image (local image) / image_url / url / original_data (instead of data) + # to add: title / description / image (local image) + # / image_url / url / original_data (instead of data) date = models.DateTimeField( - verbose_name=_('Post Date'), + verbose_name=_("Post Date"), null=True, ) title = models.CharField( max_length=128, - default='', + default="", blank=True, - verbose_name=_('Title'), + verbose_name=_("Title"), ) description = models.TextField( - default='', + default="", blank=True, - verbose_name=_('Description'), + verbose_name=_("Description"), ) image = models.ImageField( - upload_to='post-images', + upload_to="post-images", null=True, blank=True, ) url = models.URLField( max_length=256, - default='', + default="", blank=True, - verbose_name=_('Post URL (permalink)'), + verbose_name=_("Post URL (permalink)"), ) image_url = models.URLField( max_length=512, - default='', + default="", blank=True, - verbose_name=_('Image URL'), + verbose_name=_("Image URL"), ) tags = models.ManyToManyField( - 'socials.Tag', + "socials.Tag", blank=True, ) class Meta: - ordering = ['-date'] + ordering = ["-date"] unique_together = [ - ['configuration', 'original_id'], + ["configuration", "original_id"], ] - verbose_name = _('Post') - verbose_name_plural = _('Posts') + verbose_name = _("Post") + verbose_name_plural = _("Posts") def __str__(self): - return '{}'.format(self.original_id) + return "{}".format(self.original_id) def get_admin_thumbnail(self): url = self.image_url if url: - html = ''.format(url) + html = ( + f'' + ) return mark_safe(html) - get_admin_thumbnail.short_description = _('Thumbnail') + + get_admin_thumbnail.short_description = _("Thumbnail") def get_admin_title(self): url = self.url @@ -105,4 +104,5 @@ def get_admin_title(self): if url: html += ' open'.format(url) return mark_safe(html) - get_admin_thumbnail.short_description = _('Thumbnail') + + get_admin_thumbnail.short_description = _("Thumbnail") diff --git a/socials/models/tag.py b/socials/models/tag.py index dd7ef9f..96962b4 100644 --- a/socials/models/tag.py +++ b/socials/models/tag.py @@ -1,9 +1,8 @@ from django.db import models -from django.utils.translation import ugettext_lazy as _ +from django.utils.translation import gettext_lazy as _ class Tag(models.Model): - published = models.BooleanField( default=True, ) @@ -12,9 +11,9 @@ class Tag(models.Model): ) class Meta: - ordering = ['name'] - verbose_name = _('Tag') - verbose_name_plural = _('Tags') + ordering = ["name"] + verbose_name = _("Tag") + verbose_name_plural = _("Tags") def __str__(self): - return self.name \ No newline at end of file + return self.name diff --git a/socials/templates/socials/plugins/instagram.html b/socials/templates/socials/plugins/instagram.html index 806b830..9d7930b 100644 --- a/socials/templates/socials/plugins/instagram.html +++ b/socials/templates/socials/plugins/instagram.html @@ -17,4 +17,4 @@