forked from zfoh/zureg
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Create the resources for Munihac2024
(copied from munihac2022 with minimal adjustments)
- Loading branch information
Alberto Diaz Dorado
committed
May 4, 2024
1 parent
148401e
commit 95ccda2
Showing
10 changed files
with
568 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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" | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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!" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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" | ||
] |
Oops, something went wrong.