func ListEntries(w http.ResponseWriter, r *http.Request) { stopwatch.Reset("GET /diary/entries/{account_name}") defer stopwatch.Watch("finish GET /diary/entries/{account_name}") if !authenticated(w, r) { return } account := mux.Vars(r)["account_name"] owner := getUserFromAccount(w, account) var query string if permitted(w, r, owner.ID) { query = `SELECT id, user_id, private, body, created_at FROM entries WHERE user_id = ? ORDER BY created_at DESC LIMIT 20` } else { query = `SELECT id, user_id, private, body, created_at FROM entries WHERE user_id = ? AND private=0 ORDER BY created_at DESC LIMIT 20` } rows, err := db.Query(query, owner.ID) if err != sql.ErrNoRows { checkErr(err) } entries := make([]Entry, 0, 20) for rows.Next() { var id, userID, private int var body string var createdAt time.Time checkErr(rows.Scan(&id, &userID, &private, &body, &createdAt)) entry := Entry{id, userID, private == 1, strings.SplitN(body, "\n", 2)[0], strings.SplitN(body, "\n", 2)[1], createdAt} entries = append(entries, entry) } rows.Close() markFootprint(w, r, owner.ID) w.WriteHeader(http.StatusOK) checkErr(EntriesMyTmpl(w, struct { Owner *User Entries []Entry Myself bool }{owner, entries, getCurrentUser(w, r).ID == owner.ID})) }
func GetIndex(w http.ResponseWriter, r *http.Request) { stopwatch.Reset("GET /") defer stopwatch.Watch("finish GET /") if !authenticated(w, r) { return } stopwatch.Watch("After authorize") user := getCurrentUser(w, r) stopwatch.Watch("After getCurrentUser") prof := Profile{} row := db.QueryRow(`SELECT * FROM profiles WHERE user_id = ?`, user.ID) err := row.Scan(&prof.UserID, &prof.FirstName, &prof.LastName, &prof.Sex, &prof.Birthday, &prof.Pref, &prof.UpdatedAt) if err != sql.ErrNoRows { checkErr(err) } stopwatch.Watch("After Profile") rows, err := db.Query(`SELECT id, user_id, private, body, created_at FROM entries WHERE user_id = ? ORDER BY created_at LIMIT 5`, user.ID) if err != sql.ErrNoRows { checkErr(err) } entries := make([]Entry, 0, 5) for rows.Next() { var id, userID, private int var body string var createdAt time.Time checkErr(rows.Scan(&id, &userID, &private, &body, &createdAt)) entries = append(entries, Entry{id, userID, private == 1, strings.SplitN(body, "\n", 2)[0], strings.SplitN(body, "\n", 2)[1], createdAt}) } rows.Close() stopwatch.Watch("After Entry") rows, err = db.Query(`SELECT c.id AS id, c.entry_id AS entry_id, c.user_id AS user_id, c.summary, c.created_at AS created_at FROM comments c JOIN entries e ON c.entry_id = e.id WHERE e.user_id = ? ORDER BY c.created_at DESC LIMIT 10`, user.ID) if err != sql.ErrNoRows { checkErr(err) } commentsForMe := make([]Comment, 0, 10) for rows.Next() { c := Comment{} checkErr(rows.Scan(&c.ID, &c.EntryID, &c.UserID, &c.Comment, &c.CreatedAt)) commentsForMe = append(commentsForMe, c) } rows.Close() stopwatch.Watch("After Comment") relations := friendsForMe[user.ID] friendsMap := make(map[int]time.Time) friendIds := make([]string, 0) for _, r := range relations { friendID := r.anotherID if _, ok := friendsMap[friendID]; !ok { friendsMap[friendID] = r.createdAt friendIds = append(friendIds, strconv.Itoa(friendID)) } } friends := make([]Friend, 0, len(friendsMap)) for key, val := range friendsMap { friends = append(friends, Friend{key, val}) } rows.Close() stopwatch.Watch("After Relation") entryIndex := "" if len(friendIds) > 20 { entryIndex = "created_at" } else { entryIndex = "user_id" } // fmt.Println(entryIndex) rows, err = db.Query(fmt.Sprintf(`SELECT id, user_id, private, title, created_at FROM entries FORCE INDEX(%s) WHERE user_id IN (%s) ORDER BY created_at DESC LIMIT 10`, entryIndex, strings.Join(friendIds, ","))) if err != sql.ErrNoRows { checkErr(err) } entriesOfFriends := make([]Entry, 0, 10) for rows.Next() { var id, userID, private int var subject string var createdAt time.Time checkErr(rows.Scan(&id, &userID, &private, &subject, &createdAt)) if !isFriend2(friendsMap, userID) { continue } entriesOfFriends = append(entriesOfFriends, Entry{id, userID, private == 1, subject, "", createdAt}) if len(entriesOfFriends) >= 10 { break } } rows.Close() stopwatch.Watch("After entries") // コメントを1000件取得し、privateであれば自分と相手がフレンドかどうかをチェックする commentIndex := "" if len(friendIds) > 20 { commentIndex = "created_at" } else { commentIndex = "user_id" } query := fmt.Sprintf(`SELECT c.id, c.entry_id, c.user_id, c.summary, c.created_at, e.id, e.user_id, e.private, e.title, e.created_at FROM comments c FORCE INDEX (%s) JOIN entries e ON c.entry_id = e.id WHERE c.user_id IN (%s) ORDER BY c.created_at DESC LIMIT 10`, commentIndex, strings.Join(friendIds, ",")) // fmt.Println(query) rows, err = db.Query(query) if err != sql.ErrNoRows { checkErr(err) } commentsOfFriends := make([]CommentWithEntry, 0, 10) for rows.Next() { c := CommentWithEntry{} var id, userID, private int var subject string var createdAt time.Time checkErr(rows.Scan(&c.ID, &c.EntryID, &c.UserID, &c.Comment, &c.CreatedAt, &id, &userID, &private, &subject, &createdAt)) if !isFriend2(friendsMap, c.UserID) { continue } entry := Entry{id, userID, private == 1, subject, "", createdAt} c.Entry = entry if entry.Private { if !permitted(w, r, entry.UserID) { continue } } commentsOfFriends = append(commentsOfFriends, c) if len(commentsOfFriends) >= 10 { break } } rows.Close() stopwatch.Watch("After Friend Comments") footprints, err := getFootprintsFromRedis(user.ID, 10) if err != nil { checkErr(err) } stopwatch.Watch("After Get Friend Comments") w.WriteHeader(http.StatusOK) checkErr(MyTmpl(w, struct { User User Profile Profile Entries []Entry CommentsForMe []Comment EntriesOfFriends []Entry CommentsOfFriends []CommentWithEntry Friends []Friend Footprints []Footprint }{ *user, prof, entries, commentsForMe, entriesOfFriends, commentsOfFriends, friends, footprints, })) stopwatch.Watch("After after render") }