diff options
author | Aspen Smith <grfn@gws.fyi> | 2024-02-12T03·00-0500 |
---|---|---|
committer | clbot <clbot@tvl.fyi> | 2024-02-14T19·37+0000 |
commit | 82ecd61f5c699cf3af6c4eadf47a1c52b1d696c6 (patch) | |
tree | 429c5e078528000591742ec3211bc768ae913a78 /users/aspen/bbbg/src/bbbg/handlers/events.clj | |
parent | 0ba476a4266015f278f18d74094299de74a5a111 (diff) |
chore(users): grfn -> aspen r/7511
Change-Id: I6c6847fac56f0a9a1a2209792e00a3aec5e672b9 Reviewed-on: https://cl.tvl.fyi/c/depot/+/10809 Autosubmit: aspen <root@gws.fyi> Reviewed-by: sterni <sternenseemann@systemli.org> Tested-by: BuildkiteCI Reviewed-by: lukegb <lukegb@tvl.fyi>
Diffstat (limited to 'users/aspen/bbbg/src/bbbg/handlers/events.clj')
-rw-r--r-- | users/aspen/bbbg/src/bbbg/handlers/events.clj | 259 |
1 files changed, 259 insertions, 0 deletions
diff --git a/users/aspen/bbbg/src/bbbg/handlers/events.clj b/users/aspen/bbbg/src/bbbg/handlers/events.clj new file mode 100644 index 000000000000..6f6d6f3585ae --- /dev/null +++ b/users/aspen/bbbg/src/bbbg/handlers/events.clj @@ -0,0 +1,259 @@ +(ns bbbg.handlers.events + (:require + [bbbg.db :as db] + [bbbg.db.attendee :as db.attendee] + [bbbg.db.event :as db.event] + [bbbg.event :as event] + [bbbg.handlers.core :refer [*authenticated?* page-response]] + [bbbg.meetup.import :refer [import-attendees!]] + [bbbg.util.display :refer [format-date pluralize]] + [bbbg.util.time :as t] + [bbbg.views.flash :as flash] + [compojure.coercions :refer [as-uuid]] + [compojure.core :refer [context GET POST]] + [java-time :refer [local-date]] + [ring.util.response :refer [not-found redirect]] + [bbbg.attendee :as attendee] + [bbbg.event-attendee :as event-attendee] + [bbbg.db.attendee-check :as db.attendee-check] + [bbbg.attendee-check :as attendee-check] + [bbbg.user :as user]) + (:import + java.time.format.FormatStyle)) + +(defn- num-attendees [event] + (str + (:num-attendees event) + (if (= (t/->LocalDate (::event/date event)) + (local-date)) + " Signed In" + (str " Attendee" (when-not (= 1 (:num-attendees event)) "s"))))) + +(def index-type->label + {:upcoming "Upcoming" + :past "Past"}) +(def other-index-type + {:upcoming :past + :past :upcoming}) + +(defn events-index + [{:keys [events num-events type]}] + [:div.page + [:div.page-header + [:h1 + (pluralize + num-events + (str (index-type->label type) " Event"))] + [:a {:href (str "/events" + (when (= :upcoming type) + "/past"))} + "View " + (index-type->label (other-index-type type)) + " Events"]] + (when *authenticated?* + [:a.button {:href "/events/new"} + "Create New Event"]) + [:ul.events-list + (for [event (sort-by + ::event/date + (comp - compare) + events)] + [:li + [:p + [:a {:href (str "/events/" (::event/id event))} + (format-date (::event/date event) + FormatStyle/FULL)]] + [:p + (pluralize (:num-rsvps event) "RSVP") + ", " + (num-attendees event)]])]]) + +(defn- import-attendee-list-form-group [] + [:div.form-group + [:label "Import Attendee List" + [:br] + [:input {:type :file + :name :attendees}]]]) + +(defn import-attendees-form [event] + [:form {:method :post + :action (str "/events/" (::event/id event) "/attendees") + :enctype "multipart/form-data"} + (import-attendee-list-form-group) + [:div.form-group + [:input {:type :submit + :value "Import"}]]]) + +(defn event-page [{:keys [event attendees]}] + [:div.page + [:div.page-header + [:h1 (format-date (::event/date event) + FormatStyle/FULL)] + [:div.spacer] + [:a.button {:href (str "/signup-forms/" (::event/id event) )} + "Go to Signup Form"] + [:form#delete-event + {:method :post + :action (str "/events/" (::event/id event) "/delete") + :data-confirm "Are you sure you want to delete this event?"} + [:input.error {:type "submit" + :value "Delete Event"}]]] + [:div.stats + [:p (pluralize (:num-rsvps event) "RSVP")] + [:p (num-attendees event)]] + [:div + (import-attendees-form event)] + [:div + [:table.attendees + [:thead + [:th "Meetup Name"] + [:th "Discord Name"] + [:th "RSVP"] + [:th "Signed In"] + [:th "Last Vaccination Check"]] + [:tbody + (for [attendee (sort-by (juxt (comp not ::event-attendee/rsvpd-attending?) + (comp not ::event-attendee/attended?) + (comp some? :last-check) + ::attendee/meetup-name) + attendees)] + [:tr + [:td.attendee-name (::attendee/meetup-name attendee)] + [:td + [:label.mobile-label "Discord Name: "] + (or (not-empty (::attendee/discord-name attendee)) + "—")] + [:td + [:label.mobile-label "RSVP: "] + (if (::event-attendee/rsvpd-attending? attendee) + [:span {:title "Yes"} "✔️"] + [:span {:title "No"} "❌"])] + [:td + [:label.mobile-label "Signed In: "] + (if (::event-attendee/attended? attendee) + [:span {:title "Yes"} "✔️"] + [:span {:title "No"} "❌"])] + [:td + [:label.mobile-label "Last Vaccination Check: "] + (if-let [last-check (:last-check attendee)] + (str "✔️ "(-> last-check + ::attendee-check/checked-at + format-date) + ", by " + (get-in last-check [:user ::user/username])) + (list + [:span {:title "Not Checked"} + "❌"] + " " + [:a {:href (str "/attendees/" + (::attendee/id attendee) + "/checks/edit")} + "Edit"]))]])]]]]) + +(defn import-attendees-page [{:keys [event]}] + [:div.page + [:h1 "Import Attendees for " (format-date (::event/date event))] + (import-attendees-form event)]) + +(defn event-form + ([] (event-form {})) + ([event] + [:div.page + [:div.page-header + [:h1 "Create New Event"]] + [:form {:method "POST" + :action "/events" + :enctype "multipart/form-data"} + [:div.form-group + [:label "Date" + [:input {:type "date" + :id "date" + :name "date" + :value (str (::event/date event))}]]] + (import-attendee-list-form-group) + [:div.form-group + [:input {:type "submit" + :value "Create Event"}]]]])) + +(defn- events-list-handler [db query type] + (let [events (db/list db (db.event/with-stats query)) + num-events (db/count db query)] + (page-response + (events-index {:events events + :num-events num-events + :type type})))) + +(defn events-routes [{:keys [db]}] + (context "/events" [] + (GET "/" [] + (events-list-handler db (db.event/upcoming) :upcoming)) + + (GET "/past" [] + (events-list-handler db (db.event/past) :past)) + + (GET "/new" [date] + (page-response + {:title "New Event"} + (event-form {::event/date date}))) + + (POST "/" [date attendees] + (let [event (db.event/create! db {::event/date date}) + message + (if attendees + (let [num-attendees + (import-attendees! db + (::event/id event) + (:tempfile attendees))] + (format "Event created with %d attendees" + num-attendees)) + "Event created")] + (-> (str "/signup-forms/" (::event/id event)) + redirect + (flash/add-flash {:flash/type :success + :flash/message message})))) + + (context "/:id" [id :<< as-uuid] + (GET "/" [] + (if-let [event (db/fetch db + (-> {:select [:event.*] + :from [:event] + :where [:= :event.id id]} + (db.event/with-stats)))] + (let [attendees (db.attendee-check/attendees-with-last-checks + db + (db/list db (db.attendee/for-event id)))] + (page-response + (event-page {:event event + :attendees attendees}))) + (not-found "Event Not Found"))) + + (POST "/delete" [] + (db/delete! db :event_attendee [:= :event-id id]) + (db/delete! db :event [:= :id id]) + (-> (redirect "/events") + (flash/add-flash + #:flash {:type :success + :message "Successfully deleted event"}))) + + (GET "/attendees/import" [] + (if-let [event (db/get db :event id)] + (page-response + (import-attendees-page {:event event})) + (not-found "Event Not Found"))) + + (POST "/attendees" [attendees] + (let [num-imported (import-attendees! db id (:tempfile attendees))] + (-> (redirect (str "/events/" id)) + (flash/add-flash + #:flash{:type :success + :message (format "Successfully imported %d attendees" + num-imported)}))))))) + +(comment + (def db (:db bbbg.core/system)) + + (-> (db/list db :event) + first + ::event/date + format-date) + ) |