Files @ 2a720bd46bb4
Branch filter:

Location: symposion_app/pinaxcon/registrasion/management/commands/update_schedule.py - annotation

Joel Addison
Tickets for LCA2021

Disable lots of inventory that does not exist for a virtual conf.
Add Swag Badge category and product.
Adjust attendee profile to hide irrelevant questions.
2591a943feec
2591a943feec
92adbb33140e
ed21bc03359b
8badb0cb99fa
ed21bc03359b
92adbb33140e
ed21bc03359b
619a31148786
619a31148786
92adbb33140e
2591a943feec
2591a943feec
2591a943feec
a7f26de2febc
2591a943feec
2591a943feec
619a31148786
619a31148786
2591a943feec
2591a943feec
2591a943feec
2591a943feec
2591a943feec
619a31148786
ed21bc03359b
2591a943feec
0d380cd8fc0a
0d380cd8fc0a
0d380cd8fc0a
0d380cd8fc0a
0d380cd8fc0a
2591a943feec
0d380cd8fc0a
ed21bc03359b
619a31148786
2591a943feec
2591a943feec
2591a943feec
2591a943feec
2591a943feec
2591a943feec
2591a943feec
2591a943feec
2591a943feec
619a31148786
0d380cd8fc0a
619a31148786
619a31148786
619a31148786
0d380cd8fc0a
619a31148786
619a31148786
2591a943feec
2591a943feec
a7f26de2febc
619a31148786
283aa5d22bb2
283aa5d22bb2
283aa5d22bb2
283aa5d22bb2
283aa5d22bb2
0d380cd8fc0a
283aa5d22bb2
283aa5d22bb2
619a31148786
0d380cd8fc0a
0d380cd8fc0a
2591a943feec
ed21bc03359b
ed21bc03359b
ed21bc03359b
0d380cd8fc0a
619a31148786
0d380cd8fc0a
619a31148786
0d380cd8fc0a
0d380cd8fc0a
ed21bc03359b
ed21bc03359b
ed21bc03359b
619a31148786
0d380cd8fc0a
a7f26de2febc
619a31148786
0d380cd8fc0a
ed21bc03359b
619a31148786
ed21bc03359b
ed21bc03359b
619a31148786
0d380cd8fc0a
0d380cd8fc0a
619a31148786
0d380cd8fc0a
619a31148786
ed21bc03359b
ed21bc03359b
619a31148786
ed21bc03359b
619a31148786
ed21bc03359b
ed21bc03359b
619a31148786
0d380cd8fc0a
0d380cd8fc0a
0d380cd8fc0a
ed21bc03359b
0d380cd8fc0a
0d380cd8fc0a
a7f26de2febc
0d380cd8fc0a
0d380cd8fc0a
ed21bc03359b
0d380cd8fc0a
0d380cd8fc0a
0d380cd8fc0a
0d380cd8fc0a
0d380cd8fc0a
0d380cd8fc0a
0d380cd8fc0a
0d380cd8fc0a
0d380cd8fc0a
0d380cd8fc0a
0d380cd8fc0a
0d380cd8fc0a
0d380cd8fc0a
20469223cb05
92adbb33140e
92adbb33140e
0d380cd8fc0a
8badb0cb99fa
92adbb33140e
92adbb33140e
92adbb33140e
92adbb33140e
92adbb33140e
92adbb33140e
20469223cb05
20469223cb05
20469223cb05
283aa5d22bb2
20469223cb05
0d380cd8fc0a
0d380cd8fc0a
0d380cd8fc0a
20469223cb05
20469223cb05
20469223cb05
92adbb33140e
a23f22dd0900
a23f22dd0900
92adbb33140e
20469223cb05
a23f22dd0900
0d380cd8fc0a
0d380cd8fc0a
0d380cd8fc0a
0d380cd8fc0a
283aa5d22bb2
283aa5d22bb2
283aa5d22bb2
283aa5d22bb2
283aa5d22bb2
283aa5d22bb2
283aa5d22bb2
283aa5d22bb2
283aa5d22bb2
283aa5d22bb2
283aa5d22bb2
283aa5d22bb2
283aa5d22bb2
283aa5d22bb2
283aa5d22bb2
283aa5d22bb2
283aa5d22bb2
283aa5d22bb2
0d380cd8fc0a
0d380cd8fc0a
0d380cd8fc0a
0d380cd8fc0a
0d380cd8fc0a
0d380cd8fc0a
0d380cd8fc0a
0d380cd8fc0a
0d380cd8fc0a
0d380cd8fc0a
283aa5d22bb2
from django.core.management.base import BaseCommand

from symposion.conference.models import Section, current_conference

from symposion.schedule.models import (Day, Presentation, Room, SlotKind, Schedule, Slot, SlotRoom)

from symposion.proposals.models import ProposalBase

from dateutil.parser import parse

from collections import Counter
from pathlib import Path
import csv


