func RemoveUserSubscription(c *gin.Context) { userId := c.Param("user_id") if userId != c.MustGet("request_user_id").(string) { c.Error(errors.NewHttp(http.StatusUnauthorized, "Users can only delete their own subs")) return } notebookId := c.Param("notebook_id") sub := model.DbSubscription{ UserId: userId, NotebookId: notebookId, } section, err := db.GetSectionByNotebookId(sub.NotebookId) if log.Error(err) { c.Error(errors.NewISE()) return } course, err := db.GetCourseByCourseId(section.CourseId) if log.Error(err) { c.Error(errors.NewISE()) return } err = db.DeleteSubscription(sub) if log.Error(err) { c.Error(err) return } c.JSON(http.StatusOK, model.NewSubscriptionResponse(sub, course, section)) }
func GetUsersSubscriptions(c *gin.Context) { userId := c.Param("user_id") if userId != c.MustGet("request_user_id").(string) { c.Error(errors.NewHttp(http.StatusUnauthorized, "Users can only view the subscriptions of themselves")) return } subs, err := db.GetUserSubscriptions(userId) if log.Error(err) { c.Error(errors.NewISE()) return } subResponses := make([]model.SubscriptionResponse, 0) for _, sub := range subs { section, err := db.GetSectionByNotebookId(sub.NotebookId) if log.Error(err) { c.Error(errors.NewISE()) return } course, err := db.GetCourseByCourseId(section.CourseId) if log.Error(err) { c.Error(errors.NewISE()) return } subResponses = append(subResponses, model.NewSubscriptionResponse(sub, course, section)) } c.JSON(http.StatusOK, subResponses) }
// Status handler for the /status route func OpenWebsocket(c *gin.Context) { userId := c.MustGet("request_user_id").(string) noteId := c.Param("note_id") in, note, err := db.GetNoteById(noteId) if log.Error(err) { c.Error(errors.NewISE()) return } if !in { c.Error(errors.NewHttp(http.StatusNotFound, "The requested note was not found")) return } if userId != note.Owner { c.Error(errors.NewHttp(http.StatusUnauthorized, "Only owners can open websockets into their notes")) return } conn, err := websocketUpgrader.Upgrade(c.Writer, c.Request, nil) if log.Error(err) { c.Error(errors.NewISE()) return } log.Info("Opening ws for user %v on %v", userId, note.Id) bundle := model.NewContext(userId, noteId) WrapWebsocket(conn, bundle) ws.ProcessMessages(bundle) }
func SetUserSchool(c *gin.Context) { userId := c.Param("user_id") if userId != c.MustGet("request_user_id").(string) { c.Error(errors.NewHttp(http.StatusUnauthorized, "Users can only modify themselves")) return } var request model.ModifySchoolRequest err := c.BindJSON(&request) if log.Error(err) { c.Error(err) return } _, user, err := db.GetUserById(userId) if log.Error(err) { c.Error(err) return } user.School = sql.NullString{ String: request.SchoolId, Valid: true, } err = db.UpdateUser(user) if log.Error(err) { c.Error(err) return } c.JSON(http.StatusOK, user) }
func GetUnjoinedNotesInNotebook(notebookId, userId string) ([]model.DbNote, error) { // Was going to try and put this logic into sql but im bad at sql notes, err := GetNotesInNotebook(notebookId) if log.Error(err) { return notes, err } userTopics := []string{} for _, note := range notes { if note.Owner == userId { userTopics = append(userTopics, note.TopicId) } } unjoinedNotes := []model.DbNote{} for _, note := range notes { add := true for _, userTopic := range userTopics { if note.TopicId == userTopic { add = false break } } if add { unjoinedNotes = append(unjoinedNotes, note) } } return unjoinedNotes, err }
func GetAllSchools(c *gin.Context) { schools, err := db.GetAllSchools() if log.Error(err) { c.Error(errors.NewISE()) return } c.JSON(http.StatusOK, schools) }
func DumpNoteCache() { ticker := time.Tick(5 * time.Second) for range ticker { for _, note := range NoteIdCache { if log.Error(db.UpdateNote(*note)) { continue } } } }
func HandleUpdate(frame map[string]interface{}, c *model.WsContext) error { var updateFrame model.WsUpdate err := util.FillStruct(&updateFrame, frame) if log.Error(err) { return err } log.Info("Processing update %+v", updateFrame) // Update the note content in our cache note := cache.GetNote(c.NoteId) note.Content, err = updateFrame.Update.Operations.Apply(note.Content) if log.Error(err) { return err } cache.Note(note) return nil }
func PostSchoolRequest(c *gin.Context) { var request model.SchoolRequestRequest err := c.BindJSON(&request) if log.Error(err) { c.Error(err) return } dbreq := model.DbSchoolRequest{ Id: util.NewId(), RequesterUserId: c.MustGet("request_user_id").(string), Name: request.Name, Location: request.Location, } err = db.CreateSchoolRequest(dbreq) if log.Error(err) { c.Error(err) return } c.JSON(http.StatusOK, dbreq) }
func (f Facebook) genericGet(endpoint string, struc interface{}, token string, params url.Values) error { params.Set("access_token", token) fullURL := fmt.Sprintf("%v%v?%v", FacebookBaseUrl, endpoint, params.Encode()) resp, err := http.Get(fullURL) if log.Error(err) { return fmt.Errorf("ISE") } if resp.StatusCode == 400 { return fmt.Errorf("Facebook unauthorized") } bytes, err := ioutil.ReadAll(resp.Body) if log.Error(err) { return fmt.Errorf("ISE") } err = json.Unmarshal(bytes, &struc) if log.Error(err) { return fmt.Errorf("ISE") } return nil }
func EchoWebsocket(c *gin.Context) { conn, err := websocketUpgrader.Upgrade(c.Writer, c.Request, nil) if log.Error(err) { c.Error(errors.NewISE()) return } for { typ, frame, _ := conn.ReadMessage() conn.WriteMessage(typ, frame) } }
func SetUserEmail(c *gin.Context) { userId := c.Param("user_id") if userId != c.MustGet("request_user_id").(string) { c.Error(errors.NewHttp(http.StatusUnauthorized, "Users can only modify themselves")) return } newUserEmail := c.Param("email") _, user, err := db.GetUserById(userId) if log.Error(err) { c.Error(err) return } user.Email = newUserEmail err = db.UpdateUser(user) if log.Error(err) { c.Error(err) return } c.JSON(http.StatusOK, user) }
func GetNotebookNotes(c *gin.Context) { userId := c.MustGet("request_user_id").(string) notebookId := c.Param("notebook_id") // Confirm notebook exists _, err := db.GetNotebookById(notebookId) if err != nil { c.Error(err) return } // Check query params filterUserId := c.Query("user") filterUnjoined := c.Query("unjoined") // And execute those query params var notes []model.DbNote if filterUserId == "" && filterUnjoined == "" { notes, err = db.GetNotesInNotebook(notebookId) } else if filterUserId == "" { notes, err = db.GetUnjoinedNotesInNotebook(notebookId, userId) } else if filterUnjoined == "" { notes, err = db.GetNotesInNotebookByUser(notebookId, userId) } else { c.Error(errors.NewHttp(http.StatusBadRequest, "Cannot provide both unjoined and user parameters lol")) return } if log.Error(err) { c.Error(errors.NewISE()) return } // Transform the resultant list into hierarchial [topic -> []note] topicHash := make(map[string][]model.FullNoteResponse) for _, dbnote := range notes { if ar, in := topicHash[dbnote.TopicId]; in { topicHash[dbnote.TopicId] = append(ar, model.NewFullNoteResponse(dbnote)) } else { topicHash[dbnote.TopicId] = []model.FullNoteResponse{ model.NewFullNoteResponse(dbnote), } } } topicResponses := []model.TopicResponse{} for topicid, notelist := range topicHash { topicResponses = append(topicResponses, model.TopicResponse{ Id: topicid, Notes: notelist, }) } c.JSON(http.StatusOK, topicResponses) }
func Note(n model.DbNote) { if oldNote, in := NoteIdCache[n.Id]; in { log.Error(db.UpdateNote(*oldNote)) } NoteIdCache[n.Id] = &n if _, in := NoteTopicCache[n.TopicId]; in { NoteTopicCache[n.TopicId][n.Id] = &n } else { NoteTopicCache[n.TopicId] = make(map[string]*model.DbNote) NoteTopicCache[n.TopicId][n.Id] = &n } }
// Init creates a connection to the database func Init() { log.Info("Establishing a connection to the database") db, err := sql.Open("postgres", config.PostgresURL()) if log.Error(err) { os.Exit(1) } err = db.Ping() if log.Error(err) { os.Exit(1) } dbmap = &gorp.DbMap{Db: db, Dialect: gorp.PostgresDialect{}} dbmap.AddTableWithName(model.DbSchool{}, "schools").SetKeys(false, "Id") dbmap.AddTableWithName(model.DbCourse{}, "courses").SetKeys(false, "Id") dbmap.AddTableWithName(model.DbCourseSection{}, "sections").SetKeys(false, "Id") dbmap.AddTableWithName(model.DbUser{}, "users").SetKeys(false, "Id") dbmap.AddTableWithName(model.DbSchoolRequest{}, "school_requests").SetKeys(false, "Id") dbmap.AddTableWithName(model.DbNotebook{}, "notebooks").SetKeys(false, "Id") dbmap.AddTableWithName(model.DbTopic{}, "topics").SetKeys(false, "Id") dbmap.AddTableWithName(model.DbNote{}, "notes").SetKeys(false, "Id") dbmap.AddTableWithName(model.DbSubscription{}, "subscriptions").SetKeys(false, "UserId", "NotebookId") }
// model passed in is assumed to be a list // because of this, a boolean is not returned; you can just check the length of the list func GenericGet(model interface{}, sqls string, args ...interface{}) error { _, err := dbmap.Select(model, sqls, args...) if err != nil { switch err { case sql.ErrNoRows: return nil default: log.Error(err) return err } } return nil }
func GenericGetOne(model interface{}, sqls string, args ...interface{}) (bool, error) { err := dbmap.SelectOne(model, sqls, args...) if err != nil { switch err { case sql.ErrNoRows: return false, nil default: log.Error(err) return true, err } } return true, nil }
func GetSingleSchool(c *gin.Context) { schoolId := c.Param("school_id") in, school, err := db.GetSchool(schoolId) if log.Error(err) { c.Error(errors.NewISE()) return } if !in { c.Error(errors.NewHttp(http.StatusNotFound, "School requested could not be found")) return } c.JSON(http.StatusOK, school) }
func GetCoursesForSchool(c *gin.Context) { schoolId := c.Param("school_id") courses, err := db.GetCoursesForSchool(schoolId) if log.Error(err) { c.Error(errors.NewISE()) return } courseResponses := make([]model.CourseResponse, 0) for _, course := range courses { courseResponses = append(courseResponses, model.CourseResponseWithoutSchool(course)) } c.JSON(http.StatusOK, courseResponses) }
func GetSectionsForCourse(c *gin.Context) { courseId := c.Param("course_id") sections, err := db.GetSectionsForCourse(courseId) if log.Error(err) { c.Error(errors.NewISE()) return } sectionsResponse := make([]model.SectionResponse, 0) for _, section := range sections { sectionsResponse = append(sectionsResponse, model.SectionResponseWithoutCourse(section)) } c.JSON(http.StatusOK, sectionsResponse) }
func GetUser(c *gin.Context) { userId := c.Param("user_id") if userId != c.MustGet("request_user_id").(string) { c.Error(errors.NewHttp(http.StatusUnauthorized, "Users can only view detailed information about themselves")) return } _, user, err := db.GetUserById(userId) if log.Error(err) { c.Error(errors.NewISE()) return } c.JSON(http.StatusOK, model.NewUserResponse(user)) }
func WrapWebsocket(conn *websocket.Conn, bundle *model.WsContext) { // Read from WS, write to channel go func() { for { _, frameb, err := conn.ReadMessage() if log.Error(err) { bundle.Close <- true return } log.Info("Received: %v", string(frameb)) frame := make(map[string]interface{}) err = json.Unmarshal(frameb, &frame) if log.Error(err) { continue } bundle.Incoming <- frame } }() // Read from channel, write to WS go func() { for { select { case msg := <-bundle.Outgoing: b, err := json.Marshal(msg) if log.Error(err) { continue } log.Info("Sending: %v", string(b)) err = conn.WriteMessage(1, b) if log.Error(err) { continue } case <-bundle.Close: return } } }() }
func SetUserUsername(c *gin.Context) { userId := c.Param("user_id") if userId != c.MustGet("request_user_id").(string) { c.Error(errors.NewHttp(http.StatusUnauthorized, "Users can only modify themselves")) return } newUserName := c.Param("username") _, user, err := db.GetUserById(userId) if log.Error(err) { c.Error(err) return } user.Username = sql.NullString{ String: newUserName, Valid: true, } err = db.UpdateUser(user) if log.Error(err) { c.Error(err) return } c.JSON(http.StatusOK, user) }
func ModifyUserSubscription(c *gin.Context) { userId := c.Param("user_id") if userId != c.MustGet("request_user_id").(string) { c.Error(errors.NewHttp(http.StatusUnauthorized, "Users can only modify subscriptions for themselves")) return } var request model.SubscriptionRequest err := c.BindJSON(&request) if log.Error(err) { c.Error(err) return } sub := model.DbSubscription{ UserId: userId, NotebookId: request.NotebookId, Name: sql.NullString{ String: request.Name, Valid: true, }, } err = db.UpdateSubscription(sub) if log.Error(err) { c.Error(errors.NewISE()) return } section, err := db.GetSectionByNotebookId(sub.NotebookId) if log.Error(err) { c.Error(errors.NewISE()) return } course, err := db.GetCourseByCourseId(section.CourseId) if log.Error(err) { c.Error(errors.NewISE()) return } c.JSON(http.StatusOK, model.NewSubscriptionResponse(sub, course, section)) }
func Login(c *gin.Context) { var returnCode int var request model.LoginRequest // Parse the user request err := c.BindJSON(&request) if log.Error(err) { c.Error(err) return } // Right now we assume that the user is logging in with Facebook fbUser, err := service.Facebook{}.GetCurrentUser(request.AccessToken) if log.Error(err) { c.Error(errors.NewHttp(errors.ISE, "Error contacting facebook api")) return } // Then get the user's profile picture fbPicture, err := service.Facebook{}.GetProfilePic(request.AccessToken) if log.Error(err) { c.Error(errors.NewHttp(errors.ISE, "Error contacting facebook api")) return } // See if the user is already a notion user in, dbUser, err := db.GetUserByFacebookId(fbUser.Id) if log.Error(err) { c.Error(errors.NewISE()) return } // If they are in the database, we just update their auth token if in { returnCode = http.StatusAccepted dbUser.FbAuthToken = request.AccessToken dbUser.FbProfilePic = fbPicture.Data.Url err = db.UpdateUser(dbUser) } else { returnCode = http.StatusCreated dbUser = model.DbUser{ Id: util.NewId(), Name: fbUser.Name, Email: fbUser.Email, Verified: false, AuthMethod: request.AuthMethod, FbUserId: fbUser.Id, FbAuthToken: request.AccessToken, FbProfilePic: fbPicture.Data.Url, } err = db.CreateUser(dbUser) } // Error check 'er yo if log.Error(err) { c.Error(errors.NewISE()) return } // Throw back the user object at the requester c.JSON(returnCode, model.NewUserResponse(dbUser)) }