diff --git a/instagram_utils/services.py b/instagram_utils/services.py index 6c4349e4edbb5ec220458a7770ad7865e99702a4..077f25fa8863f0a59c065abf4686a6dacbac42b8 100644 --- a/instagram_utils/services.py +++ b/instagram_utils/services.py @@ -1,5 +1,5 @@ import logging -import requests +import requests_cache from main.models import MainHomePage, MainPersonPage @@ -15,36 +15,50 @@ class InstagramDownloadService: """ def __init__(self, app_id: int, app_secret: str): + self.session = requests_cache.CachedSession("instagram_cache") + self.app_id = app_id self.app_secret = app_secret - # https://www.instagram.com/web/search/topsearch/?context=user&count=1&query=that_snowden - # Useful Instagram username search API + def get_user_info_list(self) -> list[str]: + access_block = MainHomePage.objects.first().instagram_access - def get_username_list(self) -> list[str]: - instagram_usernames_block = MainHomePage.objects.first().instagram_usernames + # TODO - Individual users' instagram info - person_username_list = ( - MainPersonPage.objects.filter(instagram_username__isnull=False) - .values_list("instagram_username", flat=True) - .distinct() - ) - homepage_username_list = [ - username_data["value"] for username_data in instagram_usernames_block.raw_data + return [ + ( + block["value"]["name"], + block["value"]["user_id"], + block["value"]["access_token"] + ) + for block in access_block.raw_data ] - # kvĹŻli duplicitám udÄ›lám(e) list/set/list konverzi - return list({*person_username_list, *homepage_username_list}) + def parse_media_for_user(self, name, user_id, access_token): + with self.session.cache_disabled(): + recent_media = self.session.get( + f"https://graph.instagram.com/v16.0/{user_id}/media?access_token=" + f"{access_token}&fields=caption,media_type,permalink,media_url," + "thumbnail_url" + ) - def convert_usernames_to_ids(self, username_list) -> list[str]: - user_ids = [] + if not recent_media.ok: + logger.warning( + "Error getting media for user %s: %s", + user_id, + recent_media.status_code + ) - for username in username_list: - print(username) + return - return user_ids + recent_media = recent_media.json() + + print(recent_media) def perform_update(self) -> None: - username_list = self.get_username_list() + user_info_list = self.get_user_info_list() + + media = [] - user_ids = self.convert_usernames_to_ids(username_list) + for user_info in user_info_list: + media.append(self.parse_media_for_user(*user_info)) diff --git a/main/blocks.py b/main/blocks.py index f0ffe7fe26f04414518c8366f561f88e9be3c702..2e039e8ccd2903a4e758581f06f4c8288faa207a 100644 --- a/main/blocks.py +++ b/main/blocks.py @@ -372,4 +372,18 @@ class CardLinkWithHeadlineBlock(CardLinkWithHeadlineBlockMixin): label = "Karty odkazĹŻ s nadpisem" +class InstagramAccessBlock(StructBlock): + name = CharBlock(label="ZobrazovanĂ© jmĂ©no") + user_id = CharBlock(label="UĹľivatelskĂ© ID") + access_token = CharBlock(label="PĹ™ĂstupovĂ˝ token") + + class Meta: + label = "Synchronizace s Instagramem" + help_text = ( + "Informace lze zĂskat pĹ™ihlášenĂm poĹľadovanĂ˝m InstagramovĂ˝m " + "účtem na tools.pirati.cz/instagram . Token je tĹ™eba kvĹŻli " + "podmĂnkám Instagramu kaĹľdĂ˝ch 60 dnĂ obnovit." + ) + + # TwitterCarouselBlock diff --git a/main/migrations/0047_remove_mainhomepage_instagram_usernames_and_more.py b/main/migrations/0047_remove_mainhomepage_instagram_usernames_and_more.py new file mode 100644 index 0000000000000000000000000000000000000000..5ffb82cca00a53943819f00197da88817b34a591 --- /dev/null +++ b/main/migrations/0047_remove_mainhomepage_instagram_usernames_and_more.py @@ -0,0 +1,24 @@ +# Generated by Django 4.1.6 on 2023-04-05 11:17 + +from django.db import migrations +import wagtail.blocks +import wagtail.fields + + +class Migration(migrations.Migration): + + dependencies = [ + ('main', '0046_mainhomepage_instagram_usernames_and_more'), + ] + + operations = [ + migrations.RemoveField( + model_name='mainhomepage', + name='instagram_usernames', + ), + migrations.AddField( + model_name='mainhomepage', + name='instagram_access', + field=wagtail.fields.StreamField([('instagram_access', wagtail.blocks.StructBlock([('username', wagtail.blocks.CharBlock(label='UĹľivatelskĂ© jmĂ©no')), ('access_token', wagtail.blocks.CharBlock(help_text='TODO', label='PĹ™ĂstupovĂ˝ token'))]))], blank=True, use_json_field=True, verbose_name='UĹľivatelská jmĂ©na a pĹ™ĂstupovĂ© tokeny pro synchronizovanĂ© Instagram účty'), + ), + ] diff --git a/main/migrations/0048_alter_mainhomepage_instagram_access.py b/main/migrations/0048_alter_mainhomepage_instagram_access.py new file mode 100644 index 0000000000000000000000000000000000000000..808610fa2221c5d48fd9ecfa370fe83ff4cc95ee --- /dev/null +++ b/main/migrations/0048_alter_mainhomepage_instagram_access.py @@ -0,0 +1,20 @@ +# Generated by Django 4.1.6 on 2023-04-05 11:34 + +from django.db import migrations +import wagtail.blocks +import wagtail.fields + + +class Migration(migrations.Migration): + + dependencies = [ + ('main', '0047_remove_mainhomepage_instagram_usernames_and_more'), + ] + + operations = [ + migrations.AlterField( + model_name='mainhomepage', + name='instagram_access', + field=wagtail.fields.StreamField([('instagram_access', wagtail.blocks.StructBlock([('name', wagtail.blocks.CharBlock(label='ZobrazovanĂ© jmĂ©no')), ('user_id', wagtail.blocks.CharBlock(help_text='TODO', label='UĹľivatelskĂ© ID')), ('access_token', wagtail.blocks.CharBlock(help_text='TODO', label='PĹ™ĂstupovĂ˝ token'))]))], blank=True, use_json_field=True, verbose_name='UĹľivatelská jmĂ©na a pĹ™ĂstupovĂ© tokeny pro synchronizovanĂ© Instagram účty'), + ), + ] diff --git a/main/migrations/0049_alter_mainhomepage_instagram_access.py b/main/migrations/0049_alter_mainhomepage_instagram_access.py new file mode 100644 index 0000000000000000000000000000000000000000..6ffa876b5842cbd976731c072c0b5b62cf7c2527 --- /dev/null +++ b/main/migrations/0049_alter_mainhomepage_instagram_access.py @@ -0,0 +1,20 @@ +# Generated by Django 4.1.6 on 2023-04-05 11:56 + +from django.db import migrations +import wagtail.blocks +import wagtail.fields + + +class Migration(migrations.Migration): + + dependencies = [ + ('main', '0048_alter_mainhomepage_instagram_access'), + ] + + operations = [ + migrations.AlterField( + model_name='mainhomepage', + name='instagram_access', + field=wagtail.fields.StreamField([('instagram_access', wagtail.blocks.StructBlock([('name', wagtail.blocks.CharBlock(label='ZobrazovanĂ© jmĂ©no')), ('user_id', wagtail.blocks.CharBlock(label='UĹľivatelskĂ© ID')), ('access_token', wagtail.blocks.CharBlock(label='PĹ™ĂstupovĂ˝ token'))]))], blank=True, use_json_field=True, verbose_name='UĹľivatelská jmĂ©na a pĹ™ĂstupovĂ© tokeny pro synchronizovanĂ© Instagram účty'), + ), + ] diff --git a/main/models.py b/main/models.py index 7a330821f03d6b8d0df06f4269d05a7f64a02979..2f2fba721676a408c8741f6ea4ab5bcf47a01037 100644 --- a/main/models.py +++ b/main/models.py @@ -142,9 +142,9 @@ class MainHomePage( use_json_field=True, ) - instagram_usernames = StreamField( - [("username", CharBlock(label="Instagram uĹľivatelskĂ© jmĂ©no"))], - verbose_name="UĹľivatelská jmĂ©na pro synchronizovanĂ© Instagram účty", + instagram_access = StreamField( + [("instagram_access", blocks.InstagramAccessBlock())], + verbose_name="UĹľivatelská jmĂ©na a pĹ™ĂstupovĂ© tokeny pro synchronizovanĂ© Instagram účty", blank=True, max_num=64, use_json_field=True, @@ -167,7 +167,7 @@ class MainHomePage( FieldPanel("social_links"), FieldPanel("matomo_id"), FieldPanel("twitter_usernames"), - FieldPanel("instagram_usernames"), + FieldPanel("instagram_access"), ] ### EDIT HANDLERS diff --git a/redmine_cache.sqlite b/redmine_cache.sqlite new file mode 100644 index 0000000000000000000000000000000000000000..3b5e89721f01b173248305cbb9b09457108c9a84 Binary files /dev/null and b/redmine_cache.sqlite differ diff --git a/requirements/base.in b/requirements/base.in index 0cd088a7fe2c0e5a0ed83397828e20fac0a2532f..65386446adf23c7101e65712581b4d13d17bbcf0 100644 --- a/requirements/base.in +++ b/requirements/base.in @@ -26,3 +26,4 @@ pypdf2 pyyaml fastjsonschema tweepy +requests-cache diff --git a/requirements/base.txt b/requirements/base.txt index 5541583025f8eea6586ffb210fcf2056f8beb4dd..9544a1936c1b0d6b23f7f9ca4f9e2fb2a0673e22 100644 --- a/requirements/base.txt +++ b/requirements/base.txt @@ -1,5 +1,5 @@ # -# This file is autogenerated by pip-compile with Python 3.10 +# This file is autogenerated by pip-compile with Python 3.11 # by the following command: # # pip-compile base.in @@ -19,7 +19,10 @@ asttokens==2.2.1 async-timeout==4.0.2 # via redis attrs==22.2.0 - # via ics + # via + # cattrs + # ics + # requests-cache backcall==0.2.0 # via ipython beautifulsoup4==4.11.2 @@ -32,6 +35,8 @@ bleach==6.0.0 # via -r base.in brotli==1.0.9 # via fonttools +cattrs==22.2.0 + # via requests-cache celery==5.2.7 # via -r base.in certifi==2022.12.7 @@ -171,6 +176,8 @@ pillow==9.4.0 # weasyprint pirates==0.6.0 # via -r base.in +platformdirs==3.2.0 + # via requests-cache prompt-toolkit==3.0.36 # via # click-repl @@ -218,9 +225,12 @@ requests==2.28.2 # via # -r base.in # mozilla-django-oidc + # requests-cache # requests-oauthlib # tweepy # wagtail +requests-cache==1.0.1 + # via -r base.in requests-oauthlib==1.3.1 # via tweepy sentry-sdk==1.15.0 @@ -234,6 +244,7 @@ six==1.16.0 # ics # l18n # python-dateutil + # url-normalize soupsieve==2.3.2.post1 # via beautifulsoup4 sqlparse==0.4.3 @@ -254,9 +265,12 @@ traitlets==5.9.0 # matplotlib-inline tweepy==4.12.1 # via -r base.in +url-normalize==1.4.3 + # via requests-cache urllib3==1.26.14 # via # requests + # requests-cache # sentry-sdk vine==5.0.0 # via diff --git a/requirements/dev.txt b/requirements/dev.txt index 16d15b0fe79ceff9587f5ac290b7637ddff5f472..d37f0c97294d7a7aac1553fdea6e8454da315a75 100644 --- a/requirements/dev.txt +++ b/requirements/dev.txt @@ -1,6 +1,6 @@ # -# This file is autogenerated by pip-compile with python 3.10 -# To update, run: +# This file is autogenerated by pip-compile with Python 3.11 +# by the following command: # # pip-compile dev.in # @@ -16,8 +16,6 @@ django==4.1.6 # django-debug-toolbar django-debug-toolbar==3.8.1 # via -r dev.in -exceptiongroup==1.1.0 - # via pytest factory-boy==3.2.1 # via pytest-factoryboy faker==16.7.0 @@ -75,10 +73,6 @@ termcolor==2.2.0 # via # pytest-sugar # snapshottest -tomli==2.0.1 - # via - # coverage - # pytest typing-extensions==4.4.0 # via pytest-factoryboy wasmer==1.1.0 diff --git a/requirements/production.txt b/requirements/production.txt index 3333386f4e89a4345670321d51b646a4098aa598..992947ab06bdebf5c6edc9fe1cbc51c9b1b34600 100644 --- a/requirements/production.txt +++ b/requirements/production.txt @@ -1,6 +1,6 @@ # -# This file is autogenerated by pip-compile with python 3.10 -# To update, run: +# This file is autogenerated by pip-compile with Python 3.11 +# by the following command: # # pip-compile production.in #