Repository navigation
Expand file tree
/
Copy pathclasstrip.go
More file actions
181 lines (157 loc) · 5.37 KB
/
Copy pathclasstrip.go
File metadata and controls
181 lines (157 loc) · 5.37 KB
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
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
package classtrip
import (
"appengine"
"appengine/user"
"appengine/datastore"
"github.com/mjibson/appstats"
"net/http"
"html/template"
"strings"
"time"
"strconv"
)
type User struct {
Email string
Name string
CreateTime time.Time
}
type Context struct {
u User
c appengine.Context
cu *user.User
logoutURL string
}
func init() {
http.Handle("/", appstats.NewHandler(Secure(Main)))
http.Handle("/main", appstats.NewHandler(Secure(Main)))
http.Handle("/settings", appstats.NewHandler(Secure(Settings)))
http.Handle("/admin", appstats.NewHandler(Secure(AdminMain)))
http.Handle("/calendar", appstats.NewHandler(Secure(Calendar)))
http.Handle("/calendar/", appstats.NewHandler(Secure(Calendar)))
}
//Secure wraps a Handler functions and includes functionality to make sure
//the user is from university of maryland and also pulls their User structure
type StatsHandler func (appengine.Context, http.ResponseWriter, *http.Request)
type CustomHandler func (*Context, http.ResponseWriter, *http.Request)
func Secure(handler CustomHandler) StatsHandler {
return func(c appengine.Context, w http.ResponseWriter, r *http.Request) {
//store a context which allows us to avoid repeated calls to user.Current()
//user.LogoutURL() etc
ctx := new(Context)
ctx.c = c
ctx.cu = user.Current(c)
ctx.logoutURL, _ = user.LogoutURL(c, "/main")
//make sure the user is a university of maryland student before continuing
if !strings.HasSuffix(ctx.cu.Email, "@umaryland.edu") {
//return status unauthorized
w.WriteHeader(http.StatusUnauthorized)
//the access denied template gives the user the option to logout and try again
RenderPage(ctx, w, "accesserror", ctx.cu)
return
}
//the user is from UMB, so now try to pull their user record
//the user record is created if it does not exist
//the root key is the key under which all User{}'s live
userRK := userRootKey(c)
//create the key based on the username
userKey := datastore.NewKey(ctx.c, "User", ctx.cu.Email, 0, userRK)
//check if there is already an entry for the user, if not, create one.
if err := datastore.Get(ctx.c, userKey, &ctx.u); err != nil {
ctx.u.Email = ctx.cu.Email
ctx.u.CreateTime = time.Now()
ctx.u.Name = ""
if _,err := datastore.Put(c, userKey, &ctx.u); err != nil {
c.Errorf("Unable to put user key: %s", err.Error())
}
}
handler(ctx, w, r)
}
}
//userKey returns the root User key under which all User{} structures lay
func userRootKey(c appengine.Context) *datastore.Key {
return datastore.NewKey(c, "User", "default_users", 0, nil)
}
//userKey returns the key for a given email
func userKey(c appengine.Context, email string) *datastore.Key {
c.Debugf("Creating key for %d", email)
return datastore.NewKey(c, "User", email, 0, userRootKey(c))
}
//success returns the HTML "text-success" wrapped message
func success(message string) template.HTML {
return template.HTML(`<p class="bg-success">` + message + `</p>`)
}
//failure returns the HTML "text-danger" wrapped message
func failure(message string) template.HTML {
return template.HTML(`<p class="bg-danger">` + message + `</p>`)
}
func Main(c *Context, w http.ResponseWriter, r *http.Request) {
RenderPage(c, w, "index", nil)
}
func Settings(c *Context, w http.ResponseWriter, r *http.Request) {
//helper function
render := func (str template.HTML) {
RenderPage(c, w, "settings", str)
}
if (r.Method == "GET") {
render("")
} else {
r.ParseForm();
param,ok := r.Form["fullName"]
if !ok {
RenderPage(c, w, "settings", failure("Error updating settings: fullname not submitted"))
return
}
name := param[0]
//check to make sure the name is valid (at least two words)
if !strings.Contains(name, " ") {
render(failure("Make sure you entered your full name (first and last)"))
return
}
//get the user's datastore key
k := userKey(c.c, c.u.Email)
c.u.Name = name
datastore.Put(c.c, k, &c.u)
RenderPage(c, w, "settings", success("Settings updated"))
}
}
func Calendar(c *Context, w http.ResponseWriter, r *http.Request) {
var (
cal string
url string = r.URL.Path
t time.Time = time.Now()
month time.Month
year int
)
//parse the URL to extract the month and the year
//check to see if a month and year was provided and is in the proper format
//URL should be in format of calendar/month/year
//where month is a 1-2 digit integer and year is a four digit integer
idx := strings.LastIndex(url, "calendar/")
//default is the current month and year in case the the request is improperly formatted
month = t.Month()
year = t.Year()
if idx != -1 {
//now we have to determine if the URL is properly formatted
//ex: calendar/01/2014 for Jan 2014
//split them by the '/'
strs := strings.Split(url[idx+9:], "/")
//check to make sure we have two items (month and a year) and they are the proper length
if len(strs) == 2 && len(strs[1]) == 4 && (len(strs[0]) == 1 || len(strs[0]) == 2) {
//format is valid
if yearInt,err := strconv.Atoi(strs[1]); err == nil && yearInt >= year {
if monthInt,err := strconv.Atoi(strs[0]); err == nil {
//cant go back in time
if yearInt > year || monthInt > int(month) {
month = time.Month(monthInt)
year = yearInt
}
}
}
}
}
cal = GenCalendar(month, year)
RenderPage(c, w, "calendar", template.HTML(cal))
}
func AdminMain(c *Context, w http.ResponseWriter, r *http.Request) {
w.Write([]byte("Hello world"))
}