10 "github.com/gorilla/mux"
14 ctx = context.Background()
15 cookieAge = "31536000"
18 func getContextWithSession(ctx context.Context, req *http.Request) context.Context {
19 sessionID, err := req.Cookie("session_id")
23 return context.WithValue(ctx, "session_id", sessionID.Value)
26 func NewHandler(s Service, staticDir string) http.Handler {
29 r.PathPrefix("/static").Handler(http.StripPrefix("/static",
30 http.FileServer(http.Dir(path.Join(".", staticDir)))))
32 r.HandleFunc("/", func(w http.ResponseWriter, req *http.Request) {
35 sessionID, _ := req.Cookie("session_id")
36 if sessionID != nil && len(sessionID.Value) > 0 {
37 location = "/timeline"
40 w.Header().Add("Location", location)
41 w.WriteHeader(http.StatusFound)
42 }).Methods(http.MethodGet)
44 r.HandleFunc("/signin", func(w http.ResponseWriter, req *http.Request) {
45 err := s.ServeSigninPage(ctx, w)
47 s.ServeErrorPage(ctx, w, err)
50 }).Methods(http.MethodGet)
52 r.HandleFunc("/signin", func(w http.ResponseWriter, req *http.Request) {
53 instance := req.FormValue("instance")
54 url, sessionId, err := s.GetAuthUrl(ctx, instance)
56 s.ServeErrorPage(ctx, w, err)
60 w.Header().Add("Set-Cookie", fmt.Sprintf("session_id=%s;max-age=%s", sessionId, cookieAge))
61 w.Header().Add("Location", url)
62 w.WriteHeader(http.StatusFound)
63 }).Methods(http.MethodPost)
65 r.HandleFunc("/oauth_callback", func(w http.ResponseWriter, req *http.Request) {
66 ctx := getContextWithSession(context.Background(), req)
67 token := req.URL.Query().Get("code")
68 _, err := s.GetUserToken(ctx, "", nil, token)
70 s.ServeErrorPage(ctx, w, err)
74 w.Header().Add("Location", "/timeline")
75 w.WriteHeader(http.StatusFound)
76 }).Methods(http.MethodGet)
78 r.HandleFunc("/timeline", func(w http.ResponseWriter, req *http.Request) {
79 ctx := getContextWithSession(context.Background(), req)
81 maxID := req.URL.Query().Get("max_id")
82 sinceID := req.URL.Query().Get("since_id")
83 minID := req.URL.Query().Get("min_id")
85 err := s.ServeTimelinePage(ctx, w, nil, maxID, sinceID, minID)
87 s.ServeErrorPage(ctx, w, err)
90 }).Methods(http.MethodGet)
92 r.HandleFunc("/thread/{id}", func(w http.ResponseWriter, req *http.Request) {
93 ctx := getContextWithSession(context.Background(), req)
94 id, _ := mux.Vars(req)["id"]
95 reply := req.URL.Query().Get("reply")
96 err := s.ServeThreadPage(ctx, w, nil, id, len(reply) > 1)
98 s.ServeErrorPage(ctx, w, err)
101 }).Methods(http.MethodGet)
103 r.HandleFunc("/like/{id}", func(w http.ResponseWriter, req *http.Request) {
104 ctx := getContextWithSession(context.Background(), req)
105 id, _ := mux.Vars(req)["id"]
106 err := s.Like(ctx, w, nil, id)
108 s.ServeErrorPage(ctx, w, err)
112 w.Header().Add("Location", req.Header.Get("Referer")+"#status-"+id)
113 w.WriteHeader(http.StatusFound)
114 }).Methods(http.MethodGet)
116 r.HandleFunc("/unlike/{id}", func(w http.ResponseWriter, req *http.Request) {
117 ctx := getContextWithSession(context.Background(), req)
118 id, _ := mux.Vars(req)["id"]
119 err := s.UnLike(ctx, w, nil, id)
121 s.ServeErrorPage(ctx, w, err)
125 w.Header().Add("Location", req.Header.Get("Referer")+"#status-"+id)
126 w.WriteHeader(http.StatusFound)
127 }).Methods(http.MethodGet)
129 r.HandleFunc("/retweet/{id}", func(w http.ResponseWriter, req *http.Request) {
130 ctx := getContextWithSession(context.Background(), req)
131 id, _ := mux.Vars(req)["id"]
132 err := s.Retweet(ctx, w, nil, id)
134 s.ServeErrorPage(ctx, w, err)
138 w.Header().Add("Location", req.Header.Get("Referer")+"#status-"+id)
139 w.WriteHeader(http.StatusFound)
140 }).Methods(http.MethodGet)
142 r.HandleFunc("/unretweet/{id}", func(w http.ResponseWriter, req *http.Request) {
143 ctx := getContextWithSession(context.Background(), req)
144 id, _ := mux.Vars(req)["id"]
145 err := s.UnRetweet(ctx, w, nil, id)
147 s.ServeErrorPage(ctx, w, err)
151 w.Header().Add("Location", req.Header.Get("Referer")+"#status-"+id)
152 w.WriteHeader(http.StatusFound)
153 }).Methods(http.MethodGet)
155 r.HandleFunc("/post", func(w http.ResponseWriter, req *http.Request) {
156 ctx := getContextWithSession(context.Background(), req)
158 err := req.ParseMultipartForm(4 << 20)
160 s.ServeErrorPage(ctx, w, err)
164 content := getMultipartFormValue(req.MultipartForm, "content")
165 replyToID := getMultipartFormValue(req.MultipartForm, "reply_to_id")
166 files := req.MultipartForm.File["attachments"]
168 id, err := s.PostTweet(ctx, w, nil, content, replyToID, files)
170 s.ServeErrorPage(ctx, w, err)
174 location := "/timeline" + "#status-" + id
175 if len(replyToID) > 0 {
176 location = "/thread/" + replyToID + "#status-" + id
178 w.Header().Add("Location", location)
179 w.WriteHeader(http.StatusFound)
180 }).Methods(http.MethodPost)
182 r.HandleFunc("/notifications", func(w http.ResponseWriter, req *http.Request) {
183 ctx := getContextWithSession(context.Background(), req)
185 maxID := req.URL.Query().Get("max_id")
186 minID := req.URL.Query().Get("min_id")
188 err := s.ServeNotificationPage(ctx, w, nil, maxID, minID)
190 s.ServeErrorPage(ctx, w, err)
193 }).Methods(http.MethodGet)
195 r.HandleFunc("/signout", func(w http.ResponseWriter, req *http.Request) {
196 // TODO remove session from database
197 w.Header().Add("Set-Cookie", fmt.Sprintf("session_id=;max-age=0"))
198 w.Header().Add("Location", "/")
199 w.WriteHeader(http.StatusFound)
200 }).Methods(http.MethodGet)
205 func getMultipartFormValue(mf *multipart.Form, key string) (val string) {
206 vals, ok := mf.Value[key]