Skip to content

Commit

Permalink
Create the resources for Munihac2024
Browse files Browse the repository at this point in the history
(copied from munihac2022 with minimal adjustments)
  • Loading branch information
Alberto Diaz Dorado committed May 4, 2024
1 parent 148401e commit 95ccda2
Show file tree
Hide file tree
Showing 10 changed files with 568 additions and 0 deletions.
2 changes: 2 additions & 0 deletions lib/Zureg/Hackathon.hs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import System.Environment (lookupEnv)
import Zureg.Hackathon.Interface
import qualified Zureg.Hackathon.MuniHac2020 as MuniHac2020
import qualified Zureg.Hackathon.MuniHac2022 as MuniHac2022
import qualified Zureg.Hackathon.MuniHac2024 as MuniHac2024
import qualified Zureg.Hackathon.ZuriHac2021 as ZuriHac2021
import qualified Zureg.Hackathon.ZuriHac2022 as ZuriHac2022
import qualified Zureg.Hackathon.ZuriHac2023 as ZuriHac2023
Expand Down Expand Up @@ -41,6 +42,7 @@ hackathons :: [(String, IO SomeHackathon)]
hackathons =
[ ("munihac2020", SomeHackathon <$> MuniHac2020.newHackathon)
, ("munihac2022", SomeHackathon <$> MuniHac2022.newHackathon)
, ("munihac2024", SomeHackathon <$> MuniHac2024.newHackathon)
, ("zurihac2021", SomeHackathon <$> ZuriHac2021.newHackathon)
, ("zurihac2022", SomeHackathon <$> ZuriHac2022.newHackathon)
, ("zurihac2023", SomeHackathon <$> ZuriHac2023.newHackathon)
Expand Down
61 changes: 61 additions & 0 deletions lib/Zureg/Hackathon/MuniHac2024.hs
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE RecordWildCards #-}
module Zureg.Hackathon.MuniHac2024
( newHackathon
) where

import qualified Data.Text as T
import qualified Text.Blaze.Html5 as H
import System.Environment (getEnv)
import qualified Zureg.Captcha.ReCaptcha as ReCaptcha
import qualified Zureg.Database as Database
import Zureg.Hackathon.Interface (Hackathon)
import qualified Zureg.Hackathon.Interface as Hackathon
import qualified Zureg.Hackathon.MuniHac2024.Form as MH24
import qualified Zureg.Hackathon.MuniHac2024.Model as MH24
import Zureg.Model
import qualified Zureg.SendEmail as SendEmail

newHackathon :: IO (Hackathon MH24.RegisterInfo)
newHackathon = do
scannerSecret <- T.pack <$> getEnv "ZUREG_SCANNER_SECRET"
email <- T.pack <$> getEnv "ZUREG_EMAIL"

reCaptchaSecret <- T.pack <$> getEnv "ZUREG_RECAPTCHA_SECRET"
captcha <- ReCaptcha.new ReCaptcha.Config
{ ReCaptcha.cSiteKey = "6Lcmk7wZAAAAAKMmP6sKNvd5gVI8aGaMrWjE3JkZ"
, ReCaptcha.cSecretKey = reCaptchaSecret
}

return Hackathon.Hackathon
{ Hackathon.name = "MuniHac 2024"
, Hackathon.baseUrl = "https://registration.munihac.de"
, Hackathon.contactUrl = "https://munihac.de/2024.html#contact"
, Hackathon.legalNoticeUrl = Just "https://munihac.de/impressum.html"
, Hackathon.capacity = 120
, Hackathon.confirmation = True

, Hackathon.registerBadgeName = True
, Hackathon.registerAffiliation = True

, Hackathon.registerForm = MH24.additionalInfoForm
, Hackathon.registerView = MH24.additionalInfoView
, Hackathon.ticketView = mempty
, Hackathon.scanView = \Registrant {..} -> case rAdditionalInfo of
Nothing -> mempty
Just MH24.RegisterInfo {..} -> case riTShirt of
Nothing -> "No T-Shirt"
Just MH24.TShirtInfo {..} -> do
"T-Shirt size: "
H.strong $ H.toHtml (show tsiSize)
, Hackathon.csvHeader = MH24.csvHeader

, Hackathon.databaseConfig = Database.defaultConfig
, Hackathon.sendEmailConfig = SendEmail.Config
{ SendEmail.cFrom = "MuniHac Registration Bot <" <> email <> ">"
}
, Hackathon.captcha = captcha
, Hackathon.scannerSecret = scannerSecret
, Hackathon.chatExplanation = H.p "You can join the MuniHac Slack instance here:"
, Hackathon.chatUrl = pure "https://join.slack.com/t/munihac/shared_invite/zt-gaq3veyb-u3j9F0LqN0Q60Zc2MVqvSw"
}
126 changes: 126 additions & 0 deletions lib/Zureg/Hackathon/MuniHac2024/Form.hs
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
{-# LANGUAGE OverloadedStrings #-}
module Zureg.Hackathon.MuniHac2024.Form
( additionalInfoForm
, additionalInfoView
) where

import qualified Data.Text as T
import qualified Text.Blaze.Html5 as H
import qualified Text.Blaze.Html5.Attributes as A
import qualified Text.Digestive as D
import qualified Text.Digestive.Blaze.Html5 as DH
import Zureg.Hackathon.MuniHac2024.Model as MH24

additionalInfoForm :: Monad m => D.Form H.Html m MH24.RegisterInfo
additionalInfoForm = RegisterInfo
<$> ("tshirt" D..: (D.validate tshirtCheck $ (,)
<$> "cut" D..: D.choice
[ (Nothing, "I don't want a T-Shirt")
, (Just Female, "Female")
, (Just Male, "Male")
] (Just (Just Male))
<*> "size" D..: D.choice (
[(Just s, H.toHtml $ show s) | s <- [minBound .. maxBound]] ++
[(Nothing, "I don't want a T-Shirt")])
(Just (Just M))))
<*> "foodPreference" D..: D.choice
[ (Nothing, "None")
, (Just Vegetarian, "I prefer vegetarian food")
, (Just Vegan, "I prefer vegan food")
]
(Just Nothing)
<*> "expertiseLevel" D..: D.choice
[ (Nothing, "I'd rather not say")
, (Just Beginner, "I've just started learning Haskell")
, (Just Advanced, "I know my way around Haskell") ]
(Just Nothing)
<*> "askMeAbout" D..: optionalText
<*> "region" D..: D.choice (
(Nothing, "I'd rather not say") :
[(Just s, H.toHtml $ show s) | s <- [minBound .. maxBound]])
(Just Nothing)
<*> ("project" D..: (Project
<$> "name" D..: optionalText
<*> "website" D..: optionalText
<*> "description" D..: optionalText
<*> ("contributorLevel" D..: (ContributorLevel
<$> "beginner" D..: D.bool Nothing
<*> "intermediate" D..: D.bool Nothing
<*> "advanced" D..: D.bool Nothing))))
<*> "keepMePosted" D..: D.bool (Just False)
where
tshirtCheck (Just c, Just s) = D.Success . Just $ TShirtInfo c s
tshirtCheck (Nothing, Nothing) = D.Success Nothing
tshirtCheck (_, _) = D.Error
"Fill in both T-Shirt cut and size or neither of the two"
optionalText =
(\t -> let t' = T.strip t in if T.null t' then Nothing else Just t') <$>
(D.text Nothing)

additionalInfoView :: D.View H.Html -> H.Html
additionalInfoView view = do
H.h2 "Optional information"

H.p $ H.strong "T-Shirt"
H.p $ "In what size would you like the free T-Shirt?"
DH.label "tshirt.cut" view "Cut"
DH.inputSelect "tshirt.cut" view
H.br
DH.label "tshirt.size" view "Size"
DH.inputSelect "tshirt.size" view
H.br

H.p $ H.strong "Food Preferences"
DH.inputSelect "foodPreference" view
H.br

H.p $ H.strong "Your Level of Expertise"
DH.label "expertiseLevel" view $
"Let us know whether you're a Haskell beginner or expert!"
DH.inputSelect "expertiseLevel" view
H.br

DH.label "askMeAbout" view $ H.strong "Ask me about"
H.p $ do
"Topic(s) that you want to talk about with others. It's a good ice "
"breaker for people who want to chat with you."
DH.inputText "askMeAbout" view
H.br

H.p $ H.strong "Region"
DH.label "region" view $ do
"From what area will you attend MuniHac? This is purely for our "
"statistics."
DH.inputSelect "region" view
H.br

H.h2 "Project (optional)"
H.p $ do
"Do you have a project or an idea to hack on with others? Do you have "
"something you want to teach people?"
H.p $ do
"We greatly appreciate projects. We have had very good experience with "
"announcing the project early on the homepage, so that potential "
"participants can prepare before the Hackathon. Of course, we're also "
"happy to add projects during the Hackathon itself, so if you're not "
"sure yet, don't worry about it."
DH.label "project.name" view "Project name"
DH.inputText "project.name" view
DH.label "project.website" view "Project website"
DH.inputText "project.website" view
DH.label "project.description" view "Project description"
DH.inputText "project.description" view
H.p "Recommended contributor level(s)"
DH.inputCheckbox "project.contributorLevel.beginner" view H.! A.class_ "checkbox"
DH.label "project.contributorLevel.beginner" view $ "Beginner"
H.br
DH.inputCheckbox "project.contributorLevel.intermediate" view H.! A.class_ "checkbox"
DH.label "project.contributorLevel.intermediate" view $ "Intermediate"
H.br
DH.inputCheckbox "project.contributorLevel.advanced" view H.! A.class_ "checkbox"
DH.label "project.contributorLevel.advanced" view $ "Advanced"

H.p $ H.strong "Announcements for future MuniHacs"
H.p "Should we send you an email announcing next year's MuniHac?"
DH.inputCheckbox "keepMePosted" view H.! A.class_ "checkbox"
DH.label "keepMePosted" view "Yes, please!"
157 changes: 157 additions & 0 deletions lib/Zureg/Hackathon/MuniHac2024/Model.hs
Original file line number Diff line number Diff line change
@@ -0,0 +1,157 @@
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE RecordWildCards #-}
{-# LANGUAGE TemplateHaskell #-}
module Zureg.Hackathon.MuniHac2024.Model
( TShirtInfo (..)
, TShirtCut (..)
, TShirtSize (..)
, FoodPreference (..)
, Region (..)
, ExpertiseLevel (..)
, Project (..)
, ContributorLevel (..)
, RegisterInfo (..)
, csvHeader
) where

import qualified Data.Aeson.TH.Extended as A
import Data.Csv as Csv
import qualified Data.HashMap.Strict as HM
import qualified Data.Text as T
import Zureg.Model.Csv ()

data TShirtCut = Female | Male deriving (Bounded, Enum, Eq, Show)

data TShirtSize = S | M | L | XL | XXL deriving (Bounded, Enum, Eq, Show)

data TShirtInfo = TShirtInfo
{ tsiCut :: TShirtCut
, tsiSize :: TShirtSize
} deriving (Eq, Show)

data Region
= Germany
| Europe
| Africa
| AmericaCentral
| AmericaNorth
| AmericaSouth
| Asia
| MiddleEast
| Oceania
deriving (Bounded, Enum, Eq, Show)

data ExpertiseLevel = Beginner | Advanced
deriving (Bounded, Enum, Eq, Show)

data ContributorLevel = ContributorLevel
{ clBeginner :: !Bool
, clIntermediate :: !Bool
, clAdvanced :: !Bool
} deriving (Eq, Show)

data Project = Project
{ pName :: !(Maybe T.Text)
, pWebsite :: !(Maybe T.Text)
, pShortDescription :: !(Maybe T.Text)
, pContributorLevel :: !ContributorLevel
} deriving (Eq, Show)

data FoodPreference = Vegetarian | Vegan
deriving (Eq, Show)

data RegisterInfo = RegisterInfo
{ riTShirt :: !(Maybe TShirtInfo)
, riFoodPreference :: !(Maybe FoodPreference)
, riExpertiseLevel :: !(Maybe ExpertiseLevel)
, riAskMeAbout :: !(Maybe T.Text)
, riRegion :: !(Maybe Region)
, riProject :: !Project
, riKeepMePosted :: !Bool
} deriving (Eq, Show)

$(A.deriveJSON A.options ''TShirtSize)
$(A.deriveJSON A.options ''TShirtCut)
$(A.deriveJSON A.options ''TShirtInfo)
$(A.deriveJSON A.options ''Region)
$(A.deriveJSON A.options ''ExpertiseLevel)
$(A.deriveJSON A.options ''ContributorLevel)
$(A.deriveJSON A.options ''Project)
$(A.deriveJSON A.options ''FoodPreference)
$(A.deriveJSON A.options ''RegisterInfo)

instance Csv.ToField TShirtCut where
toField = toField . show

instance Csv.ToField TShirtSize where
toField = toField . show

instance Csv.ToNamedRecord (Maybe TShirtInfo) where
toNamedRecord mbTi =
namedRecord [ "T-Shirt Cut" .= (tsiCut <$> mbTi)
, "T-Shirt Size" .= (tsiSize <$> mbTi)
]

instance Csv.ToField FoodPreference where
toField = toField . show

instance Csv.ToNamedRecord Project where
toNamedRecord Project {..}
= HM.unions [ namedRecord [ "Project Name" .= pName
, "Project Website" .= pWebsite
, "Project Short Description" .= pShortDescription
]
, toNamedRecord pContributorLevel
]

instance Csv.ToNamedRecord ContributorLevel where
toNamedRecord ContributorLevel {..}
= namedRecord [ "CL Beginner" .= clBeginner
, "CL Intermediate" .= clIntermediate
, "CL Advanced" .= clAdvanced
]

instance Csv.ToField ExpertiseLevel where
toField = toField . show

instance Csv.ToField Region where
toField = toField . show

instance Csv.ToNamedRecord RegisterInfo where
toNamedRecord RegisterInfo {..}
= HM.unions
[ namedRecord
[ "AskMeAbout" .= riAskMeAbout
, "Expertise Level" .= riExpertiseLevel
, "Region" .= riRegion
, "Food Preference" .= riFoodPreference
]
, toNamedRecord riProject
, toNamedRecord riTShirt
]

csvHeader :: Csv.Header
csvHeader = Csv.header
[ "UUID"
, "State"
, "Scanned"
, "Name"
, "Name on Badge"
, "Email"
, "Affiliation"
, "Expertise Level"
, "AskMeAbout"
, "Region"
, "Project Name"
, "Project Website"
, "Project Short Description"
, "CL Beginner"
, "CL Intermediate"
, "CL Advanced"
, "Registered At"
, "T-Shirt Cut"
, "T-Shirt Size"
, "Food Preference"
]
Loading

0 comments on commit 95ccda2

Please sign in to comment.