-
Notifications
You must be signed in to change notification settings - Fork 4
/
authenticated-pizzas.elm
158 lines (142 loc) · 5.89 KB
/
authenticated-pizzas.elm
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
-- The user database.
userdata: List (String, (String, Int))
userdata = [
("7989", ("Laurent", 1)),
("10000", ("Ravi", 3))
]
-- List of potential admins
potentialadmins =
["102014571179481340426"]
|> List.map Just
-- Ensures that only owners and admins can modify their own pizza
userdata =
let canModify (sub, x) =
if sub == usersub || admin then
Nothing
else
Just "cannot modify someone else's data if already answered"
in
{-
-- TODO: Implement these checks
List.update.errOnInsert canModify <|
List.update.errOnUpdate canModify <|
List.update.errOnDelete canModify <|
-}
userdata
-- Helpers
adminModifiable hint =
Update.freezeWhen (not admin) (\_ -> """Cannot modify @hint, only admins can""")
potentialadminModifiable hint =
Update.freezeWhen (not potentialadmin) (\_ -> """Cannot modify @hint, only potential admins can""")
-- If the current user has the right to act as admin
potentialadmin =
listDict.get "sub" user |>
flip List.contains potentialadmins
-- If the current user activated the admin mode
admin =
potentialadmin && (listDict.get "admin" vars == Just "true")
-- Default value of type a for 'Maybe a' that can only be modified by admins
mbReplaceAdmin hint =
if admin then
Maybe.withDefaultReplace
else
\default x ->
Maybe.withDefaultReplace (Update.lens { apply = identity, update = always <| Err """Cannot change the @hint if you are not an admin"""} default) x
-- The user subject number. Admins can simulate users by adding &sub=... to the URL
usersub =
let default _ = listDict.get "sub" user |> mbReplaceAdmin "default sub" "0" in
if potentialadmin then
listDict.get "sub" vars
|> Maybe.withDefault (default ())
else
default ()
-- The username. We'll take it from the database if available, else from the credentials
username =
listDict.get usersub userdata
|> Maybe.map Tuple.first
|> Maybe.withDefaultLazy (\_ ->
let default _ = listDict.get "given_name" user |> mbReplaceAdmin "default name" "Anonymous" in
if potentialadmin then
listDict.get "given_name" vars
|> Maybe.withDefault (default ())
else
default ()
)
-- The list of pizzas (only modifiable by admin)
options = adminModifiable "list of pissas" ["Margharita", "Four Cheese", "Pepper", "Napoli"]
-- The interface for potential admins and admins
admininterface =
if admin then
<span>- admin mode activated<br></span>
else if potentialadmin then
<button onclick="""location.href = location.pathname + '?admin=true'""">Activate admin mode</button>
else []
-- Content displayed to the user
content =
if usersub == "0" || (potentialadmin && listDict.get "admin" vars == Just "false") then
potentialadminModifiable "text when not signed in" <span>Please sign in or wait a bit for the auto-sign</span>
else
let
selection =
Html.select [] (adminModifiable "text when no pizza selected" "Choose one..." :: options) (
listDict.get usersub userdata
|> mbReplaceAdmin "default pizza choice" (username, 0)
|> Tuple.second)
finalChoices =
userdata
|> List.map (\(sub, (name, id)) ->
let chosenPizza =
List.findByAReturnB Tuple.first Tuple.second (id - freeze 1) (List.zipWithIndex options)
|> Maybe.withDefault "a pizza that does not exist"
in
adminModifiable "template for choosing" (\name chosenPizza ->
<span>@name would like a @(chosenPizza).<br></span>) name chosenPizza
)
in
adminModifiable "content template" (\username selection finalChoices ->
<span><br>Hi <span sub=@usersub>@username</span>!<br>
Select the pizza you want
@selection<br><br>
Final choices made by everyone:<br>@finalChoices
</span>) username selection finalChoices
main = adminModifiable "general html page" (\googleClientId googlesigninbutton admininterface content ->
<html>
<head>
<meta name="google-signin-client_id" content=@googleClientId>
</head>
<body>
@googlesigninbutton@(admininterface)
@content
<hr>
<h1>Fully authenticated webpage</h1>
This webpage only authorizes you to modify the parts you <i>own</i>.<br>
<br>
Let's how to get started to play around this file:
<ul>
<li>Sign in using your Google account, accept the permissions.</li>
<li>Disable the "Ask questions" button by clicking on it, if it's on.</li>
<li>Select a pizza (e.g. Four Cheese). Wait for the page to save your changes.<br>
The list "final choices" should now include your choice</li>
<li>Go to the source file `authenticated-pizzas.elm`. In the variable <code>userdata</code>, you should see a string of digits close to your name, it's your <code>sub</code>.<br>Add your <code>sub</code> to the list of potential admins and reload the page</li>
<li>Now you should see the button <button>Activate admin mode</button>. Click on it. It will add <code>?admin=true</code> to the URL.</li>
<li>As an admin, you can modify the template. Modify "choose" to "would like a" for example.</li>
<li>As an admin, you can now simulate another's existing account
<ul>
<li>Append <code>&sub=7989</code> to the URL.</li>
<li>The website displays what Laurent would see if he was logged in.</li>
<li>Remove <code>admin=true&</code> from the URL.</li>
<li>Change Laurent's name, and pizza. This modification is stored into the database</li>
<li>Try to modify the template by modifying "would like a" to "choose". Reload the page after it fails (because Laurent is not an admin)</li>
</ul>
</li>
<li>
You can also simulate a not yet existing account
<ul>
<li>Append <code>?sub=12345&given_name=faked</code></li>
<li>Choose a pizza. The name and pizza are stored with respect to the sub</li>
</ul>
</li>
<li>To finish, add again <code>admin=true&</code> and add/rename pizzas.
</ul>
</body>
</html>) googleClientId googlesigninbutton admininterface content