Example #1
0
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}))
}
Example #2
0
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")
}