For the past 4 years I’ve helped to host a Secret Santa gift exchange for an online film club I participate in, and every year I find myself refining the process of drawing names, sharing information, and giving folks reminders for deadlines, which has increasingly involved both the Wolfram Language and Wolfram Cloud.
I was reminded of Bernat Espigulé's post a number of years back using FormFunction, and decided to take a swing at making a multi-stage form not only to randomize names, but also to collect information from participants and handle distributing the information as well.
The film club I participate in has members in the US, UK, and Canada and the number of participants varies year to year, so the first step in setting up the drawing was to actually gather everyone’s information. I could reach out to everyone individually and write down all the information, but since everyone who participates also congregates in the same Discord server I figured I could just post a form there and let people fill in the information themselves.
I was reminded of Bernat Espigulé's post a number of years back using FormFunction, and decided to take a swing at making a multi-stage form not only to randomize names, but also to collect information from participants and handle distributing the information as well.
The film club I participate in has members in the US, UK, and Canada and the number of participants varies year to year, so the first step in setting up the drawing was to actually gather everyone’s information. I could reach out to everyone individually and write down all the information, but since everyone who participates also congregates in the same Discord server I figured I could just post a form there and let people fill in the information themselves.
bin=CreateDatabin[];With[{o=bin},CloudDeploy[FormFunction[{"Name"->"String","Country"->"String","Pronouns"->"String","Wishlist"-><|"Help"->"Link or \"Blind buy\""|>,"Prefered Format"-><|"Help"->"bluray, DVD, 4K, etc"|>,"Shipping Address"-><|"Help"->"mailing address, PO Box, or \"None\" if digital only"|>},"Information added; Thanks "<>#["Name"]<>"!"&],Permissions->"Public"]]
That left me with a public cloud object I could simply post in the chat and let folks fill things out as they wished, after which I could simply poll the Databin for info from when it was time to draw.
After giving people a few days to put their info in, I closed submissions and checked my Databin, and low-and-behold we had 11 participants!
names=Values[bin]["Name"]
{Nick,Johnny,Kathy,Mauricio,Becky,Matt,Sam,James,Tom,Ross,Dan}
Next I needed a system to actually draw the names...there are a number of ways to accomplish this, but I went with a basic bogo-shuffle:
shuffle[]:=Transpose[{names,RandomSample@names}]makePairs[]:=Module[{i=0,pair=shuffle[]},While[!AllTrue[pair,UnsameQ@@#&],Print[i++];pair=shuffle[]];$pair=pair;]
(The Print is handy here just to see how many shuffles were needed within a given evaluation to avoid ‘self-drawing’)
With that all sorted it was time to make use the draw to generate information pages for each participant! To do this I threw together a handful of convenience functions to make collecting the data into pages a bit easier, and then finally define a ‘pick submission’ form:
With that all sorted it was time to make use the draw to generate information pages for each participant! To do this I threw together a handful of convenience functions to make collecting the data into pages a bit easier, and then finally define a ‘pick submission’ form:
longToShort[name_]:=First[StringSplit[name]]makeNamedCO[name_,suffix_]:=CloudObject[longToShort[name]<>suffix,Permissions->"Public"]fromBin[name_,prop_]:=Replace[Values[bin[FirstPosition[names,name]]][prop],{entry_String}:>entry]linkIfCan[link_]:=If[URLParse[link,"Domain"]===None,link,Hyperlink[link]]wishlistLink[person_]:=linkIfCan[fromBin[person,"Wishlist"]]pickHash[name_]:=Hash[name,"SHA","HexString"]makeForm[{person_,personYouDrew_String}]:=With[{formobj=makeNamedCO[person,"DRAW"],pickobj=makeNamedCO[pickHash@personYouDrew,"PICK"]},CloudDeploy[FormFunction[{"Selection"-><|"Help"->"if possible give an Amazon link, otherwise include the film name and format."|>},Row[{CloudPut[#,pickobj];"You picked: ",linkIfCan[#["Selection"]]}]&,"HTML",AppearanceRules-><|"Title"->"In/Frame/Out Secret Santa 2023!","Description"->Column[{Style["Hey "<>longToShort[person]<>", you drew "<>personYouDrew<>" for this year's In/Frame/Out Secret Santa exchange!",Bold],"\n","They are based out of "<>fromBin[personYouDrew,"Country"]<>" and are interested in the following formats: "<>fromBin[personYouDrew,"Prefered Format"]<>".",Row[{"Their wishlist information is: ",wishlistLink[personYouDrew]}],"\n","When you have made your selection for them please enter it in the field below and submit it(you can re-submit the form to change the pick if you make a mistake or change your mind). If you have any questions or trouble just ping us in the 2023 secret santa channel."}]|>],formobj,Permissions->"Public"]]
And then it was just a matter of generating the forms for each participant, giving person their own individualized cloud object with the info they need to make and submit their selection.
That takes care of gathering the information, doing the draw, and handing out the picks...but there’s one extra step still needed for our remote movie-buying exchange...actually getting the picks sent out! Since we have members in 3 different countries that actually involved a bit of extra work, and the way we’ve handled it is to have two designated purchasers on each side of the pond, and then two secondary purchasers that deal with buying and shipping for the primary purchasers(that way no one is responsible for buying a gift for themselves, even if someone else picked it out for them).
To handle gathering the data for individual selections together, we just need to make another small utility function:
purchasingInfo[name_]:=With[{obj=makeNamedCO[pickHash@name,"PICK"]},Module[{pick=CloudGet[obj]},If[pick==$Failed,pick=<|"Selection"->"TDB"|>];Join[Values[bin[FirstPosition[names,name]]],pick]]]
purchasingInfo["Ross"]
<|Prefered Format->{digital},Shipping Address->{123 Forest Road},Wishlist->{Blind buy},Pronouns->{He/him},Name->{Ross},Selection->https://www.amazon.co.uk/Searching-Sugar-Man-Sixto-Rodriguez/dp/B00ESQA0X4|>
And then we can take that information and format it nicely using Cells and CellGroups so that a collection of picks can be put together into a single document:
formatInfo[name_]:=With[{info=purchasingInfo[name]},CellGroupData[{Cell[name,"Section"],Cell[CellGroupData[{Cell["Shipping info","Subsection"],Cell[name,"Text"],Cell[First@info["Shipping Address"],"Text"],Cell[country[name],"Text"]}]],Cell[CellGroupData[{Cell["Selection","Subsection"],Cell[info["Selection"],"Text"],Cell["Prefered format: "<>First[info["Prefered Format"]],"Text"]}]]}]]
Which when deployed gives a nice looking info page for the purchaser, complete with shipping address and selection. Then each of the primary purchasers gets a single landing page that has all the pick information in one convenient location for them to use when getting orders out.
nb=CloudDeploy[Notebook[formatInfo/@{"Ross","Beth","Matt"}]]
The nice thing about this setup is that neither the participants nor the purchasers know who is buying what, since all of the selection information is done through forms instead of direct communication.
I hope this was as interesting of an exercise to read about as it was to put together!
CITE THIS NOTEBOOK
CITE THIS NOTEBOOK
Double-blind Secret Santa organized by multi-stage online form
by Nick Lariviere
Wolfram Community, STAFF PICKS, December 11, 2023
https://community.wolfram.com/groups/-/m/t/3081689
by Nick Lariviere
Wolfram Community, STAFF PICKS, December 11, 2023
https://community.wolfram.com/groups/-/m/t/3081689