[fix] map concurrency issue, [add] better logging, [add] activity template, [fix] safari redirect issue, [add] timezone framework

This commit is contained in:
2023-09-20 20:35:01 -04:00
parent 240b3a2b67
commit f2163c8fd9
13 changed files with 368 additions and 202 deletions

View File

@@ -83,21 +83,25 @@ func (api *API) authorizeUser(c *gin.Context) {
func (api *API) createUser(c *gin.Context) {
if !api.Config.RegistrationEnabled {
c.AbortWithStatus(http.StatusConflict)
return
}
var rUser requestUser
if err := c.ShouldBindJSON(&rUser); err != nil {
log.Error("[createUser] Invalid JSON Bind")
c.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"error": "Invalid User Data"})
return
}
if rUser.Username == "" || rUser.Password == "" {
log.Error("[createUser] Invalid User - Empty Username or Password")
c.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"error": "Invalid User Data"})
return
}
hashedPassword, err := argon2.CreateHash(rUser.Password, argon2.DefaultParams)
if err != nil {
log.Error("[createUser] Argon2 Hash Failure:", err)
c.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"error": "Unknown Error"})
return
}
@@ -106,20 +110,18 @@ func (api *API) createUser(c *gin.Context) {
ID: rUser.Username,
Pass: hashedPassword,
})
// SQL Error
if err != nil {
log.Error("[createUser] CreateUser DB Error:", err)
c.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"error": "Invalid User Data"})
return
}
// User Exists (ON CONFLICT DO NOTHING)
// User Exists
if rows == 0 {
c.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"error": "User Already Exists"})
return
}
// TODO: Struct -> JSON
c.JSON(http.StatusCreated, gin.H{
"username": rUser.Username,
})
@@ -130,26 +132,25 @@ func (api *API) setProgress(c *gin.Context) {
var rPosition requestPosition
if err := c.ShouldBindJSON(&rPosition); err != nil {
log.Error("[setProgress] Invalid JSON Bind")
c.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"error": "Invalid Progress Data"})
return
}
// Upsert Device
device, err := api.DB.Queries.UpsertDevice(api.DB.Ctx, database.UpsertDeviceParams{
if _, err := api.DB.Queries.UpsertDevice(api.DB.Ctx, database.UpsertDeviceParams{
ID: rPosition.DeviceID,
UserID: rUser.(string),
DeviceName: rPosition.Device,
})
if err != nil {
log.Error("Device Upsert Error:", device, err)
}); err != nil {
log.Error("[setProgress] UpsertDevice DB Error:", err)
}
// Upsert Document
document, err := api.DB.Queries.UpsertDocument(api.DB.Ctx, database.UpsertDocumentParams{
if _, err := api.DB.Queries.UpsertDocument(api.DB.Ctx, database.UpsertDocumentParams{
ID: rPosition.DocumentID,
})
if err != nil {
log.Error("Document Upsert Error:", document, err)
}); err != nil {
log.Error("[setProgress] UpsertDocument DB Error:", err)
}
// Create or Replace Progress
@@ -161,11 +162,11 @@ func (api *API) setProgress(c *gin.Context) {
Progress: rPosition.Progress,
})
if err != nil {
log.Error("[setProgress] UpdateProgress DB Error:", err)
c.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"error": "Invalid Request"})
return
}
// TODO: Struct -> JSON
c.JSON(http.StatusOK, gin.H{
"document": progress.DocumentID,
"timestamp": progress.CreatedAt,
@@ -177,6 +178,7 @@ func (api *API) getProgress(c *gin.Context) {
var rDocID requestDocumentID
if err := c.ShouldBindUri(&rDocID); err != nil {
log.Error("[getProgress] Invalid URI Bind")
c.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"error": "Invalid Request"})
return
}
@@ -187,12 +189,11 @@ func (api *API) getProgress(c *gin.Context) {
})
if err != nil {
log.Error("Invalid Progress:", progress, err)
log.Error("[getProgress] GetProgress DB Error:", err)
c.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"error": "Invalid Document"})
return
}
// TODO: Struct -> JSON
c.JSON(http.StatusOK, gin.H{
"document": progress.DocumentID,
"percentage": progress.Percentage,
@@ -207,6 +208,7 @@ func (api *API) addActivities(c *gin.Context) {
var rActivity requestActivity
if err := c.ShouldBindJSON(&rActivity); err != nil {
log.Error("[addActivity] Invalid JSON Bind")
c.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"error": "Invalid Activity"})
return
}
@@ -214,6 +216,7 @@ func (api *API) addActivities(c *gin.Context) {
// Do Transaction
tx, err := api.DB.DB.Begin()
if err != nil {
log.Error("[addActivities] Transaction Begin DB Error:", err)
c.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"error": "Unknown Error"})
return
}
@@ -231,30 +234,29 @@ func (api *API) addActivities(c *gin.Context) {
// Upsert Documents
for _, doc := range allDocuments {
_, err := qtx.UpsertDocument(api.DB.Ctx, database.UpsertDocumentParams{
if _, err := qtx.UpsertDocument(api.DB.Ctx, database.UpsertDocumentParams{
ID: doc,
})
if err != nil {
}); err != nil {
log.Error("[addActivities] UpsertDocument DB Error:", err)
c.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"error": "Invalid Document"})
return
}
}
// Upsert Device
_, err = qtx.UpsertDevice(api.DB.Ctx, database.UpsertDeviceParams{
if _, err = qtx.UpsertDevice(api.DB.Ctx, database.UpsertDeviceParams{
ID: rActivity.DeviceID,
UserID: rUser.(string),
DeviceName: rActivity.Device,
})
if err != nil {
}); err != nil {
log.Error("[addActivities] UpsertDevice DB Error:", err)
c.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"error": "Invalid Device"})
return
}
// Add All Activity
for _, item := range rActivity.Activity {
_, err := qtx.AddActivity(api.DB.Ctx, database.AddActivityParams{
if _, err := qtx.AddActivity(api.DB.Ctx, database.AddActivityParams{
UserID: rUser.(string),
DocumentID: item.DocumentID,
DeviceID: rActivity.DeviceID,
@@ -262,19 +264,17 @@ func (api *API) addActivities(c *gin.Context) {
Duration: int64(item.Duration),
CurrentPage: int64(item.CurrentPage),
TotalPages: int64(item.TotalPages),
})
if err != nil {
}); err != nil {
log.Error("[addActivities] AddActivity DB Error:", err)
c.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"error": "Invalid Activity"})
return
}
}
// Commit Transaction
tx.Commit()
if err != nil {
c.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"error": "Invalid Document"})
if err := tx.Commit(); err != nil {
log.Error("[addActivities] Transaction Commit DB Error:", err)
c.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"error": "Unknown Error"})
return
}
@@ -288,6 +288,7 @@ func (api *API) checkActivitySync(c *gin.Context) {
var rCheckActivity requestCheckActivitySync
if err := c.ShouldBindJSON(&rCheckActivity); err != nil {
log.Error("[checkActivitySync] Invalid JSON Bind")
c.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"error": "Invalid Request"})
return
}
@@ -300,7 +301,7 @@ func (api *API) checkActivitySync(c *gin.Context) {
if err == sql.ErrNoRows {
lastActivity = time.UnixMilli(0)
} else if err != nil {
log.Error("GetLastActivity Error:", err)
log.Error("[checkActivitySync] GetLastActivity DB Error:", err)
c.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"error": "Unknown Error"})
return
}
@@ -321,7 +322,7 @@ func (api *API) addDocuments(c *gin.Context) {
// Do Transaction
tx, err := api.DB.DB.Begin()
if err != nil {
log.Error("[addDocuments] Unknown Transaction Error")
log.Error("[addDocuments] Transaction Begin DB Error:", err)
c.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"error": "Unknown Error"})
return
}
@@ -342,17 +343,16 @@ func (api *API) addDocuments(c *gin.Context) {
Description: doc.Description,
})
if err != nil {
log.Error("[addDocuments] UpsertDocument Error:", err)
log.Error("[addDocuments] UpsertDocument DB Error:", err)
c.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"error": "Invalid Document"})
return
}
_, err = qtx.UpdateDocumentSync(api.DB.Ctx, database.UpdateDocumentSyncParams{
if _, err = qtx.UpdateDocumentSync(api.DB.Ctx, database.UpdateDocumentSyncParams{
ID: doc.ID,
Synced: true,
})
if err != nil {
log.Error("[addDocuments] UpsertDocumentSync Error:", err)
}); err != nil {
log.Error("[addDocuments] UpdateDocumentSync DB Error:", err)
c.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"error": "Invalid Document"})
return
}
@@ -360,7 +360,11 @@ func (api *API) addDocuments(c *gin.Context) {
}
// Commit Transaction
tx.Commit()
if err := tx.Commit(); err != nil {
log.Error("[addDocuments] Transaction Commit DB Error:", err)
c.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"error": "Unknown Error"})
return
}
c.JSON(http.StatusOK, gin.H{
"changed": len(rNewDocs.Documents),
@@ -372,6 +376,7 @@ func (api *API) checkDocumentsSync(c *gin.Context) {
var rCheckDocs requestCheckDocumentSync
if err := c.ShouldBindJSON(&rCheckDocs); err != nil {
log.Error("[checkDocumentsSync] Invalid JSON Bind")
c.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"error": "Invalid Request"})
return
}
@@ -383,6 +388,7 @@ func (api *API) checkDocumentsSync(c *gin.Context) {
DeviceName: rCheckDocs.Device,
})
if err != nil {
log.Error("[checkDocumentsSync] UpsertDevice DB Error", err)
c.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"error": "Invalid Device"})
return
}
@@ -394,7 +400,7 @@ func (api *API) checkDocumentsSync(c *gin.Context) {
// Get Missing Documents
missingDocs, err = api.DB.Queries.GetMissingDocuments(api.DB.Ctx, rCheckDocs.Have)
if err != nil {
log.Error("GetMissingDocuments Error:", err)
log.Error("[checkDocumentsSync] GetMissingDocuments DB Error", err)
c.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"error": "Invalid Request"})
return
}
@@ -402,7 +408,7 @@ func (api *API) checkDocumentsSync(c *gin.Context) {
// Get Deleted Documents
deletedDocIDs, err = api.DB.Queries.GetDeletedDocuments(api.DB.Ctx, rCheckDocs.Have)
if err != nil {
log.Error("GetDeletedDocuements Error:", err)
log.Error("[checkDocumentsSync] GetDeletedDocuments DB Error", err)
c.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"error": "Invalid Request"})
return
}
@@ -411,14 +417,14 @@ func (api *API) checkDocumentsSync(c *gin.Context) {
// Get Wanted Documents
jsonHaves, err := json.Marshal(rCheckDocs.Have)
if err != nil {
log.Error("JSON Marshal Error:", err)
log.Error("[checkDocumentsSync] JSON Marshal Error", err)
c.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"error": "Invalid Request"})
return
}
wantedDocs, err := api.DB.Queries.GetWantedDocuments(api.DB.Ctx, string(jsonHaves))
if err != nil {
log.Error("GetWantedDocuments Error:", err)
log.Error("[checkDocumentsSync] GetWantedDocuments DB Error", err)
c.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"error": "Invalid Request"})
return
}
@@ -462,12 +468,14 @@ func (api *API) checkDocumentsSync(c *gin.Context) {
func (api *API) uploadDocumentFile(c *gin.Context) {
var rDoc requestDocumentID
if err := c.ShouldBindUri(&rDoc); err != nil {
log.Error("[uploadDocumentFile] Invalid URI Bind")
c.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"error": "Invalid Request"})
return
}
fileData, err := c.FormFile("file")
if err != nil {
log.Error("[uploadDocumentFile] File Error:", err)
c.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"error": "File Error"})
return
}
@@ -478,6 +486,7 @@ func (api *API) uploadDocumentFile(c *gin.Context) {
fileExtension := fileMime.Extension()
if !slices.Contains(allowedExtensions, fileExtension) {
log.Error("[uploadDocumentFile] Invalid FileType:", fileExtension)
c.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"error": "Invalid Filetype"})
return
}
@@ -485,6 +494,7 @@ func (api *API) uploadDocumentFile(c *gin.Context) {
// Validate Document Exists in DB
document, err := api.DB.Queries.GetDocument(api.DB.Ctx, rDoc.DocumentID)
if err != nil {
log.Error("[uploadDocumentFile] GetDocument DB Error:", err)
c.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"error": "Unknown Document"})
return
}
@@ -517,6 +527,7 @@ func (api *API) uploadDocumentFile(c *gin.Context) {
if os.IsNotExist(err) {
err = c.SaveUploadedFile(fileData, safePath)
if err != nil {
log.Error("[uploadDocumentFile] Save Failure:", err)
c.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"error": "File Error"})
return
}
@@ -525,27 +536,28 @@ func (api *API) uploadDocumentFile(c *gin.Context) {
// Get MD5 Hash
fileHash, err := getFileMD5(safePath)
if err != nil {
log.Error("[uploadDocumentFile] Hash Failure:", err)
c.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"error": "File Error"})
return
}
// Upsert Document
_, err = api.DB.Queries.UpsertDocument(api.DB.Ctx, database.UpsertDocumentParams{
if _, err = api.DB.Queries.UpsertDocument(api.DB.Ctx, database.UpsertDocumentParams{
ID: document.ID,
Md5: fileHash,
Filepath: &fileName,
})
if err != nil {
}); err != nil {
log.Error("[uploadDocumentFile] UpsertDocument DB Error:", err)
c.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"error": "Document Error"})
return
}
// Update Document Sync Attribute
_, err = api.DB.Queries.UpdateDocumentSync(api.DB.Ctx, database.UpdateDocumentSyncParams{
if _, err = api.DB.Queries.UpdateDocumentSync(api.DB.Ctx, database.UpdateDocumentSyncParams{
ID: document.ID,
Synced: true,
})
if err != nil {
}); err != nil {
log.Error("[uploadDocumentFile] UpdateDocumentSync DB Error:", err)
c.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"error": "Invalid Document"})
return
}
@@ -558,6 +570,7 @@ func (api *API) uploadDocumentFile(c *gin.Context) {
func (api *API) downloadDocumentFile(c *gin.Context) {
var rDoc requestDocumentID
if err := c.ShouldBindUri(&rDoc); err != nil {
log.Error("[downloadDocumentFile] Invalid URI Bind")
c.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"error": "Invalid Request"})
return
}
@@ -565,11 +578,13 @@ func (api *API) downloadDocumentFile(c *gin.Context) {
// Get Document
document, err := api.DB.Queries.GetDocument(api.DB.Ctx, rDoc.DocumentID)
if err != nil {
log.Error("[uploadDocumentFile] GetDocument DB Error:", err)
c.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"error": "Unknown Document"})
return
}
if document.Filepath == nil {
log.Error("[uploadDocumentFile] Document Doesn't Have File:", rDoc.DocumentID)
c.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"error": "Document Doesn't Exist"})
return
}
@@ -580,6 +595,7 @@ func (api *API) downloadDocumentFile(c *gin.Context) {
// Validate File Exists
_, err = os.Stat(filePath)
if os.IsNotExist(err) {
log.Error("[uploadDocumentFile] File Doesn't Exist:", rDoc.DocumentID)
c.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"error": "Document Doesn't Exists"})
return
}