func GetMembers(c web.C, w http.ResponseWriter, r *http.Request) { var ( db = c.Env["db"].(*mgo.Database) user = c.Env["user"].(bson.ObjectId) boardIDHex = c.URLParams["board_id"] ) // find the board and make sure the user making the request is a member board, err := getBoard(db, boardIDHex) if err != nil { utils.Error(w, err.Error(), err.HTTPStatusCode) return } if !board.IsMember(user) { utils.Error(w, "", http.StatusForbidden) return } // return the members of the board utils.WriteJSON(w, http.StatusOK, board.Members) return }
func GetBoard(c web.C, w http.ResponseWriter, r *http.Request) { var ( db = c.Env["db"].(*mgo.Database) user = c.Env["user"].(bson.ObjectId) boardIDHex = c.URLParams["board_id"] ) // get the board specified by 'board_id' board, err := getBoard(db, boardIDHex) if err != nil { utils.Error(w, err.Error(), err.HTTPStatusCode) return } // make sure the user is a member on it if !board.IsMember(user) { utils.Error(w, "", http.StatusForbidden) return } // return it utils.WriteJSON(w, http.StatusOK, board) return }
func authenticate(c *web.C, h http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { var ( db = c.Env["db"].(*mgo.Database) auth = strings.Split(r.Header.Get("authorization"), " ") ) // validate that the authorization header is correctly formatted if len(auth) != 2 || auth[0] != "Bearer" { utils.Error(w, "Authorization: Bearer <Token>", http.StatusUnauthorized) return } // find the token var ( token = models.Token{} tokenQuery = db.C("tokens").Find(bson.M{ "secret": auth[1], }) ) if err := tokenQuery.One(&token); err != nil { if err == mgo.ErrNotFound { utils.Error(w, err.Error(), http.StatusUnauthorized) return } utils.Error(w, err.Error(), http.StatusInternalServerError) return } // find the user corresponding to the token and attach its // 'ID' attribute to the request's context under the 'user' key var ( user = models.User{} userQuery = db.C("users").FindId(token.UserID) ) if err := userQuery.One(&user); err != nil { if err == mgo.ErrNotFound { utils.Error(w, err.Error(), http.StatusUnauthorized) return } utils.Error(w, err.Error(), http.StatusInternalServerError) return } c.Env["user"] = user.ID h.ServeHTTP(w, r) return }) }
func AddBoard(c web.C, w http.ResponseWriter, r *http.Request) { var ( db = c.Env["db"].(*mgo.Database) user = c.Env["user"].(bson.ObjectId) payload struct { Name string `json:"name"` Description string `json:"description"` Size models.Size `json:"size"` Background string `json:"background"` } ) // read the payload if err := utils.ReadJSON(r, &payload); err != nil { utils.Error(w, err.Error(), http.StatusBadRequest) return } // create the board, with the requesting user as the creator board := models.Board{ ID: bson.NewObjectId(), CreatedBy: user, CreatedAt: time.Now(), Name: payload.Name, Size: payload.Size, Background: payload.Background, Description: payload.Description, Members: []models.Member{ { Role: "admin", UserID: user, MemberSince: time.Now(), }, }, } if err := db.C("boards").Insert(&board); err != nil { utils.Error(w, err.Error(), http.StatusInternalServerError) return } // respond with the created board utils.WriteJSON(w, http.StatusCreated, &board) return }
func UpdateBoard(c web.C, w http.ResponseWriter, r *http.Request) { var ( db = c.Env["db"].(*mgo.Database) user = c.Env["user"].(bson.ObjectId) boardIDHex = c.URLParams["board_id"] payload struct { Name string `json:"name"` Background string `json:"background"` Description string `json:"description"` } ) board, err := updateBoard(db, user, boardIDHex, bson.M{ "name": payload.Name, "background": payload.Background, "description": payload.Description, }) if err != nil { utils.Error(w, err.Error(), err.HTTPStatusCode) return } utils.WriteJSON(w, http.StatusOK, &board) return }
func RemoveTicket(c web.C, w http.ResponseWriter, r *http.Request) { var ( db = c.Env["db"].(*mgo.Database) user = c.Env["user"].(bson.ObjectId) boardIDHex = c.URLParams["board_id"] ticketIDHex = c.URLParams["ticket_id"] ) // get the board for this request, and make sure the user making the // request is a member on this board board, err := getBoard(db, boardIDHex) if err != nil { utils.Error(w, err.Error(), err.HTTPStatusCode) return } if !board.IsMember(user) { utils.Error(w, "", http.StatusForbidden) return } // get the ticket ticket, err := getTicket(db, boardIDHex, ticketIDHex) if err != nil { utils.Error(w, err.Error(), err.HTTPStatusCode) return } // remove the ticket from 'tickets'-collection and return the removed ticket if err := db.C("tickets").RemoveId(ticket.ID); err != nil { if err == mgo.ErrNotFound { utils.Error(w, "Ticket not found", http.StatusNotFound) return } utils.Error(w, err.Error(), http.StatusInternalServerError) return } utils.WriteJSON(w, http.StatusOK, ticket) return }
func RemoveBoard(c web.C, w http.ResponseWriter, r *http.Request) { var ( db = c.Env["db"].(*mgo.Database) user = c.Env["user"].(bson.ObjectId) boardIDHex = c.URLParams["board_id"] ) // get the board specified by 'board_id' and make sure the user // is an 'admin' on the board board, err := getBoard(db, boardIDHex) if err != nil { utils.Error(w, err.Error(), err.HTTPStatusCode) return } if board.GetRole(user) != "admin" { utils.Error(w, "User must have 'admin' privileges", http.StatusForbidden) return } // remove board, and the tickets that are associated with it if err := db.C("boards").RemoveId(board.ID); err != nil { utils.Error(w, err.Error(), http.StatusInternalServerError) return } if _, err := db.C("tickets").RemoveAll(bson.M{ "board_id": board.ID, }); err != nil { utils.Error(w, err.Error(), http.StatusInternalServerError) return } // return the removed board utils.WriteJSON(w, http.StatusOK, board) return }
func RemoveMember(c web.C, w http.ResponseWriter, r *http.Request) { var ( db = c.Env["db"].(*mgo.Database) user = c.Env["user"].(bson.ObjectId) boardIDHex = c.URLParams["board_id"] memberIDHex = c.URLParams["member_id"] ) // get the board for this request, the user must be an 'admin' board, err := getBoard(db, boardIDHex) if err != nil { utils.Error(w, err.Error(), err.HTTPStatusCode) return } if board.GetRole(user) != "admin" { utils.Error(w, "", http.StatusForbidden) return } // make sure the 'user_id' is a valid ObjectID, and that // the member actually exists if !bson.IsObjectIdHex(memberIDHex) { utils.Error(w, "'user_id' must be a valid 'ObjectID'", http.StatusBadRequest) return } memberID := bson.ObjectIdHex(memberIDHex) member := board.GetMember(memberID) if member == nil { utils.Error(w, "Member not found", http.StatusNotFound) return } // remove the membership and return the removed member if err := db.C("boards").UpdateId(board.ID, bson.M{ "$pull": bson.M{ "members": bson.M{ "user_id": member.UserID, }, }, }); err != nil { if err == mgo.ErrNotFound { utils.Error(w, "Board not found", http.StatusNotFound) return } utils.Error(w, err.Error(), http.StatusInternalServerError) return } utils.WriteJSON(w, http.StatusOK, member) return }
func GetTickets(c web.C, w http.ResponseWriter, r *http.Request) { var ( db = c.Env["db"].(*mgo.Database) user = c.Env["user"].(bson.ObjectId) boardIDHex = c.URLParams["board_id"] ) // find the board and make sure the user making the request is a member board, err := getBoard(db, boardIDHex) if err != nil { utils.Error(w, err.Error(), err.HTTPStatusCode) return } if !board.IsMember(user) { utils.Error(w, "User must be a member", http.StatusForbidden) return } // find tickets that are on this board and return them var ( tickets = []models.Ticket{} ticketsQuery = db.C("tickets").Find(bson.M{ "board_id": board.ID, }) ) if err := ticketsQuery.All(&tickets); err != nil { utils.Error(w, err.Error(), http.StatusInternalServerError) return } utils.WriteJSON(w, http.StatusOK, tickets) return }
func UpdateBoardSize(c web.C, w http.ResponseWriter, r *http.Request) { var ( db = c.Env["db"].(*mgo.Database) user = c.Env["user"].(bson.ObjectId) boardIDHex = c.URLParams["board_id"] payload struct { Width string `json:"width"` Height string `json:"height"` } ) // read the payload if err := utils.ReadJSON(r, &payload); err != nil { utils.Error(w, err.Error(), http.StatusBadRequest) return } // update the board and return the updated board to the user board, err := updateBoard(db, user, boardIDHex, bson.M{ "size": bson.M{ "width": payload.Width, "height": payload.Height, }, }) if err != nil { utils.Error(w, err.Error(), err.HTTPStatusCode) return } utils.WriteJSON(w, http.StatusOK, &board) return }
func GetUsers(c web.C, w http.ResponseWriter, r *http.Request) { var ( db = c.Env["db"].(*mgo.Database) users = []models.User{} usersQuery = db.C("users").Find(nil) ) if err := usersQuery.All(&users); err != nil { utils.Error(w, err.Error(), http.StatusInternalServerError) return } utils.WriteJSON(w, http.StatusOK, users) return }
func GetUser(c web.C, w http.ResponseWriter, r *http.Request) { var ( db = c.Env["db"].(*mgo.Database) userIDHex = c.URLParams["user_id"] ) user, err := getUser(db, userIDHex) if err != nil { utils.Error(w, err.Error(), err.HTTPStatusCode) return } utils.WriteJSON(w, http.StatusOK, user) return }
func GetBoards(c web.C, w http.ResponseWriter, r *http.Request) { var ( db = c.Env["db"].(*mgo.Database) user = c.Env["user"].(bson.ObjectId) boards = []models.Board{} boardsQuery = db.C("boards").Find(bson.M{ "members.user_id": user, }) ) // return all the boards that the user is member of if err := boardsQuery.All(&boards); err != nil { utils.Error(w, err.Error(), http.StatusInternalServerError) return } utils.WriteJSON(w, http.StatusOK, boards) return }
func UpdateTicket(c web.C, w http.ResponseWriter, r *http.Request) { var ( db = c.Env["db"].(*mgo.Database) user = c.Env["user"].(bson.ObjectId) boardIDHex = c.URLParams["board_id"] ticketIDHex = c.URLParams["ticket_id"] payload struct { Color string `json:"color"` Heading string `json:"heading"` Content string `json:"content"` } ) // read the payload if err := utils.ReadJSON(r, &payload); err != nil { utils.Error(w, err.Error(), http.StatusBadRequest) return } // check that 'ticket_id' is a valid 'ObjectID' if !bson.IsObjectIdHex(ticketIDHex) { utils.Error(w, "'ticket_id' must be a valid 'ObjectID'", http.StatusBadRequest) return } ticketID := bson.ObjectIdHex(ticketIDHex) // get the board and make sure that the user is a member board, err := getBoard(db, boardIDHex) if err != nil { utils.Error(w, err.Error(), err.HTTPStatusCode) return } if !board.IsMember(user) { utils.Error(w, "", http.StatusForbidden) return } // apply the update and return the newly updated ticket var ( ticket = models.Ticket{} ticketQuery = db.C("tickets").FindId(ticketID) ticketUpdate = mgo.Change{ Update: bson.M{ "color": payload.Color, "heading": payload.Heading, "content": payload.Content, }, ReturnNew: true, } ) if _, err := ticketQuery.Apply(ticketUpdate, &ticket); err != nil { if err == mgo.ErrNotFound { utils.Error(w, "Ticket not found", http.StatusNotFound) return } utils.Error(w, err.Error(), http.StatusInternalServerError) return } utils.WriteJSON(w, http.StatusOK, &ticket) return }
func AddMember(c web.C, w http.ResponseWriter, r *http.Request) { var ( db = c.Env["db"].(*mgo.Database) user = c.Env["user"].(bson.ObjectId) boardIDHex = c.URLParams["board_id"] payload struct { Role string `json:"role"` UserID bson.ObjectId `json:"user_id"` } ) // read the payload if err := utils.ReadJSON(r, &payload); err != nil { utils.Error(w, err.Error(), http.StatusBadRequest) return } // validate that the 'role' in payload matches either 'admin' or 'member' if payload.Role != "admin" && payload.Role != "member" { utils.Error(w, "'role' must be either 'admin' or 'member'", http.StatusBadRequest) return } // get the requested board board, err := getBoard(db, boardIDHex) if err != nil { utils.Error(w, err.Error(), err.HTTPStatusCode) return } // make sure the user making the request is 'admin' on the board if board.GetRole(user) != "admin" { utils.Error(w, "Role 'admin' required", http.StatusForbidden) return } // make sure the user we are about to add is not already a member // and that the user actually exists if board.IsMember(payload.UserID) { utils.Error(w, "User is already a member", http.StatusConflict) return } // TODO what is the most efficient way of checking that the // document we are referencing with 'user_id' actually exists // add the user as a member newMember := models.Member{ Role: payload.Role, UserID: payload.UserID, MemberSince: time.Now(), } if err := db.C("boards").UpdateId(board.ID, bson.M{ "$push": bson.M{ "members": newMember, }, }); err != nil { utils.Error(w, err.Error(), http.StatusInternalServerError) return } // return the member we just added utils.WriteJSON(w, http.StatusCreated, &newMember) return }
func UpdateBoardMember(c web.C, w http.ResponseWriter, r *http.Request) { var ( db = c.Env["db"].(*mgo.Database) user = c.Env["user"].(bson.ObjectId) boardIDHex = c.URLParams["board_id"] memberIDHex = c.URLParams["member_id"] payload struct { Role string `json:"height"` } ) // read the payload if err := utils.ReadJSON(r, &payload); err != nil { utils.Error(w, err.Error(), http.StatusBadRequest) return } // make sure the 'member_id' attribute is a valid 'ObjectID' if !bson.IsObjectIdHex(memberIDHex) { utils.Error(w, "'user_id' must be a valid 'ObjectID'", http.StatusBadRequest) return } memberID := bson.ObjectIdHex(memberIDHex) // get the board and make sure the user has admin access board, err := getBoard(db, boardIDHex) if err != nil { utils.Error(w, err.Error(), err.HTTPStatusCode) return } if board.GetRole(user) != "admin" { utils.Error(w, "", http.StatusForbidden) return } // make sure the 'member_id' is an actual member member := board.GetMember(memberID) if member == nil { utils.Error(w, "Member not found on Board", http.StatusNotFound) return } // apply updates and return the newly updated board // NOTE this does not use the 'updateBoard' helper function // because this uses the positional operator to update // the embedded member document var ( boardQuery = bson.M{ "_id": board.ID, "members.user_id": member.UserID, } boardUpdate = bson.M{ "$set": bson.M{ "members.$.role": payload.Role, }, } ) if err := db.C("boards").Update(boardQuery, boardUpdate); err != nil { if err == mgo.ErrNotFound { utils.Error(w, "Board not found", http.StatusNotFound) return } utils.Error(w, err.Error(), http.StatusInternalServerError) return } member.Role = payload.Role utils.WriteJSON(w, http.StatusOK, &member) return }
func AddTicket(c web.C, w http.ResponseWriter, r *http.Request) { var ( db = c.Env["db"].(*mgo.Database) user = c.Env["user"].(bson.ObjectId) boardIDHex = c.URLParams["board_id"] payload struct { Color string `json:"color"` Heading string `json:"heading"` Content string `json:"content"` Position models.Position `json:"position"` } ) // read the payload if err := utils.ReadJSON(r, &payload); err != nil { utils.Error(w, err.Error(), http.StatusBadRequest) return } // get the required board and make sure the requesting user is a member board, err := getBoard(db, boardIDHex) if err != nil { utils.Error(w, err.Error(), err.HTTPStatusCode) return } if !board.IsMember(user) { utils.Error(w, "User must be a board member", http.StatusForbidden) return } // insert a new 'Ticket' into 'tickets' newTicket := models.Ticket{ ID: bson.NewObjectId(), BoardID: board.ID, Color: payload.Color, Heading: payload.Heading, Content: payload.Content, Position: payload.Position, CreatedBy: user, CreatedAt: time.Now(), } if err := db.C("tickets").Insert(&newTicket); err != nil { utils.Error(w, err.Error(), http.StatusInternalServerError) return } // return the added ticket utils.WriteJSON(w, http.StatusCreated, &newTicket) return }