feat: add entity-scoped application events
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
parent
3364eacbcc
commit
e787359c54
40 changed files with 2143 additions and 1437 deletions
|
|
@ -166,7 +166,16 @@ func (s *ScheduledInterviewService) UpdateStatus(
|
|||
if !valid {
|
||||
return model.ScheduledInterview{}, fmt.Errorf("%w: invalid interview status transition", ErrInvalidState)
|
||||
}
|
||||
return s.store.UpdateScheduledInterviewStatus(ctx, interviewID, status)
|
||||
updated, err := s.store.UpdateScheduledInterviewStatus(ctx, interviewID, status)
|
||||
if err != nil {
|
||||
return model.ScheduledInterview{}, err
|
||||
}
|
||||
if err := s.bus.PublishInterviewEvent(ctx, eventbus.InterviewEvent{
|
||||
Type: "status.updated", InterviewID: interviewID, Status: updated.Status,
|
||||
}); err != nil {
|
||||
return model.ScheduledInterview{}, fmt.Errorf("publish persisted interview status: %w", err)
|
||||
}
|
||||
return updated, nil
|
||||
}
|
||||
|
||||
func (s *ScheduledInterviewService) UpdateDocument(
|
||||
|
|
@ -243,10 +252,24 @@ func (s *ScheduledInterviewService) UpdateInbox(
|
|||
if status != "accepted" && status != "declined" {
|
||||
return model.ScheduledInterview{}, fmt.Errorf("%w: attendee status must be accepted or declined", ErrValidation)
|
||||
}
|
||||
if _, err := s.store.UpdateAttendeeStatus(ctx, interviewID, userID, status); err != nil {
|
||||
attendee, err := s.store.UpdateAttendeeStatus(ctx, interviewID, userID, status)
|
||||
if err != nil {
|
||||
return model.ScheduledInterview{}, err
|
||||
}
|
||||
return s.Get(ctx, userID, interviewID)
|
||||
updated, err := s.Get(ctx, userID, interviewID)
|
||||
if err != nil {
|
||||
return model.ScheduledInterview{}, err
|
||||
}
|
||||
if err := s.bus.PublishInterviewEvent(ctx, eventbus.InterviewEvent{
|
||||
Type: "attendee.updated", InterviewID: interviewID,
|
||||
Attendee: &eventbus.InterviewAttendeeEvent{
|
||||
UserID: attendee.UserID, DisplayName: attendee.User.DisplayName,
|
||||
Email: attendee.User.Email, Status: attendee.Status,
|
||||
},
|
||||
}); err != nil {
|
||||
return model.ScheduledInterview{}, fmt.Errorf("publish persisted attendee status: %w", err)
|
||||
}
|
||||
return updated, nil
|
||||
}
|
||||
|
||||
func (s *ScheduledInterviewService) ListCalendar(
|
||||
|
|
@ -303,7 +326,7 @@ func (s *ScheduledInterviewService) subscribeToInterview(
|
|||
if event.InterviewID != interviewID {
|
||||
continue
|
||||
}
|
||||
if documentsOnly && event.Type != "document.updated" {
|
||||
if documentsOnly && event.Type != "document.updated" && event.Type != "status.updated" {
|
||||
continue
|
||||
}
|
||||
select {
|
||||
|
|
|
|||
|
|
@ -34,6 +34,7 @@ type scheduledStore struct {
|
|||
createdIDs []uint
|
||||
status string
|
||||
document string
|
||||
attendee model.InterviewAttendee
|
||||
}
|
||||
|
||||
func (f *scheduledStore) GetInvitation(context.Context, uint, uint) (model.Invitation, error) {
|
||||
|
|
@ -68,6 +69,20 @@ func (f *scheduledStore) UpdateScheduledInterviewDocument(
|
|||
f.interview.SharedDocument = document
|
||||
return f.interview, nil
|
||||
}
|
||||
func (f *scheduledStore) UpdateAttendeeStatus(
|
||||
_ context.Context, _, userID uint, status string,
|
||||
) (model.InterviewAttendee, error) {
|
||||
f.attendee = model.InterviewAttendee{
|
||||
UserID: userID, Status: status,
|
||||
User: model.User{ID: userID, DisplayName: "Ada", Email: "ada@example.com"},
|
||||
}
|
||||
for index := range f.interview.Attendees {
|
||||
if f.interview.Attendees[index].UserID == userID {
|
||||
f.interview.Attendees[index] = f.attendee
|
||||
}
|
||||
}
|
||||
return f.attendee, nil
|
||||
}
|
||||
func (f *scheduledStore) CreateInterviewNote(
|
||||
_ context.Context, value model.InterviewNote,
|
||||
) (model.InterviewNote, error) {
|
||||
|
|
@ -414,6 +429,7 @@ func TestUpdateDocumentPublishesEvent(t *testing.T) {
|
|||
ID: 9, Status: "scheduled", Attendees: []model.InterviewAttendee{{UserID: 1}},
|
||||
},
|
||||
}
|
||||
|
||||
bus := eventbus.NewMemoryBus()
|
||||
events, err := bus.SubscribeInterviewEvents(context.Background())
|
||||
if err != nil {
|
||||
|
|
@ -431,6 +447,36 @@ func TestUpdateDocumentPublishesEvent(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestStatusAndAttendeeUpdatesPublishEvents(t *testing.T) {
|
||||
store := &scheduledStore{
|
||||
fakeStore: &fakeStore{},
|
||||
interview: model.ScheduledInterview{
|
||||
ID: 9, Status: "scheduled",
|
||||
Attendees: []model.InterviewAttendee{{UserID: 1, Status: "pending"}},
|
||||
},
|
||||
}
|
||||
bus := eventbus.NewMemoryBus()
|
||||
events, err := bus.SubscribeInterviewEvents(context.Background())
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
interviews := NewScheduledInterviewService(store, bus)
|
||||
if _, err := interviews.UpdateStatus(context.Background(), 1, 9, "started"); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if event := <-events; event.Type != "status.updated" || event.Status != "started" {
|
||||
t.Fatalf("unexpected status event: %#v", event)
|
||||
}
|
||||
store.interview.Status = "scheduled"
|
||||
if _, err := interviews.UpdateInbox(context.Background(), 1, 9, "accepted"); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if event := <-events; event.Type != "attendee.updated" || event.Attendee == nil ||
|
||||
event.Attendee.UserID != 1 || event.Attendee.Status != "accepted" {
|
||||
t.Fatalf("unexpected attendee event: %#v", event)
|
||||
}
|
||||
}
|
||||
|
||||
func TestParticipantSubscriptionFiltersPrivateNotes(t *testing.T) {
|
||||
bus := eventbus.NewMemoryBus()
|
||||
interviews := NewScheduledInterviewService(&fakeStore{}, bus)
|
||||
|
|
@ -455,14 +501,27 @@ func TestParticipantSubscriptionFiltersPrivateNotes(t *testing.T) {
|
|||
}); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := bus.PublishInterviewEvent(ctx, eventbus.InterviewEvent{
|
||||
Type: "status.updated", InterviewID: 0, Status: "started",
|
||||
}); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
select {
|
||||
case event := <-events:
|
||||
if event.Type != "document.updated" || event.SharedDocument != "candidate-safe" {
|
||||
t.Fatalf("participant received unexpected event: %#v", event)
|
||||
t.Fatalf("participant received unexpected document event: %#v", event)
|
||||
}
|
||||
case <-time.After(time.Second):
|
||||
t.Fatal("participant did not receive document event")
|
||||
}
|
||||
select {
|
||||
case event := <-events:
|
||||
if event.Type != "status.updated" || event.Status != "started" {
|
||||
t.Fatalf("participant received unexpected event: %#v", event)
|
||||
}
|
||||
case <-time.After(time.Second):
|
||||
t.Fatal("participant did not receive status event")
|
||||
}
|
||||
}
|
||||
|
||||
func TestUserCreationHashesPasswordAndUsesCoInterviewerRole(t *testing.T) {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue