def test_next_many_planned(db_connection): event1 = create_event(1, start_at=datetime(2021, 4, 15)) # noqa event2 = create_event(2, start_at=datetime(2021, 6, 1)) # noqa event3 = create_event(3, start_at=datetime(2021, 5, 3)) event4 = create_event(4, start_at=datetime(2021, 3, 15)) # noqa assert Event.next(today=date(2021, 5, 2)) == event3
def test_archive_listing(db_connection): event1 = create_event(1, start_at=datetime(2021, 4, 15)) event2 = create_event(2, start_at=datetime(2021, 5, 1)) event3 = create_event(3, start_at=datetime(2021, 5, 3)) # noqa event4 = create_event(4, start_at=datetime(2021, 3, 15)) assert Event.archive_listing(today=date(2021, 5, 2)) == [event2, event1, event4]
def test_list_speaking_members(db_connection): event1 = create_event(1) member1 = create_member(1) EventSpeaking.create(event=event1, speaker=member1) event2 = create_event(2) member2 = create_member(2) member3 = create_member(3) EventSpeaking.create(event=event2, speaker=member2) EventSpeaking.create(event=event2, speaker=member3) member4 = create_member(4) # noqa assert set(Event.list_speaking_members()) == {member1, member2, member3}
def main(): with db: members = MessageAuthor.members_listing() changes = [] top_members_limit = MessageAuthor.top_members_limit() log.info( f'members_count={len(members)}, top_members_limit={top_members_limit}' ) # ROLE_MOST_DISCUSSING messages_count_stats = calc_stats(members, lambda m: m.messages_count(), top_members_limit) log.info(f"messages_count {repr_stats(members, messages_count_stats)}") recent_messages_count_stats = calc_stats( members, lambda m: m.recent_messages_count(), top_members_limit) log.info( f"recent_messages_count {repr_stats(members, recent_messages_count_stats)}" ) most_discussing_members_ids = set(messages_count_stats.keys()) | set( recent_messages_count_stats.keys()) log.info( f"most_discussing_members: {repr_ids(members, most_discussing_members_ids)}" ) for member in members: changes.extend( evaluate_changes(member.id, member.roles, most_discussing_members_ids, ROLE_MOST_DISCUSSING)) # ROLE_MOST_HELPFUL upvotes_count_stats = calc_stats(members, lambda m: m.upvotes_count(), top_members_limit) log.info(f"upvotes_count {repr_stats(members, upvotes_count_stats)}") recent_upvotes_count_stats = calc_stats( members, lambda m: m.recent_upvotes_count(), top_members_limit) log.info( f"recent_upvotes_count {repr_stats(members, recent_upvotes_count_stats)}" ) most_helpful_members_ids = set(upvotes_count_stats.keys()) | set( recent_upvotes_count_stats.keys()) log.info( f"most_helpful_members: {repr_ids(members, most_helpful_members_ids)}" ) for member in members: changes.extend( evaluate_changes(member.id, member.roles, most_helpful_members_ids, ROLE_MOST_HELPFUL)) # ROLE_HAS_INTRO_AND_AVATAR intro_avatar_members_ids = [ member.id for member in members if member.has_avatar and member.has_intro() ] log.info( f"intro_avatar_members: {repr_ids(members, intro_avatar_members_ids)}" ) for member in members: changes.extend( evaluate_changes(member.id, member.roles, intro_avatar_members_ids, ROLE_HAS_INTRO_AND_AVATAR)) # ROLE_IS_NEW new_members_ids = [member.id for member in members if member.is_new()] log.info(f"new_members_ids: {repr_ids(members, new_members_ids)}") for member in members: changes.extend( evaluate_changes(member.id, member.roles, new_members_ids, ROLE_IS_NEW)) # ROLE_IS_SPEAKER speaking_members_ids = [ member.id for member in Event.list_speaking_members() ] log.info( f"speaking_members_ids: {repr_ids(members, speaking_members_ids)}") for member in members: changes.extend( evaluate_changes(member.id, member.roles, speaking_members_ids, ROLE_IS_SPEAKER)) if DISCORD_MUTATIONS_ENABLED: apply_changes(changes) else: log.warning( "Skipping Discord mutations, DISCORD_MUTATIONS_ENABLED not set")
def main(): path = DATA_DIR / 'events.yml' records = [ load_record(record.data) for record in load(path.read_text(), schema) ] if FLUSH_POSTERS: log.warning("Removing all existing posters, FLUSH_POSTERS is set") for poster_path in POSTERS_DIR.glob('*.png'): poster_path.unlink() with db: db.drop_tables([Event, EventSpeaking]) db.create_tables([Event, EventSpeaking]) # process data from the YAML, generate posters for record in records: name = record['title'] log.info(f"Creating '{name}'") speakers_ids = record.pop('speakers', []) event = Event.create(**record) for speaker_id in speakers_ids: try: avatar_path = next( (IMAGES_DIR / 'speakers').glob(f"{speaker_id}.*")) except StopIteration: log.info(f"Didn't find speaker avatar for {speaker_id}") avatar_path = None else: log.info(f"Downsizing speaker avatar for {speaker_id}") avatar_path = downsize_square_photo( avatar_path, 500).relative_to(IMAGES_DIR) log.info(f"Marking member {speaker_id} as a speaker") EventSpeaking.create(speaker=speaker_id, event=event, avatar_path=avatar_path) if event.logo_path: log.info(f"Checking '{event.logo_path}'") image_path = IMAGES_DIR / event.logo_path if not image_path.exists(): raise ValueError( f"Event '{name}' references '{image_path}', but it doesn't exist" ) log.info(f"Rendering poster for '{name}'") context = dict( event=model_to_dict(event, extra_attrs=['first_avatar_path'])) image_path = render_image_file('poster.html', context, POSTERS_DIR, filters={ 'md': md, 'local_time': local_time, 'weekday': weekday, }) event.poster_path = image_path.relative_to(IMAGES_DIR) event.save() log.info(f"Rendering Instagram poster for '{name}'") save_as_ig_square(image_path) # discord messages if DISCORD_MUTATIONS_ENABLED: post_next_event_messages() else: log.warning( "Skipping Discord mutations, DISCORD_MUTATIONS_ENABLED not set" )
async def post_next_event_messages(client): announcements_channel = await client.fetch_channel(ANNOUNCEMENTS_CHANNEL) events_chat_channel = await client.fetch_channel(EVENTS_CHAT_CHANNEL) event = Event.next() if not event: log.info("The next event is not announced yet") return speakers = ', '.join( [speaking.speaker.mention for speaking in event.list_speaking]) log.info("About to post a message 7 days prior to the event") if event.start_at.date() - timedelta(days=7) == date.today(): with db: message = Message.last_bot_message(ANNOUNCEMENTS_CHANNEL, '🗓', event.url) if message: log.info(f'Looks like the message already exists: {message.url}') else: log.info("Found no message, posting!") content = f"🗓 Už **za týden** bude v klubu „{event.title}” s {speakers}! {event.url}" await announcements_channel.send(content) else: log.info("It's not 1 day prior to the event") log.info("About to post a message 1 day prior to the event") if event.start_at.date() - timedelta(days=1) == date.today(): with db: message = Message.last_bot_message(ANNOUNCEMENTS_CHANNEL, '🤩', event.url) if message: log.info(f'Looks like the message already exists: {message.url}') else: log.info("Found no message, posting!") content = f"🤩 Už **zítra v {event.start_at_prg:%H:%M}** bude v klubu „{event.title}” s {speakers}! {event.url}" await announcements_channel.send(content) else: log.info("It's not 1 day prior to the event") log.info("About to post a message on the day when the event is") if event.start_at.date() == date.today(): with db: message = Message.last_bot_message(ANNOUNCEMENTS_CHANNEL, '⏰', event.url) if message: log.info(f'Looks like the message already exists: {message.url}') else: log.info("Found no message, posting!") content = f"⏰ @everyone Už **dnes v {event.start_at_prg:%H:%M}** bude v klubu „{event.title}” s {speakers}! Odehrávat se to bude v klubovně, případné dotazy v {events_chat_channel.mention} 💬 Akce se nahrávají, odkaz na záznam se objeví v tomto kanále. {event.url}" await announcements_channel.send(content) else: log.info("It's not the day when the event is") log.info( "About to post a message to event chat on the day when the event is") if event.start_at.date() == date.today(): with db: message = Message.last_bot_message(EVENTS_CHAT_CHANNEL, '👋', event.url) if message: log.info(f'Looks like the message already exists: {message.url}') else: log.info("Found no message, posting!") content = [ f"👋 Už **dnes v {event.start_at_prg:%H:%M}** tady bude probíhat „{event.title}” s {speakers} (viz {announcements_channel.mention}). Tento kanál slouží k pokládání dotazů, sdílení odkazů, slajdů k prezentaci…", "", "⚠️ Ve výchozím nastavení Discord udělá zvuk při každé aktivitě v hlasovém kanále, např. při připojení nového účastníka, odpojení, vypnutí zvuku, zapnutí, apod. Zvuky si vypni v _User Settings_, stránka _Notifications_, sekce _Sounds_. Většina zvuků souvisí s hovory, takže je potřeba povypínat skoro vše.", "", f"ℹ️ {strip_links(event.description.strip())}", "", f"🦸 {strip_links(event.bio).strip()}" "", "", f"👉 {event.url}", ] await events_chat_channel.send('\n'.join(content)) else: log.info("It's not the day when the event is")
def test_next_nothing_planned(db_connection): create_event(1, start_at=datetime(2021, 4, 15)) create_event(2, start_at=datetime(2021, 5, 1)) create_event(4, start_at=datetime(2021, 3, 15)) assert Event.next(today=date(2021, 5, 2)) is None
def create_event(id, **kwargs): return Event.create(id=id, **{ 'title': f"Event #{id}", 'description': 'Markdown **description** of the _event_.', 'start_at': datetime.now(), **kwargs})