def patreon_oauth_callback(request): code = request.GET.get("code") if not code: return render( request, "error.html", { "title": "Что-то сломалось между нами и патреоном", "message": "Так бывает. Попробуйте залогиниться еще раз" }) try: auth_data = patreon.fetch_auth_data(code) user_data = patreon.fetch_user_data(auth_data["access_token"]) except PatreonException as ex: if "invalid_grant" in str(ex): return render( request, "error.html", { "title": "Тут такое дело 😭", "message": "Авторизация патреона — говно. " "Она не сразу понимает, что вы стали патроном и отдаёт " "статус «отказано» в первые несколько минут, а иногда и часов. " "Я уже написал им в саппорт, но пока вам надо немного подождать и авторизоваться снова. " "Если долго не будет пускать — напишите мне в личку на патреоне." }) return render( request, "error.html", { "message": "Не получилось загрузить ваш профиль с серверов патреона. " "Попробуйте еще раз, наверняка оно починится. " f"Но если нет, то вот текст ошибки, с которым можно пожаловаться мне в личку:", "data": str(ex) }) membership = patreon.parse_active_membership(user_data) if not membership: return render( request, "error.html", { "title": "Надо быть патроном, чтобы состоять в Клубе", "message": "Кажется, вы не патроните <a href=\"https://www.patreon.com/join/vas3k\">@vas3k</a>. " "А это одно из основных требований для входа в Клуб.<br><br>" "Ещё иногда бывает, что ваш банк отказывает патреону в снятии денег. " "Проверьте, всё ли там у них в порядке." }) now = datetime.utcnow() user, is_created = User.objects.get_or_create( membership_platform_type=User.MEMBERSHIP_PLATFORM_PATREON, membership_platform_id=membership.user_id, defaults=dict( email=membership.email, full_name=membership.full_name[:120], avatar=upload_image_from_url(membership.image) if membership.image else None, membership_started_at=membership.started_at, membership_expires_at=membership.expires_at, created_at=now, updated_at=now, is_email_verified=False, is_profile_complete=False, # redirect new users to an intro page ), ) if is_created: user.balance = membership.lifetime_support_cents / 100 else: user.membership_expires_at = membership.expires_at user.balance = membership.lifetime_support_cents / 100 # TODO: remove when the real money comes in user.membership_platform_data = { "access_token": auth_data["access_token"], "refresh_token": auth_data["refresh_token"], } user.save() session = Session.objects.create( user=user, token=random_string(length=32), created_at=now, expires_at=user.membership_expires_at, ) redirect_to = reverse("profile", args=[user.slug]) state = request.GET.get("state") if state: redirect_to += f"?{state}" response = redirect(redirect_to) response.set_cookie( key="token", value=session.token, max_age=settings.SESSION_COOKIE_AGE, httponly=True, secure=not settings.DEBUG, ) return response
def initialize(config, board_slug, upload_favicons, always_yes): yaml_file = os.path.join(BASE_DIR, config) with open(yaml_file) as f: try: config = yaml.load(f.read(), Loader=yaml.FullLoader) except yaml.YAMLError as ex: print(f"Bad YAML file '{yaml_file}': {ex}") exit(1) if not always_yes: input( f"Initializing feeds from {yaml_file}. Press Enter to continue...") for board_index, board_config in enumerate(config.get("boards") or []): if board_slug and board_config["slug"] != board_slug: continue board_name = board_config.get("name") or board_config["slug"] print(f"Creating board: {board_name}...") board, is_created = Board.objects.update_or_create( slug=board_config["slug"], defaults=dict( name=board_name or board_config["slug"], avatar=board_config["curator"].get("avatar"), curator_name=board_config["curator"].get("name"), curator_title=board_config["curator"].get("title"), curator_footer=board_config["curator"].get("footer"), curator_bio=board_config["curator"].get("bio"), curator_url=board_config["curator"].get("url"), is_private=board_config.get("is_private"), is_visible=board_config.get("is_visible"), index=board_index, )) for block_index, block_config in enumerate( board_config.get("blocks") or []): block_name = block_config.get("name") or "" print(f"\nCreating block: {block_name}...") block, is_created = BoardBlock.objects.update_or_create( board=board, slug=block_config["slug"], defaults=dict( name=block_name, index=block_index, view=block_config.get("view") or BoardBlock.DEFAULT_VIEW, )) if not block_config.get("feeds"): continue updated_feed_urls = set() for feed_index, feed_config in enumerate( block_config.get("feeds") or []): feed_name = feed_config.get("name") feed_mix = feed_config.get("mix") if feed_mix: feed_url = feed_config.get( "url") or f"mix:{'|'.join(feed_mix)}" feed_rss = None else: feed_url = feed_config["url"] feed_rss = feed_config["rss"] updated_feed_urls.add(feed_url) print(f"Creating or updating feed {feed_name} ({feed_url})...") feed, is_created = BoardFeed.objects.update_or_create( board=board, block=block, url=feed_url, defaults=dict( rss=feed_rss, mix=feed_mix, name=feed_name, comment=feed_config.get("comment"), icon=feed_config.get("icon"), index=feed_index, columns=feed_config.get("columns") or 1, conditions=feed_config.get("conditions"), is_parsable=feed_config.get("is_parsable", True), view=feed_config.get("view") or BoardFeed.DEFAULT_VIEW, )) html = None if not feed.mix: if not feed.icon: feed.icon = DOMAIN_FAVICONS.get(parse_domain(feed_url)) if not feed.icon: html = html or load_page_html(feed_url) icon = feed_config.get("icon") if not icon: icon = find_favicon(feed_url, html) print(f"- found favicon: {icon}") if upload_favicons: icon = upload_image_from_url(icon) print(f"- uploaded favicon: {icon}") feed.icon = icon feed.save() # delete unused feeds BoardFeed.objects.filter( board=board, block=block).exclude(url__in=updated_feed_urls).delete() # delete unused blocks BoardBlock.objects.filter(board=board, ).exclude(slug__in={ block["slug"] for block in board_config.get("blocks") or [] }).delete() print("Done ✅")
def patreon_oauth_callback(request): code = request.GET.get("code") if not code: return render( request, "error.html", { "message": "Что-то сломалось между нами и патреоном. Так бывает. Попробуйте залогиниться еще раз." }) try: auth_data = patreon.fetch_auth_data(code) user_data = patreon.fetch_user_data(auth_data["access_token"]) except PatreonException as ex: if "invalid_grant" in str(ex): return render( request, "error.html", { "message": "Тут такое дело. Авторизация патреона — говно. " "Она не сразу понимает, что вы стали моим патроном и отдаёт мне ошибку. " "Я уже написал им в саппорт, но пока вам надо немного подождать и авторизоваться снова. " "Обычно тогда срабатывает. Если нет — напишите мне в личные сообщения на патреоне." }) return render( request, "error.html", { "message": "Не получилось загрузить ваш профиль с серверов патреона. " "Попробуйте еще раз, наверняка оно починится. " f"Но если нет, то вот текст ошибки, с которым можно пожаловаться мне в личку:", "data": str(ex) }) membership = patreon.parse_active_membership(user_data) if not membership: return render( request, "error.html", { "message": "Надо быть патроном чтобы состоять в клубе.<br>" '<a href="https://www.patreon.com/join/vas3k">Станьте им здесь!</a>' }) now = datetime.utcnow() user, is_created = User.objects.get_or_create( membership_platform_type=User.MEMBERSHIP_PLATFORM_PATREON, membership_platform_id=membership.user_id, defaults=dict( email=membership.email, full_name=membership.full_name[:120], avatar=upload_image_from_url(membership.image) if membership.image else None, membership_started_at=membership.started_at, membership_expires_at=membership.expires_at, created_at=now, updated_at=now, is_email_verified=False, is_profile_complete=False, # redirect new users to an intro page ), ) if is_created: user.balance = membership.lifetime_support_cents / 100 else: user.membership_expires_at = membership.expires_at user.balance = membership.lifetime_support_cents / 100 # TODO: remove when the real money comes in user.membership_platform_data = { "access_token": auth_data["access_token"], "refresh_token": auth_data["refresh_token"], } user.save() session = Session.objects.create( user=user, token=random_string(length=32), created_at=now, expires_at=first_day_of_next_month(now), ) redirect_to = reverse("profile", args=[user.slug]) state = request.GET.get("state") if state: redirect_to += f"?{state}" response = redirect(redirect_to) response.set_cookie( key="token", value=session.token, max_age=settings.SESSION_COOKIE_AGE, httponly=True, secure=not settings.DEBUG, ) return response
def initialize(config, board_slug, upload_favicons, always_yes): yaml_file = os.path.join(BASE_DIR, config) with open(yaml_file) as f: try: config = yaml.load(f.read(), Loader=yaml.FullLoader) except yaml.YAMLError as ex: print(f"Bad YAML file '{yaml_file}': {ex}") exit(1) if not always_yes: input( f"Initializing feeds from {yaml_file}. Press Enter to continue...") for board_index, board_config in enumerate(config.get("boards") or []): if board_slug and board_config["slug"] != board_slug: continue board_name = board_config.get("name") or board_config["slug"] print(f"Creating board: {board_name}...") board, is_created = Board.objects.get_or_create( slug=board_config["slug"], defaults=dict( name=board_name, avatar=board_config["curator"].get("avatar"), curator_name=board_config["curator"].get("name"), curator_title=board_config["curator"].get("title"), curator_footer=board_config["curator"].get("footer"), curator_bio=board_config["curator"].get("bio"), curator_url=board_config["curator"].get("url"), is_private=board_config.get("is_private"), is_visible=board_config.get("is_visible"), index=board_index, )) if not is_created: # update existing values board.name = board_config.get("name") or board_config["slug"] board.avatar = board_config["curator"].get("avatar") board.curator_name = board_config["curator"].get("name") board.curator_title = board_config["curator"].get("title") board.curator_footer = board_config["curator"].get("footer") board.curator_bio = board_config["curator"].get("bio") board.curator_url = board_config["curator"].get("url") board.is_private = board_config.get("is_private") board.is_visible = board_config.get("is_visible") board.index = board_index board.save() for block_index, block_config in enumerate( board_config.get("blocks") or []): block_name = block_config.get("name") or "" print(f"\nCreating block: {block_name}...") block, is_created = BoardBlock.objects.get_or_create( board=board, slug=block_config["slug"], defaults=dict(name=block_name, index=block_index)) if not is_created: block.index = block_index block.name = block_name block.save() if not block_config.get("feeds"): continue for feed_index, feed_config in enumerate( block_config.get("feeds") or []): feed_name = feed_config.get("name") feed_url = feed_config["url"] print(f"Creating or updating feed: {feed_name}...") feed, is_created = BoardFeed.objects.get_or_create( board=board, block=block, url=feed_config["url"], defaults=dict(rss=feed_config.get("rss"), name=feed_name, comment=feed_config.get("comment"), icon=feed_config.get("icon"), index=feed_index, columns=feed_config.get("columns") or 1, conditions=feed_config.get("conditions"), is_parsable=feed_config.get( "is_parsable", True))) if not is_created: feed.rss = feed_config.get("rss") feed.name = feed_name feed.comment = feed_config.get("comment") feed.index = feed_index feed.columns = feed_config.get("columns") or 1 feed.conditions = feed_config.get("conditions") feed.is_parsable = feed_config.get("is_parsable", True) html = None if not feed.rss: html = html or load_page_html(feed_url) rss_url = feed_config.get("rss") if not rss_url: rss_url = find_rss_feed(feed_url, html) if not rss_url: print(f"RSS feed for '{feed_name}' not found. " f"Please specify 'rss' key.") exit(1) print(f"- found RSS: {rss_url}") feed.rss = rss_url if not feed.icon: html = html or load_page_html(feed_url) icon = feed_config.get("icon") if not icon: icon = find_favicon(feed_url, html) print(f"- found favicon: {icon}") if upload_favicons: icon = upload_image_from_url(icon) print(f"- uploaded favicon: {icon}") feed.icon = icon feed.save() # delete unused feeds BoardFeed.objects.filter( board=board, block=block).exclude(url__in={ feed["url"] for feed in block_config.get("feeds") or [] }).delete() # delete unused blocks BoardBlock.objects.filter(board=board, ).exclude(slug__in={ block["slug"] for block in board_config.get("blocks") or [] }).delete() print("Done ✅")