func deleteAccountHandler(w http.ResponseWriter, r *http.Request) { id := "" session, err := sessions.Session(r, "", "datastore") c1 := appengine.NewContext(r) c1.Debugf("deleteAccount: id=%v, session=%v, err=%v\n", session["userID"], session, err) if err == nil { if session["userID"] != nil { id = session["userID"].(string) } } if id != "" { user := loadUser(r, id) if user.Id != "" { c := appengine.NewContext(r) key := datastore.NewKey(c, "User", user.Id, 0, nil) datastore.Delete(c, key) session["userID"] = "" sessions.Save(r, w) memUserDelete(c, user.Id) memcache.Delete(c, "user"+user.Id) http.SetCookie(w, &http.Cookie{Name: "userId", Value: "", Domain: appConfig.AppDomain, Path: "/", MaxAge: -1}) } } http.Redirect(w, r, "/", http.StatusFound) }
func signInTwitterHandler(w http.ResponseWriter, r *http.Request) { c := appengine.NewContext(r) id := r.FormValue("id") if id == "" { serveError(c, w, errors.New("Missing ID parameter")) return } conf := &tweetlib.Config{ ConsumerKey: appConfig.TwitterConsumerKey, ConsumerSecret: appConfig.TwitterConsumerSecret, Callback: "http://" + appConfig.AppHost + "/twitter?action=temp&id=" + id} tok := &tweetlib.Token{} tr := &tweetlib.Transport{Config: conf, Token: tok, Transport: &urlfetch.Transport{Context: c}} tt, err := tr.TempToken() if err != nil { c := appengine.NewContext(r) serveError(c, w, err) c.Errorf("%v", err) return } item := &memcache.Item{ Key: tt.Token, Value: []byte(tt.Secret), } // Add the item to the memcache, if the key does not already exist memcache.Add(c, item) http.Redirect(w, r, tt.AuthURL(), http.StatusFound) }
func secureWebAccess(w http.ResponseWriter, r *http.Request) *User { session, _ := sessionsStore.Get(r, "logindata") value := session.Values["id"] c := appengine.NewContext(r) c.Infof("The Value is: %v", value) var u User if value == nil { c.Infof("Redirecting to login") http.Redirect(w, r, "/login.do", http.StatusTemporaryRedirect) } else { c := appengine.NewContext(r) q := datastore.NewQuery("User"). Filter("Username = "******"User",,0,nil) if count, _ := q.Count(c); count == 0 { //what ever you have in the session is not in the datastore, these happends when you delete a user directly from the datastore, and the sesion is still active http.Redirect(w, r, "/login.do", http.StatusTemporaryRedirect) return nil } t := q.Run(c) t.Next(&u) } return &u }
func TestEditVisitPageMissingPathInfo(t *testing.T) { inst, err := aetest.NewInstance(&aetest.Options{StronglyConsistentDatastore: true}) if err != nil { t.Fatalf("Failed to create instance: %v", err) } defer inst.Close() url := "/editvisit/" req, err := inst.NewRequest("GET", url, nil) if err != nil { t.Fatalf("Failed to create req: %v", err) } aetest.Login(&user.User{Email: "*****@*****.**"}, req) w := httptest.NewRecorder() c := appengine.NewContext(req) addTestUser(c, "*****@*****.**", true) editvisitpage(c, w, req) code := w.Code if code != http.StatusBadRequest { t.Errorf("got code %v, want %v", code, http.StatusBadRequest) } body := w.Body.Bytes() expected := []byte("id is missing in path for update request /editvisit/") if !bytes.Contains(body, expected) { t.Errorf("got body %v, did not contain %v", string(body), string(expected)) } url += "12345" req, err = inst.NewRequest("GET", url, nil) if err != nil { t.Fatalf("Failed to create req: %v", err) } aetest.Login(&user.User{Email: "*****@*****.**"}, req) w = httptest.NewRecorder() c = appengine.NewContext(req) editvisitpage(c, w, req) code = w.Code if code != http.StatusBadRequest { t.Errorf("got code %v, want %v", code, http.StatusBadRequest) } body = w.Body.Bytes() expected = []byte("id is missing in path for update request /editvisit/") if !bytes.Contains(body, expected) { t.Errorf("got body %v, did not contain %v", string(body), string(expected)) } }
func data(w http.ResponseWriter, r *http.Request) { c := appengine.NewContext(r) confData, err := Configs(appengine.NewContext(r)) handlePanic(w, c, err) jsonData, err := json.Marshal(confData) handlePanic(w, c, err) fmt.Fprintf(w, "%s", jsonData) }
func sendLinks(w http.ResponseWriter, req *http.Request) { m, _ := url.ParseQuery(req.URL.RawQuery) col, _ := strconv.Atoi(m["col"][0]) count, _ := strconv.Atoi(m["count"][0]) str := controllers.GetImages(col, count, appengine.NewContext(req)) json, _ := json.Marshal(str) c := appengine.NewContext(req) c.Infof("%d", len(str)) io.WriteString(w, string(json)) }
func (p *Profile) get(w http.ResponseWriter, r *http.Request) { // Create a key with a key for Profile with Key = Id p.Id = user.Current(appengine.NewContext(r)).ID c := appengine.NewContext(r) err := datastore.Get(c, datastore.NewKey(c, "Profile", p.Id, 0, nil), p) if err != nil { // http.Error(w, err.Error(), http.StatusInternalServerError) p.put(w, r) } }
func twitterVerify(w http.ResponseWriter, r *http.Request) { token := r.FormValue("oauth_token") id := r.FormValue("id") c := appengine.NewContext(r) if id == "" { serveError(c, w, errors.New("Missing ID parameter")) return } item, _ := memcache.Get(c, token) secret := string(item.Value) verifier := r.FormValue("oauth_verifier") conf := &tweetlib.Config{ ConsumerKey: appConfig.TwitterConsumerKey, ConsumerSecret: appConfig.TwitterConsumerSecret} tok := &tweetlib.Token{} tr := &tweetlib.Transport{Config: conf, Token: tok, Transport: &urlfetch.Transport{Context: c}} tt := &tweetlib.TempToken{Token: token, Secret: secret} tok, err := tr.AccessToken(tt, verifier) if err != nil { c := appengine.NewContext(r) serveError(c, w, err) c.Errorf("%v", err) return } tr.Token = tok tl, _ := tweetlib.New(tr.Client()) u, err := tl.Account.VerifyCredentials(nil) fmt.Printf("err=%v\n", err) user := loadUser(r, id) user.TwitterOAuthToken = tok.OAuthToken user.TwitterOAuthSecret = tok.OAuthSecret user.TwitterId = u.IdStr user.TwitterScreenName = u.ScreenName if err := saveUser(r, &user); err != nil { serveError(c, w, err) return } http.Redirect(w, r, "/", http.StatusFound) }
func primeCache(w http.ResponseWriter, r *http.Request) { c := appengine.NewContext(r) err := model.ForceUpdateStatuses(c) if err != nil { http.Error(w, "An error occured while updating the cache", http.StatusInternalServerError) } }
func view(w http.ResponseWriter, r *http.Request) { id, _ := strconv.Atoi(r.FormValue("id")) c := appengine.NewContext(r) var view detail_view // グループ情報を取得 if group, err := model.GetGroup(c, id); err != nil { http.Error(w, err.String(), http.StatusInternalServerError) return } else { view.Group = group } // メンバー情報を取得 if memberlist, err := model.MemberList(c, id); err != nil { http.Error(w, err.String(), http.StatusInternalServerError) return } else { view.Member = memberlist } // 詳細画面を表示 if err := detailTemplate.Execute(w, view); err != nil { http.Error(w, err.String(), http.StatusInternalServerError) } }
func handleInboxItem(w http.ResponseWriter, r *http.Request) { c := appengine.NewContext(r) userid, _, err := getSession(c, r) if err != nil { sendError(w, r, "No session cookie") return } s := newStore(c) perma_blobref := r.FormValue("perma") item, err := s.GetInboxItem(userid, perma_blobref) if err != nil { http.Error(w, "Could not get inbox item", http.StatusInternalServerError) c.Errorf("handleInboxItem: %v", err) return } entry := make(map[string]interface{}) entry["perma"] = perma_blobref entry["seq"] = item.LastSeq err = fillInboxItem(s, perma_blobref, item.LastSeq, entry) if err != nil { fmt.Fprintf(w, `{"ok":false, "error":%v}`, err.String()) return } info, _ := json.Marshal(entry) fmt.Fprintf(w, `{"ok":true, "item":%v}`, string(info)) }
func handleListInbox(w http.ResponseWriter, r *http.Request) { c := appengine.NewContext(r) userid, _, err := getSession(c, r) if err != nil { sendError(w, r, "No session cookie") return } s := newStore(c) inbox, err := s.ListInbox(userid, false) if err != nil { sendError(w, r, err.String()) return } // Read the updates for all items in the inbox for _, entry := range inbox { fillInboxItem(s, entry["perma"].(string), entry["seq"].(int64), entry) } j := map[string]interface{}{"ok": true, "items": inbox} msg, err := json.Marshal(j) if err != nil { panic("Cannot serialize") } fmt.Fprint(w, string(msg)) }
func ArticleDeleteHandler(w http.ResponseWriter, r *http.Request) { c := appengine.NewContext(r) user := core.AdminUser(c, w) if user == nil { return } vars := mux.Vars(r) id, err := strconv.ParseInt(vars["id"], 10, 64) if err != nil { core.HandleError(c, w, err) return } article, err := GetArticleById(c, id, false) if err != nil { core.HandleNotFound(c, w) return } err = DeleteArticle(c, article) if err != nil { core.HandleError(c, w, err) return } http.Redirect(w, r, "/", 302) }
func ArticlePermaLinkHandler(w http.ResponseWriter, r *http.Request) { c := appengine.NewContext(r) vars := mux.Vars(r) id, err := strconv.ParseInt(vars["id"], 10, 64) if err != nil { core.HandleError(c, w, err) return } article, err := GetArticleById(c, id, true) if err != nil { core.HandleNotFound(c, w) return } if !article.IsPublic { user := auth.CurrentUser(c) if !user.IsAdmin { core.HandleAuthRequired(c, w) return } } redirectTo, err := article.URL() if err != nil { core.HandleNotFound(c, w) return } http.Redirect(w, r, redirectTo.Path, 302) }
func handleIndex(w http.ResponseWriter, r *http.Request) { c := appengine.NewContext(r) // Get user info userInfo := getUserInfo(c) // Get post id and page id pageId, _ := strconv.Atoi(getUrlQuery(r.URL, "pid")) pageSize := config.PageSize // Get offset and page numbers offset, pageNums := getOffset("Article", pageId, pageSize, c) // New PageSetting pageSetting := new(PageSetting) // Setting PageSetting pageSetting.Title = config.Title pageSetting.Description = config.Description pageSetting.Layout = "column2" pageSetting.ShowSidebar = true // showNext and showPrev button if pageId <= 0 || pageId > pageNums { pageId = 1 } if pageId < pageNums { pageSetting.ShowPrev = true } if pageId != 1 { pageSetting.ShowNext = true } pageSetting.PrevPageID = pageId + 1 pageSetting.NextPageID = pageId - 1 // Get article data dbQuery := datastore.NewQuery("Article").Order("-Date").Offset(offset).Limit(pageSize) articleData, err := getArticleData(dbQuery, true, c) if err != nil { serveError(c, w, err) return } // Get widget data dbQuery = datastore.NewQuery("Widget").Order("Sequence") widgetData, err := getWidgetData(dbQuery, true, c) if err != nil { serveError(c, w, err) return } // New PageData pageData := &PageData{ User: userInfo, Article: articleData, Widget: widgetData } // New Page page := NewPage(pageSetting, pageData) // Render page page.Render("index", w) }
// insertItem inserts a Timeline Item in the user's Timeline. func insertItem(r *http.Request, svc *mirror.Service) string { c := appengine.NewContext(r) c.Infof("Inserting Timeline Item") body := mirror.TimelineItem{ Notification: &mirror.NotificationConfig{Level: "AUDIO_ONLY"}, } if r.FormValue("html") == "on" { body.Html = r.FormValue("message") } else { body.Text = r.FormValue("message") } var media io.Reader = nil mediaLink := r.FormValue("imageUrl") if mediaLink != "" { if strings.HasPrefix(mediaLink, "/") { mediaLink = fullURL(r.Host, mediaLink) } c.Infof("Downloading media from: %s", mediaLink) client := urlfetch.Client(c) if resp, err := client.Get(mediaLink); err != nil { c.Errorf("Unable to retrieve media: %s", err) } else { defer resp.Body.Close() media = resp.Body } } if _, err := svc.Timeline.Insert(&body).Media(media).Do(); err != nil { return fmt.Sprintf("Unable to insert timeline item: %s", err) } return "A timeline item has been inserted." }
// insertItemAllUsers inserts a Timeline Item to all authorized users. func insertItemAllUsers(r *http.Request, svc *mirror.Service) string { c := appengine.NewContext(r) c.Infof("Inserting timeline item to all users") q := datastore.NewQuery("OAuth2Token") count, err := q.Count(c) if err != nil { return fmt.Sprintf("Unable to fetch users: %s", err) } if count > 5 { return fmt.Sprintf("Total user count is %d. Aborting broadcast to save your quota", count) } body := mirror.TimelineItem{ Text: "Hello Everyone!", Notification: &mirror.NotificationConfig{Level: "AUDIO_ONLY"}, } i := q.Run(c) tok := new(oauth.Token) creds := &oauth.Transport{ Config: config(""), Token: tok, Transport: &urlfetch.Transport{Context: c}, } svc, _ = mirror.New(creds.Client()) failed := 0 for _, err = i.Next(tok); err == nil; _, err = i.Next(tok) { if _, err := svc.Timeline.Insert(&body).Do(); err != nil { c.Errorf("Failed to insert timeline item: %s", err) failed += 1 } } return fmt.Sprintf("Sent cards to %d (%d failed).", count, failed) }
func accept(w http.ResponseWriter, r *http.Request) { c := appengine.NewContext(r) id := r.FormValue("id") intID, err := strconv.ParseInt(id, 10, 64) if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return } pkg := &Package{} key := datastore.NewKey(c, "Package", "", intID, nil) err = datastore.Get(c, key, pkg) if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return } // check if the package is already present acceptQuery := datastore.NewQuery("Package"). Filter("Accepted =", true). Filter("Repo =", pkg.Repo) var packages []*Package keys, err := acceptQuery.GetAll(c, &packages) if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return } if len(packages) > 1 { // just print an error to let admin know c.Errorf("More tha one package for repo: %v", pkg.Repo) } if len(packages) > 0 { // update the package and delete oldKey := keys[0] oldPkg := packages[0] oldPkg.Name = pkg.Name oldPkg.Description = pkg.Description oldPkg.IsLibrary = pkg.IsLibrary oldPkg.Category = pkg.Category oldPkg.Updated = time.Now() if _, err = datastore.Put(c, oldKey, oldPkg); err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return } if err = datastore.Delete(c, key); err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return } } else { // accept the new package pkg.Accepted = true if _, err = datastore.Put(c, key, pkg); err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return } } memcache.Delete(c, pkg.Repo) memcache.Delete(c, CAT) memcache.Delete(c, ALL_QUERY) }
func ArticlePageHandler(w http.ResponseWriter, r *http.Request) { c := appengine.NewContext(r) user := auth.CurrentUser(c) vars := mux.Vars(r) page, err := strconv.ParseInt(vars["page"], 10, 32) if err != nil { page = 1 } q := NewArticleQuery().Order("-CreatedOn") if !user.IsAdmin { q = q.Filter("IsPublic=", true) } p := NewArticlePager(c, q, int(page)) articles, err := GetArticles(c, p) if err != nil { core.HandleError(c, w, err) return } context := tmplt.Context{ "articles": articles, "pager": p, } core.RenderTemplate(c, w, context, "templates/blog/articleList.html", "templates/pager.html", LAYOUT) }
func WebHandler(w http.ResponseWriter, r *http.Request) { query := r.URL.Query() code := query.Get("code") if code == "" { http.Error(w, "Cannot get code from facebook.", 505) return } context := appengine.NewContext(r) client := urlfetch.Client(context) fb.SetHttpClient(client) redirectURL := "http://" + r.Host + r.URL.Path accessResp, err := fb.Get("/v2.4/oauth/access_token", fb.Params{ "code": code, "redirect_uri": redirectURL, "client_id": clientID, "client_secret": APPSECRET, }) check(err, context) var accessToken string accessResp.DecodeField("access_token", &accessToken) paths := strings.Split(r.URL.Path, "/") party := paths[len(paths)-1] photoID := UploadPhoto(accessToken, party, context) redirectUrl := "https://facebook.com/photo.php?fbid=" + photoID + "&makeprofile=1&prof" http.Redirect(w, r, redirectUrl, 303) }
// tileHandler implements a tile renderer for use with the Google Maps JavaScript API. // See http://code.google.com/apis/maps/documentation/javascript/maptypes.html#ImageMapTypes func tileHandler(w http.ResponseWriter, r *http.Request) { c := appengine.NewContext(r) x, _ := strconv.Atoi(r.FormValue("x")) y, _ := strconv.Atoi(r.FormValue("y")) z, _ := strconv.Atoi(r.FormValue("z")) w.Header().Set("Content-Type", "image/png") // Try memcache first. key := fmt.Sprintf("mandelbrot:%d/%d/%d", x, y, z) if z < maxMemcacheLevel { if item, err := memcache.Get(c, key); err == nil { w.Write(item.Value) return } } b := render(x, y, z) if z < maxMemcacheLevel { memcache.Set(c, &memcache.Item{ Key: key, Value: b, Expiration: 3600, // TTL = 1 hour }) } w.Header().Set("Content-Length", strconv.Itoa(len(b))) w.Write(b) }
func grantSubscribe(w http.ResponseWriter, r *http.Request) { q := r.URL.Query() ch := q.Get("ch") read := q.Get("r") write := q.Get("w") ttl := q.Get("ttl") bRead := false if read == "1" { bRead = true } bWrite := false if write == "1" { bWrite = true } iTTL := 1440 if ival, err := strconv.Atoi(ttl); err == nil { iTTL = ival } uuid := q.Get("uuid") c := appengine.NewContext(r) pubInstance := messaging.New(c, uuid, w, r, publishKey, subscribeKey, secretKey, "", false) errorChannel := make(chan []byte) successChannel := make(chan []byte) go pubInstance.GrantSubscribe(c, w, r, ch, bRead, bWrite, iTTL, successChannel, errorChannel) handleResult(c, w, r, uuid, successChannel, errorChannel, messaging.GetNonSubscribeTimeout(), "Revoke Subscribe") }
func handleInviteByMail(w http.ResponseWriter, r *http.Request) { c := appengine.NewContext(r) _, _, err := getSession(c, r) if err != nil { sendError(w, r, "No session cookie") return } blob, err := ioutil.ReadAll(r.Body) if err != nil { sendError(w, r, "Error reading request body") return } r.Body.Close() var req inviteByMail err = json.Unmarshal(blob, &req) if err != nil { sendError(w, r, "Malformed request body: "+err.String()) return } msg := &mail.Message{ Sender: "*****@*****.**", To: []string{req.UserName}, Subject: "Invitation to LightWave", Body: req.Content, } if err := mail.Send(c, msg); err != nil { sendError(w, r, "Could not send mail") c.Errorf("Couldn't send email: %v", err) } }
func getAuthKey(w http.ResponseWriter, r *http.Request) { q := r.URL.Query() uuid := q.Get("uuid") c := appengine.NewContext(r) pubInstance := messaging.New(c, uuid, w, r, publishKey, subscribeKey, secretKey, "", false) sendResponseToChannel(w, "Auth key: "+pubInstance.GetAuthenticationKey(), r, uuid) }
func DateHandler(w http.ResponseWriter, r *http.Request) { c := appengine.NewContext(r) c.Infof("cs253: Requested URL: %v", r.URL) c.Infof("cs253: Http METHOD: %v", r.Method) if r.Method == "GET" { date := Date{ Month: "", Day: "", Year: "", } if err := dateTemplate.Execute(w, date); err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return } } else if r.Method == "POST" { d := Date{ Month: validMonth(r.FormValue("month")), Day: validDay(r.FormValue("day")), Year: validYear(r.FormValue("year")), } if d.Day == "" || d.Month == "" || d.Year == "" { d.Error = "That's an error!" if err := dateTemplate.Execute(w, d); err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return } } http.Redirect(w, r, "/unit1/thanks", http.StatusFound) } else { tools.Error404(w) return } }
func uploadBlob(w http.ResponseWriter, r *http.Request) { bodyData, error := ioutil.ReadAll(r.Body) fileType := r.URL.Query()["type"][0] var mimeType string if fileType == "png" { mimeType = "image/png" } else { mimeType = "application/pdf" } context := appengine.NewContext(r) writer, error := blobstore.Create(context, mimeType) if error != nil { return } _, error = writer.Write(bodyData) if error != nil { return } error = writer.Close() if error != nil { return } var k appengine.BlobKey k, _ = writer.Key() encoder := json.NewEncoder(w) encoder.Encode(&UploadBlobResponse{Key: string(k)}) }
// GetApiConfigs creates APIDescriptor for every registered RPCService and // responds with a config suitable for generating Discovery doc. // // Responds with a list of active APIs and their configuration files. func (s *BackendService) GetApiConfigs( r *http.Request, req *GetAPIConfigsRequest, resp *APIConfigsList) error { c := appengine.NewContext(r) if req.AppRevision != "" { revision := strings.Split(appengine.VersionID(c), ".")[1] if req.AppRevision != revision { err := fmt.Errorf( "API backend app revision %s not the same as expected %s", revision, req.AppRevision) c.Errorf("%s", err) return err } } resp.Items = make([]string, 0) for _, service := range s.server.services.services { if service.internal { continue } d := &APIDescriptor{} if err := service.APIDescriptor(d, r.Host); err != nil { c.Errorf("%s", err) return err } bytes, err := json.Marshal(d) if err != nil { c.Errorf("%s", err) return err } resp.Items = append(resp.Items, string(bytes)) } return nil }
func contactRequestHandler(w http.ResponseWriter, r *http.Request) { name := r.FormValue("name") email := r.FormValue("email") subject := r.FormValue("subject") message := r.FormValue("message") if len(email) == 0 { fmt.Fprint(w, "invalid request") return } context := appengine.NewContext(r) mailMessage := &mail.Message{ Sender: name + " <*****@*****.**>", ReplyTo: email, To: []string{"*****@*****.**"}, Subject: subject, Body: message, } if error := mail.Send(context, mailMessage); error != nil { context.Errorf("the email could not be sent: %v", error) } http.ServeFile(w, r, "static/html/contact/contact_sent.html") }
func realInit(w http.ResponseWriter, r *http.Request) bool { ctx := appengine.NewContext(r) errf := func(format string, args ...interface{}) bool { ctx.Errorf("In init: "+format, args...) http.Error(w, fmt.Sprintf(format, args...), 500) return false } config, err := serverconfig.Load("./config.json") if err != nil { return errf("Could not load server config: %v", err) } // Update the config to use the URL path derived from the first App Engine request. // TODO(bslatkin): Support hostnames that aren't x.appspot.com scheme := "http" if r.TLS != nil { scheme = "https" } baseURL := fmt.Sprintf("%s://%s/", scheme, appengine.DefaultVersionHostname(ctx)) ctx.Infof("baseurl = %q", baseURL) root.mux = http.NewServeMux() _, err = config.InstallHandlers(root.mux, baseURL, r) if err != nil { return errf("Error installing handlers: %v", err) } return true }
func register(w http.ResponseWriter, req *http.Request) { req.ParseForm() context := appengine.NewContext(req) team := Team{ Date: time.Now(), Name: req.FormValue("name"), Email: req.FormValue("email"), Phonenumber: req.FormValue("phone"), PartnerName: req.FormValue("partner-name"), PartnerEmail: req.FormValue("partner-email"), PartnerPhonenumber: req.FormValue("partner-phone"), Tech: strings.Join(req.Form["tech"], ","), TeamDescrition: req.FormValue("descript"), TeamWish: req.FormValue("wish"), } // TODO make vaildater key := datastore.NewIncompleteKey(context, "3rd", getDataStoreKey(context)) _, err := datastore.Put(context, key, &team) if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) } else { view.Render(w, "main", RenderData{Mode: "pc"}) return } }