Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update from main #371

Merged
merged 2 commits into from
Apr 18, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions backend/src/appointment/database/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,7 @@ class Attendee(Base):
id = Column(Integer, primary_key=True, index=True)
email = Column(StringEncryptedType(String, secret, AesEngine, "pkcs5", length=255), index=True)
name = Column(StringEncryptedType(String, secret, AesEngine, "pkcs5", length=255), index=True)
timezone = Column(String(255), index=True)

slots = relationship("Slot", cascade="all,delete", back_populates="attendee")

Expand Down
1 change: 1 addition & 0 deletions backend/src/appointment/database/schemas.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
class AttendeeBase(BaseModel):
email: str
name: str | None = None
timezone: str


class Attendee(AttendeeBase):
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
"""add attendee timezone

Revision ID: 89e1197d980d
Revises: fadd0d1ef438
Create Date: 2024-04-18 08:23:55.660065

"""
from alembic import op
import sqlalchemy as sa


# revision identifiers, used by Alembic.
revision = '89e1197d980d'
down_revision = 'fadd0d1ef438'
branch_labels = None
depends_on = None


def upgrade() -> None:
op.add_column('attendees', sa.Column('timezone', sa.String(255), index=True))


def downgrade() -> None:
op.drop_column('attendees', 'timezone')
15 changes: 12 additions & 3 deletions backend/src/appointment/routes/schedule.py
Original file line number Diff line number Diff line change
Expand Up @@ -220,7 +220,12 @@ def request_schedule_availability_slot(
# human readable date in subscribers timezone
# TODO: handle locale date representation
date = slot.start.replace(tzinfo=timezone.utc).astimezone(ZoneInfo(subscriber.timezone)).strftime("%c")
date = f"{date}, {slot.duration} minutes"
date = f"{date}, {slot.duration} minutes ({subscriber.timezone})"

# human readable date in attendee timezone
# TODO: handle locale date representation
attendee_date = slot.start.replace(tzinfo=timezone.utc).astimezone(ZoneInfo(slot.attendee.timezone)).strftime("%c")
attendee_date = f"{attendee_date}, {slot.duration} minutes ({slot.attendee.timezone})"

# Create a pending appointment
attendee_name = slot.attendee.name if slot.attendee.name is not None else slot.attendee.email
Expand All @@ -246,7 +251,7 @@ def request_schedule_availability_slot(
background_tasks.add_task(send_confirmation_email, url=url, attendee=attendee, date=date, to=subscriber.email)

# Sending pending email to attendee
background_tasks.add_task(send_pending_email, owner=subscriber, date=date, to=slot.attendee.email)
background_tasks.add_task(send_pending_email, owner=subscriber, date=attendee_date, to=slot.attendee.email)

# Mini version of slot, so we can grab the newly created slot id for tests
return schemas.SlotOut(
Expand Down Expand Up @@ -416,5 +421,9 @@ def decide_on_schedule_availability_slot(

return schemas.AvailabilitySlotAttendee(
slot=schemas.SlotBase(start=slot.start, duration=slot.duration),
attendee=schemas.AttendeeBase(email=slot.attendee.email, name=slot.attendee.name)
attendee=schemas.AttendeeBase(
email=slot.attendee.email,
name=slot.attendee.name,
timezone=slot.attendee.timezone
)
)
6 changes: 3 additions & 3 deletions backend/test/integration/test_appointment.py
Original file line number Diff line number Diff line change
Expand Up @@ -338,7 +338,7 @@ def test_attendee_selects_slot_of_unavailable_appointment(self, with_db, with_cl

response = with_client.put(
f"/apmt/public/{generated_appointment.slug}",
json={"slot_id": generated_appointment.slots[-1].id, "attendee": {"email": "a", "name": "b"}},
json={"slot_id": generated_appointment.slots[-1].id, "attendee": {"email": "a", "name": "b", "timezone": "c"}},
)
assert response.status_code == 403, response.text

Expand All @@ -347,7 +347,7 @@ def test_attendee_selects_slot_of_missing_appointment(self, with_client, make_ap

response = with_client.put(
f"/apmt/public/{generated_appointment}",
json={"slot_id": generated_appointment.slots[0].id, "attendee": {"email": "a", "name": "b"}},
json={"slot_id": generated_appointment.slots[0].id, "attendee": {"email": "a", "name": "b", "timezone": "c"}},
)
assert response.status_code == 404, response.text

Expand All @@ -356,7 +356,7 @@ def test_attendee_selects_missing_slot_of_existing_appointment(self, with_client

response = with_client.put(
f"/apmt/public/{generated_appointment.id}",
json={"slot_id": generated_appointment.slots[0].id + 1, "attendee": {"email": "a", "name": "b"}},
json={"slot_id": generated_appointment.slots[0].id + 1, "attendee": {"email": "a", "name": "b", "timezone": "c"}},
)
assert response.status_code == 404, response.text

Expand Down
3 changes: 2 additions & 1 deletion backend/test/integration/test_schedule.py
Original file line number Diff line number Diff line change
Expand Up @@ -462,7 +462,8 @@ def bust_cached_events(self, all_calendars = False):
),
attendee=schemas.AttendeeBase(
email='[email protected]',
name='Greg'
name='Greg',
timezone='Europe/Berlin'
)
).model_dump(mode='json')

Expand Down
2 changes: 1 addition & 1 deletion backend/test/unit/test_mailer.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ def test_confirm(self, faker, with_l10n):
deny_url = 'https://example.org/no'
fake_email = '[email protected]'
now = datetime.datetime.now()
attendee = schemas.AttendeeBase(email=faker.email(), name=faker.name())
attendee = schemas.AttendeeBase(email=faker.email(), name=faker.name(), timezone='Europe/Berlin')

mailer = ConfirmationMail(confirm_url, deny_url, attendee, now, to=fake_email)
assert mailer.html()
Expand Down
10 changes: 4 additions & 6 deletions frontend/src/components/BookingModal.vue
Original file line number Diff line number Diff line change
Expand Up @@ -79,9 +79,7 @@
</template>

<script setup>
import {
inject, computed, reactive, ref, onMounted,
} from 'vue';
import { inject, computed, reactive, ref, onMounted } from 'vue';
import { timeFormat } from '@/utils';
import { useI18n } from 'vue-i18n';
import { useRoute } from 'vue-router';
Expand Down Expand Up @@ -111,15 +109,14 @@ const props = defineProps({

// Store
const bookingModalStore = useBookingModalStore();
const {
open, state, stateData, isLoading, hasErrors, isFinished, isEditable,
} = storeToRefs(bookingModalStore);
const { open, state, stateData, isLoading, hasErrors, isFinished, isEditable } = storeToRefs(bookingModalStore);

// Refs

const attendee = reactive({
name: '',
email: '',
timezone: dj.tz.guess(),
});

const bookingForm = ref();
Expand All @@ -145,6 +142,7 @@ onMounted(() => {
if (user.exists()) {
attendee.name = user.data.name;
attendee.email = user.data.email;
attendee.timezone = user.data.timezone;
}
});
</script>
2 changes: 1 addition & 1 deletion frontend/src/elements/CalendarEvent.vue
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@
:style="{
borderColor: eventColor(eventData, placeholder).border,
backgroundColor: monthView || placeholder ? eventColor(eventData, placeholder).background : eventData.calendar_color,
color: !monthView ? getAccessibleColor(eventData.calendar_color) : null,
color: !monthView && !placeholder ? getAccessibleColor(eventData.calendar_color) : null,
}"
@click="emit('eventSelected', day)"
@mouseenter="element => showDetails ? popup=showEventPopup(element, event, popupPosition) : null"
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/elements/PrimaryButton.vue
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@
<script setup>
import { ref } from 'vue';
import { useI18n } from 'vue-i18n';
import ToolTip from '@/elements/Tooltip';
import ToolTip from '@/elements/ToolTip';

// icons
import { IconClipboardCheck, IconCopy } from '@tabler/icons-vue';
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/elements/SecondaryButton.vue
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@
<script setup>
import { ref } from 'vue';
import { useI18n } from 'vue-i18n';
import ToolTip from '@/elements/Tooltip';
import ToolTip from '@/elements/ToolTip';

// icons
import { IconClipboardCheck, IconCopy } from '@tabler/icons-vue';
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/elements/TextButton.vue
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
<script setup>
import { ref } from 'vue';
import { useI18n } from 'vue-i18n';
import ToolTip from '@/elements/Tooltip';
import ToolTip from '@/elements/ToolTip';

// icons
import { IconCopy, IconClipboardCheck } from '@tabler/icons-vue';
Expand Down