First pass at basic functionality.
This PR introduces the beginnings of Sprint Padawan. Reviewed-on: #1
This commit was merged in pull request #1.
This commit is contained in:
+189
@@ -0,0 +1,189 @@
|
||||
package lib
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
type Story struct {
|
||||
ID int
|
||||
RoomID int
|
||||
Title string
|
||||
Points *int
|
||||
Voted bool
|
||||
}
|
||||
|
||||
type Vote struct {
|
||||
ID int
|
||||
StoryID int
|
||||
UserID int
|
||||
Value string
|
||||
}
|
||||
|
||||
// create story
|
||||
func CreateStory(roomID int, title string) (*Story, error) {
|
||||
res, err := DB.Exec("INSERT INTO stories (room_id, title, voted) VALUES (?, ?, 0)", roomID, title)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
id64, err := res.LastInsertId()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &Story{
|
||||
ID: int(id64),
|
||||
RoomID: roomID,
|
||||
Title: title,
|
||||
Points: nil,
|
||||
Voted: false,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// get stories for room
|
||||
func GetStoriesForRoom(roomID int) ([]Story, error) {
|
||||
rows, err := DB.Query("SELECT id, room_id, title, points, voted FROM stories WHERE room_id = ? ORDER BY id", roomID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
var stories []Story
|
||||
for rows.Next() {
|
||||
var s Story
|
||||
var points sql.NullInt64
|
||||
var voted int
|
||||
err := rows.Scan(&s.ID, &s.RoomID, &s.Title, &points, &voted)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if points.Valid {
|
||||
p := int(points.Int64)
|
||||
s.Points = &p
|
||||
}
|
||||
s.Voted = voted == 1
|
||||
stories = append(stories, s)
|
||||
}
|
||||
return stories, nil
|
||||
}
|
||||
|
||||
// vote on story
|
||||
func VoteOnStory(storyID, userID int, value string) error {
|
||||
_, err := DB.Exec("INSERT OR REPLACE INTO votes (story_id, user_id, value) VALUES (?, ?, ?)", storyID, userID, value)
|
||||
return err
|
||||
}
|
||||
|
||||
// get votes for story
|
||||
func GetVotesForStory(storyID int) ([]Vote, error) {
|
||||
rows, err := DB.Query("SELECT story_id, user_id, value FROM votes WHERE story_id = ?", storyID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
var votes []Vote
|
||||
for rows.Next() {
|
||||
var v Vote
|
||||
err := rows.Scan(&v.StoryID, &v.UserID, &v.Value)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
votes = append(votes, v)
|
||||
}
|
||||
return votes, nil
|
||||
}
|
||||
|
||||
// reveal votes — just marks the story as revealed
|
||||
func RevealVotes(storyID int) error {
|
||||
_, err := DB.Exec("UPDATE stories SET voted = 1 WHERE id = ?", storyID)
|
||||
return err
|
||||
}
|
||||
|
||||
type VoteView struct {
|
||||
Username string
|
||||
Value string
|
||||
}
|
||||
|
||||
// get votes with usernames for display
|
||||
func GetVotesWithUsernames(storyID int) ([]VoteView, error) {
|
||||
rows, err := DB.Query(`
|
||||
SELECT u.username, v.value
|
||||
FROM votes v
|
||||
JOIN users u ON v.user_id = u.id
|
||||
WHERE v.story_id = ?
|
||||
`, storyID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
var views []VoteView
|
||||
for rows.Next() {
|
||||
var vv VoteView
|
||||
err := rows.Scan(&vv.Username, &vv.Value)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
views = append(views, vv)
|
||||
}
|
||||
return views, nil
|
||||
}
|
||||
|
||||
// unreveal story — set voted back to 0 and clear points
|
||||
func UnrevealStory(storyID int) error {
|
||||
_, err := DB.Exec("UPDATE stories SET voted = 0, points = NULL WHERE id = ?", storyID)
|
||||
return err
|
||||
}
|
||||
|
||||
// clear all votes for a story
|
||||
func ClearVotesForStory(storyID int) error {
|
||||
_, err := DB.Exec("DELETE FROM votes WHERE story_id = ?", storyID)
|
||||
return err
|
||||
}
|
||||
|
||||
// rename story
|
||||
func RenameStory(storyID int, title string) error {
|
||||
_, err := DB.Exec("UPDATE stories SET title = ? WHERE id = ?", title, storyID)
|
||||
return err
|
||||
}
|
||||
|
||||
// delete story and its votes
|
||||
func DeleteStory(storyID int) error {
|
||||
_, err := DB.Exec("DELETE FROM stories WHERE id = ?", storyID)
|
||||
return err
|
||||
}
|
||||
|
||||
func tshirtToPoints(s string) float64 {
|
||||
switch s {
|
||||
case "XS":
|
||||
return 1
|
||||
case "S":
|
||||
return 3
|
||||
case "M":
|
||||
return 5
|
||||
case "L":
|
||||
return 8
|
||||
case "XL":
|
||||
return 13
|
||||
case "XXL":
|
||||
return 21
|
||||
case "?":
|
||||
return 0
|
||||
default:
|
||||
n, _ := strconv.Atoi(s)
|
||||
return float64(n)
|
||||
}
|
||||
}
|
||||
|
||||
func GetStoryByID(id int) (*Story, error) {
|
||||
row := DB.QueryRow("SELECT id, room_id, title, points, voted FROM stories WHERE id = ?", id)
|
||||
var s Story
|
||||
var points sql.NullInt64
|
||||
var voted int
|
||||
err := row.Scan(&s.ID, &s.RoomID, &s.Title, &points, &voted)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if points.Valid {
|
||||
p := int(points.Int64)
|
||||
s.Points = &p
|
||||
}
|
||||
s.Voted = voted == 1
|
||||
return &s, nil
|
||||
}
|
||||
Reference in New Issue
Block a user