Skip to content
Snippets Groups Projects
Commit 12ea0a4a authored by Tomáš Valenta's avatar Tomáš Valenta
Browse files

wip - authorized instagram sync

parent 468ed4b3
No related branches found
No related tags found
3 merge requests!787Release,!743Add Redmine datasets to charts, Instagram feed to homepage,!742Add Instagram feed to homepage
Pipeline #12210 passed
import logging import logging
import requests import requests_cache
from main.models import MainHomePage, MainPersonPage from main.models import MainHomePage, MainPersonPage
...@@ -15,36 +15,50 @@ class InstagramDownloadService: ...@@ -15,36 +15,50 @@ class InstagramDownloadService:
""" """
def __init__(self, app_id: int, app_secret: str): def __init__(self, app_id: int, app_secret: str):
self.session = requests_cache.CachedSession("instagram_cache")
self.app_id = app_id self.app_id = app_id
self.app_secret = app_secret self.app_secret = app_secret
# https://www.instagram.com/web/search/topsearch/?context=user&count=1&query=that_snowden def get_user_info_list(self) -> list[str]:
# Useful Instagram username search API access_block = MainHomePage.objects.first().instagram_access
def get_username_list(self) -> list[str]: # TODO - Individual users' instagram info
instagram_usernames_block = MainHomePage.objects.first().instagram_usernames
person_username_list = ( return [
MainPersonPage.objects.filter(instagram_username__isnull=False) (
.values_list("instagram_username", flat=True) block["value"]["name"],
.distinct() block["value"]["user_id"],
block["value"]["access_token"]
) )
homepage_username_list = [ for block in access_block.raw_data
username_data["value"] for username_data in instagram_usernames_block.raw_data
] ]
# kvůli duplicitám udělám(e) list/set/list konverzi def parse_media_for_user(self, name, user_id, access_token):
return list({*person_username_list, *homepage_username_list}) 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]: if not recent_media.ok:
user_ids = [] logger.warning(
"Error getting media for user %s: %s",
user_id,
recent_media.status_code
)
for username in username_list: return
print(username)
return user_ids recent_media = recent_media.json()
print(recent_media)
def perform_update(self) -> None: 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))
...@@ -372,4 +372,18 @@ class CardLinkWithHeadlineBlock(CardLinkWithHeadlineBlockMixin): ...@@ -372,4 +372,18 @@ class CardLinkWithHeadlineBlock(CardLinkWithHeadlineBlockMixin):
label = "Karty odkazů s nadpisem" 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 # TwitterCarouselBlock
# 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'),
),
]
# 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'),
),
]
# 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'),
),
]
...@@ -142,9 +142,9 @@ class MainHomePage( ...@@ -142,9 +142,9 @@ class MainHomePage(
use_json_field=True, use_json_field=True,
) )
instagram_usernames = StreamField( instagram_access = StreamField(
[("username", CharBlock(label="Instagram uživatelské jméno"))], [("instagram_access", blocks.InstagramAccessBlock())],
verbose_name="Uživatelská jména pro synchronizované Instagram účty", verbose_name="Uživatelská jména a přístupové tokeny pro synchronizované Instagram účty",
blank=True, blank=True,
max_num=64, max_num=64,
use_json_field=True, use_json_field=True,
...@@ -167,7 +167,7 @@ class MainHomePage( ...@@ -167,7 +167,7 @@ class MainHomePage(
FieldPanel("social_links"), FieldPanel("social_links"),
FieldPanel("matomo_id"), FieldPanel("matomo_id"),
FieldPanel("twitter_usernames"), FieldPanel("twitter_usernames"),
FieldPanel("instagram_usernames"), FieldPanel("instagram_access"),
] ]
### EDIT HANDLERS ### EDIT HANDLERS
......
File added
...@@ -26,3 +26,4 @@ pypdf2 ...@@ -26,3 +26,4 @@ pypdf2
pyyaml pyyaml
fastjsonschema fastjsonschema
tweepy tweepy
requests-cache
# #
# 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: # by the following command:
# #
# pip-compile base.in # pip-compile base.in
...@@ -19,7 +19,10 @@ asttokens==2.2.1 ...@@ -19,7 +19,10 @@ asttokens==2.2.1
async-timeout==4.0.2 async-timeout==4.0.2
# via redis # via redis
attrs==22.2.0 attrs==22.2.0
# via ics # via
# cattrs
# ics
# requests-cache
backcall==0.2.0 backcall==0.2.0
# via ipython # via ipython
beautifulsoup4==4.11.2 beautifulsoup4==4.11.2
...@@ -32,6 +35,8 @@ bleach==6.0.0 ...@@ -32,6 +35,8 @@ bleach==6.0.0
# via -r base.in # via -r base.in
brotli==1.0.9 brotli==1.0.9
# via fonttools # via fonttools
cattrs==22.2.0
# via requests-cache
celery==5.2.7 celery==5.2.7
# via -r base.in # via -r base.in
certifi==2022.12.7 certifi==2022.12.7
...@@ -171,6 +176,8 @@ pillow==9.4.0 ...@@ -171,6 +176,8 @@ pillow==9.4.0
# weasyprint # weasyprint
pirates==0.6.0 pirates==0.6.0
# via -r base.in # via -r base.in
platformdirs==3.2.0
# via requests-cache
prompt-toolkit==3.0.36 prompt-toolkit==3.0.36
# via # via
# click-repl # click-repl
...@@ -218,9 +225,12 @@ requests==2.28.2 ...@@ -218,9 +225,12 @@ requests==2.28.2
# via # via
# -r base.in # -r base.in
# mozilla-django-oidc # mozilla-django-oidc
# requests-cache
# requests-oauthlib # requests-oauthlib
# tweepy # tweepy
# wagtail # wagtail
requests-cache==1.0.1
# via -r base.in
requests-oauthlib==1.3.1 requests-oauthlib==1.3.1
# via tweepy # via tweepy
sentry-sdk==1.15.0 sentry-sdk==1.15.0
...@@ -234,6 +244,7 @@ six==1.16.0 ...@@ -234,6 +244,7 @@ six==1.16.0
# ics # ics
# l18n # l18n
# python-dateutil # python-dateutil
# url-normalize
soupsieve==2.3.2.post1 soupsieve==2.3.2.post1
# via beautifulsoup4 # via beautifulsoup4
sqlparse==0.4.3 sqlparse==0.4.3
...@@ -254,9 +265,12 @@ traitlets==5.9.0 ...@@ -254,9 +265,12 @@ traitlets==5.9.0
# matplotlib-inline # matplotlib-inline
tweepy==4.12.1 tweepy==4.12.1
# via -r base.in # via -r base.in
url-normalize==1.4.3
# via requests-cache
urllib3==1.26.14 urllib3==1.26.14
# via # via
# requests # requests
# requests-cache
# sentry-sdk # sentry-sdk
vine==5.0.0 vine==5.0.0
# via # via
......
# #
# This file is autogenerated by pip-compile with python 3.10 # This file is autogenerated by pip-compile with Python 3.11
# To update, run: # by the following command:
# #
# pip-compile dev.in # pip-compile dev.in
# #
...@@ -16,8 +16,6 @@ django==4.1.6 ...@@ -16,8 +16,6 @@ django==4.1.6
# django-debug-toolbar # django-debug-toolbar
django-debug-toolbar==3.8.1 django-debug-toolbar==3.8.1
# via -r dev.in # via -r dev.in
exceptiongroup==1.1.0
# via pytest
factory-boy==3.2.1 factory-boy==3.2.1
# via pytest-factoryboy # via pytest-factoryboy
faker==16.7.0 faker==16.7.0
...@@ -75,10 +73,6 @@ termcolor==2.2.0 ...@@ -75,10 +73,6 @@ termcolor==2.2.0
# via # via
# pytest-sugar # pytest-sugar
# snapshottest # snapshottest
tomli==2.0.1
# via
# coverage
# pytest
typing-extensions==4.4.0 typing-extensions==4.4.0
# via pytest-factoryboy # via pytest-factoryboy
wasmer==1.1.0 wasmer==1.1.0
......
# #
# This file is autogenerated by pip-compile with python 3.10 # This file is autogenerated by pip-compile with Python 3.11
# To update, run: # by the following command:
# #
# pip-compile production.in # pip-compile production.in
# #
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment