package api import ( "io" "net/http" "os" "path/filepath" "strconv" "github.com/julienschmidt/httprouter" "github.com/notherealmarco/WASAPhoto/service/api/authorization" "github.com/notherealmarco/WASAPhoto/service/api/helpers" "github.com/notherealmarco/WASAPhoto/service/api/reqcontext" ) func (rt *_router) PostPhoto(w http.ResponseWriter, r *http.Request, ps httprouter.Params, ctx reqcontext.RequestContext) { //defer r.Body.Close() uid := ps.ByName("user_id") // send error if the user has no permission to perform this action if !authorization.SendAuthorizationError(ctx.Auth.UserAuthorized, uid, rt.db, w, rt.baseLogger, http.StatusNotFound) { return } transaction, photo_id, err := rt.db.PostPhoto(uid) if err != nil { helpers.SendInternalError(err, "Database error: PostPhoto", w, rt.baseLogger) return } path := rt.dataPath + "/photos/" + uid + "/" + strconv.FormatInt(photo_id, 10) + ".jpg" // todo: we should check if the body is a valid jpg image if err = os.MkdirAll(filepath.Dir(path), os.ModePerm); err != nil { // perms = 511 helpers.SendInternalError(err, "Error creating directory", w, rt.baseLogger) return } file, err := os.Create(path) if err != nil { helpers.SendInternalError(err, "Error creating file", w, rt.baseLogger) helpers.RollbackOrLogError(transaction, rt.baseLogger) return } if _, err = io.Copy(file, r.Body); err != nil { helpers.SendInternalError(err, "Error writing the file", w, rt.baseLogger) helpers.RollbackOrLogError(transaction, rt.baseLogger) return } if err = file.Close(); err != nil { helpers.SendInternalError(err, "Error closing file", w, rt.baseLogger) helpers.RollbackOrLogError(transaction, rt.baseLogger) } err = transaction.Commit() if err != nil { helpers.SendInternalError(err, "Error committing transaction", w, rt.baseLogger) //todo: should I roll back? return } helpers.SendStatus(http.StatusCreated, w, "Photo uploaded", rt.baseLogger) } func (rt *_router) GetPhoto(w http.ResponseWriter, r *http.Request, ps httprouter.Params, ctx reqcontext.RequestContext) { if !authorization.SendErrorIfNotLoggedIn(ctx.Auth.Authorized, rt.db, w, rt.baseLogger) { // We want the user to be authenticated return } uid := ps.ByName("user_id") photo_id_str := ps.ByName("photo_id") photo_id, err := strconv.ParseInt(photo_id_str, 10, 64) if err != nil { helpers.SendBadRequest(w, "Invalid photo id", rt.baseLogger) return } // This is also checking if the requesting user is banned by the author of the photo exists, err := rt.db.PhotoExists(uid, photo_id, ctx.Auth.GetUserID()) if err != nil { helpers.SendInternalError(err, "Database error: PhotoExists", w, rt.baseLogger) return } if !exists { helpers.SendNotFound(w, "Resource not found", rt.baseLogger) return } path := rt.dataPath + "/photos/" + uid + "/" + photo_id_str + ".jpg" file, err := os.Open(path) if err != nil { helpers.SendNotFound(w, "Photo not found", rt.baseLogger) return } defer file.Close() io.Copy(w, file) } func (rt *_router) DeletePhoto(w http.ResponseWriter, r *http.Request, ps httprouter.Params, ctx reqcontext.RequestContext) { uid := ps.ByName("user_id") photo_id := ps.ByName("photo_id") // photo id to int64 photo_id_int, err := strconv.ParseInt(photo_id, 10, 64) if err != nil { helpers.SendBadRequestError(err, "Bad photo id", w, rt.baseLogger) return } // send error if the user has no permission to perform this action (only the author can delete a photo) if !authorization.SendAuthorizationError(ctx.Auth.UserAuthorized, uid, rt.db, w, rt.baseLogger, http.StatusNotFound) { return } deleted, err := rt.db.DeletePhoto(uid, photo_id_int) if err != nil { helpers.SendInternalError(err, "Error deleting photo from database", w, rt.baseLogger) return } //todo: maybe let's use a transaction also here if !deleted { helpers.SendNotFound(w, "Photo not found", rt.baseLogger) return } path := rt.dataPath + "/photos/" + uid + "/" + photo_id + ".jpg" if err := os.Remove(path); err != nil { helpers.SendInternalError(err, "Error deleting file", w, rt.baseLogger) return } w.WriteHeader(http.StatusNoContent) }