class Command(BaseCommand):
    known_headers = ["date", "start time", "end time", "kind", "rooms"]
    SLOTS = 'slots'
    TALKS = 'talks'

    help = "Updates the schedule based on two csv files, "\
           "one that gives all the talk slots, the other the talks."

    def add_arguments(self, parser):
        parser.add_argument(self.SLOTS, type=Path)
        parser.add_argument(self.TALKS, type=Path)

    def parse_slots(self, options):
        self.date_strs = set()
        self.room_names = set()
        self.slotkind_names = set()
        self.slot_details = {}

        slot_type_count = Counter()

        with open(options[self.SLOTS]) as csv_file:
            csv_reader = csv.reader(csv_file)

            headers = next(csv_reader)

            assert headers == self.known_headers

            for row in csv_reader:
                assert len(row) == len(self.known_headers)

                rowdate, start_time, end_time, kind, rooms = row
                self.slotkind_names.add(kind)

                if rowdate:
                    date = rowdate
                    self.date_strs.add(date)

                assert kind, "kind cannot be blank"

                slot_type_count[(date, kind)] += 1
                kindslot = f"{kind} {slot_type_count[(date, kind)]}"

                if rooms.strip():
                    for room in rooms.split(';'):
                        room = room.strip()
                        self.room_names.add(room)
                        self.slot_details[(date, kindslot, room)] = (start_time, end_time)

                elif self.exclusive(kind):
                    self.slot_details[(date, kindslot, None)] = (start_time, end_time)

    def parse_talks(self, options):
        self.talks = {}

        with open(options[self.TALKS]) as csv_file:
            csv_reader = csv.reader(csv_file)

            self.used_rooms = next(csv_reader)

            assert self.used_rooms[0] == '', "Cell (1, 1) must be empty"

            for room in self.used_rooms[1:]:
                assert room in self.room_names, f"Unknown room: {room}"

            for row in csv_reader:
                cell = row[0]

                if cell.rsplit(' ', 1)[0] in self.slotkind_names:
                    kindslot = cell

                    for i, room in enumerate(self.used_rooms[1:], 1):
                        talk_id = row[i]

                        if not talk_id:
                            continue

                        assert (date, kindslot, room) in self.slot_details,\
                            f"Slot ({date}, '{kindslot}', '{room}') not found"

                        self.talks[(date, kindslot, room)] = int(talk_id)

                else:
                    assert parse(row[0]), "Not a date: {row[0]}"

                    date = row[0]

                    for col in row[1:]:
                        assert col == '', f"All other columns must be empty: {date}"

    def create_simple_models(self):
        self.days = {}
        for date in self.date_strs:
            day, _created = Day.objects.get_or_create(
                schedule=self.schedule, date=date)
            self.days[date] = day

        self.rooms = {}
        for room_name in self.room_names:
            room, _created = Room.objects.get_or_create(
                schedule=self.schedule,
                name=room_name,
                order=self.used_rooms.index(room_name))
            self.rooms[room_name] = room

        self.slotkinds = {}
        for slotkind_name in self.slotkind_names:
            slotkind, _created = SlotKind.objects.get_or_create(
                schedule=self.schedule, label=slotkind_name)
            self.slotkinds[slotkind_name] = slotkind

    def create_complex_models(self):
        for details, talk_id in self.talks.items():
            date, kindslot, room_name = details
            kind_name = kindslot.rsplit(' ', 1)[0]

            (start_time, end_time) = self.slot_details[(date, kindslot, room_name)]

            proposal = ProposalBase.objects.filter(pk=talk_id).first()

            assert proposal, f"Could not find proposal {talk_id}"

            preso = Presentation.objects.filter(proposal_base=proposal).first()

            assert preso, f"Could not find Presentation for talk {talk_id}"

            if not preso.slot:
                exclusive = self.exclusive(kind_name)

                preso.slot = Slot.objects.create(
                    day=self.days[date],
                    kind=self.slotkinds[kind_name],
                    start=start_time,
                    end=end_time,
                    exclusive=exclusive)

            # FIXME update the preso.slot, e.g. if the day/time changes

            preso.save()

            # FIXME what happens if the room changes?
            slotroom, _create = SlotRoom.objects.get_or_create(
                slot=preso.slot,
                room=self.rooms[room_name])

    def create_exclusive_models(self):
        for (date, kindslot, room) in self.slot_details.keys():
            if room is None:
                start_time, end_time = self.slot_details[(date, kindslot, room)]

                kind_name = kindslot.rsplit(' ', 1)[0]
                slot = Slot.objects.create(
                    day=self.days[date],
                    kind=self.slotkinds[kind_name],
                    start=start_time,
                    end=end_time,
                    exclusive=True)
                slot.save()

    def exclusive(self, kind_name):
        # TODO the exclusive list should not be hard coded, another csv file maybe.
        return kind_name in ["plenary", "morning tea", "lunch", "afternoon tea"]

    def handle(self, *args, **options):
        self.parse_slots(options)
        self.parse_talks(options)

        conf = current_conference()
        section = Section.objects.filter(conference=conf, slug="main").all().first()
        self.schedule, _created = Schedule.objects.get_or_create(section=section)

        self.create_simple_models()
        self.create_complex_models()
        self.create_exclusive_models()