Example #1
0
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
}
Example #2
0
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
}
Example #3
0
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
	})
}
Example #4
0
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
}
Example #5
0
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
}
Example #7
0
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
}
Example #9
0
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
}
Example #11
0
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
}
Example #12
0
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
}
Example #13
0
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
}
Example #14
0
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
}
Example #15
0
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
}
Example #17
0
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
}