2024-06-14 12:48:23 +00:00
package postgres
import (
"context"
2024-06-25 19:55:43 +00:00
"errors"
2024-07-01 11:42:53 +00:00
"time"
2024-06-26 07:10:04 +00:00
2024-07-02 08:11:42 +00:00
otterError "git.dragse.it/anthrove/otter-space-sdk/v2/pkg/error"
"git.dragse.it/anthrove/otter-space-sdk/v2/pkg/models"
2024-06-28 08:43:55 +00:00
gonanoid "github.com/matoous/go-nanoid/v2"
2024-06-14 12:48:23 +00:00
log "github.com/sirupsen/logrus"
"gorm.io/gorm"
)
2024-07-01 09:36:21 +00:00
// Workaround, should be changed later maybe, but its not that bad right now
type selectFrequencyTag struct {
tagName string ` gorm:"tag_name" `
count int64 ` gorm:"count" `
tagType models . TagType ` gorm:"tag_type" `
}
2024-06-23 20:35:46 +00:00
func CreateUser ( ctx context . Context , db * gorm . DB , anthroveUserID models . AnthroveUserID ) error {
2024-06-19 21:32:42 +00:00
2024-06-20 13:24:55 +00:00
if anthroveUserID == "" {
2024-06-26 08:02:54 +00:00
return & otterError . EntityValidationFailed { Reason : otterError . AnthroveUserIDIsEmpty }
2024-06-25 19:55:43 +00:00
}
if len ( anthroveUserID ) != 25 {
2024-06-26 08:02:54 +00:00
return & otterError . EntityValidationFailed { Reason : otterError . AnthroveUserIDToShort }
2024-06-20 13:24:55 +00:00
}
2024-06-22 20:06:36 +00:00
user := models . User {
2024-06-25 07:09:18 +00:00
BaseModel : models . BaseModel [ models . AnthroveUserID ] {
ID : anthroveUserID ,
2024-06-19 21:32:42 +00:00
} ,
}
2024-06-25 19:55:43 +00:00
result := db . WithContext ( ctx ) . FirstOrCreate ( & user )
if result . Error != nil {
2024-06-26 09:31:42 +00:00
2024-06-25 19:55:43 +00:00
if errors . Is ( result . Error , gorm . ErrDuplicatedKey ) {
2024-06-26 08:02:54 +00:00
return & otterError . EntityAlreadyExists { }
2024-06-25 19:55:43 +00:00
}
return result . Error
}
2024-06-19 21:32:42 +00:00
return nil
}
2024-06-23 20:35:46 +00:00
func CreateUserWithRelationToSource ( ctx context . Context , db * gorm . DB , anthroveUserID models . AnthroveUserID , sourceID models . AnthroveSourceID , accountId string , accountUsername string ) error {
2024-06-20 13:24:55 +00:00
2024-06-23 20:35:46 +00:00
if anthroveUserID == "" {
2024-06-26 08:02:54 +00:00
return & otterError . EntityValidationFailed { Reason : otterError . AnthroveUserIDIsEmpty }
2024-06-25 19:55:43 +00:00
}
if len ( anthroveUserID ) != 25 {
2024-06-26 08:02:54 +00:00
return & otterError . EntityValidationFailed { Reason : otterError . AnthroveUserIDToShort }
2024-06-20 13:24:55 +00:00
}
2024-06-23 20:35:46 +00:00
if accountId == "" {
2024-06-26 08:02:54 +00:00
return & otterError . EntityValidationFailed { Reason : "accountID cannot be empty" }
2024-06-23 20:35:46 +00:00
}
if accountUsername == "" {
2024-06-26 08:02:54 +00:00
return & otterError . EntityValidationFailed { Reason : "accountUsername cannot be empty" }
2024-06-23 20:35:46 +00:00
}
2024-06-28 08:43:55 +00:00
validationCode , err := gonanoid . New ( 25 )
if err != nil {
return err
}
2024-06-26 14:12:10 +00:00
result := db . WithContext ( ctx ) . Exec ( ` WITH userObj AS (
INSERT INTO "User" ( id )
VALUES ( $ 1 )
ON CONFLICT ( id ) DO NOTHING
)
2024-06-28 08:43:55 +00:00
INSERT INTO "UserSource" ( user_id , source_id , account_username , account_id , account_validate , account_validation_key )
SELECT $ 2 , source . id , $ 3 , $ 4 , false , $ 5
2024-06-26 14:12:10 +00:00
FROM "Source" AS source
2024-06-28 08:43:55 +00:00
WHERE source . id = $ 6 ; ` , anthroveUserID , anthroveUserID , accountUsername , accountId , validationCode , sourceID )
2024-06-14 12:48:23 +00:00
2024-06-25 19:55:43 +00:00
if result . Error != nil {
2024-06-26 14:12:10 +00:00
if errors . Is ( result . Error , gorm . ErrDuplicatedKey ) {
return & otterError . EntityAlreadyExists { }
2024-06-25 19:55:43 +00:00
}
return result . Error
2024-06-14 12:48:23 +00:00
}
2024-06-27 19:37:29 +00:00
if result . RowsAffected == 0 {
return & otterError . NoDataWritten { }
}
2024-06-14 12:48:23 +00:00
log . WithFields ( log . Fields {
"anthrove_user_id" : anthroveUserID ,
2024-06-23 20:35:46 +00:00
"source_id" : sourceID ,
"account_username" : accountUsername ,
"account_id" : accountId ,
2024-06-26 14:12:10 +00:00
} ) . Info ( "database: created user-source relationship" )
2024-06-14 12:48:23 +00:00
return nil
}
2024-06-14 12:50:29 +00:00
func GetUserFavoritesCount ( ctx context . Context , db * gorm . DB , anthroveUserID models . AnthroveUserID ) ( int64 , error ) {
2024-06-25 19:55:43 +00:00
var count int64
2024-06-20 20:45:03 +00:00
if anthroveUserID == "" {
2024-06-26 08:02:54 +00:00
return 0 , & otterError . EntityValidationFailed { Reason : otterError . AnthroveUserIDIsEmpty }
2024-06-20 20:45:03 +00:00
}
2024-06-25 19:55:43 +00:00
if len ( anthroveUserID ) != 25 {
2024-06-26 08:02:54 +00:00
return 0 , & otterError . EntityValidationFailed { Reason : otterError . AnthroveUserIDToShort }
2024-06-25 19:55:43 +00:00
}
result := db . WithContext ( ctx ) . Model ( & models . UserFavorites { } ) . Where ( "user_id = ?" , string ( anthroveUserID ) ) . Count ( & count )
if result . Error != nil {
if errors . Is ( result . Error , gorm . ErrRecordNotFound ) {
2024-06-26 08:02:54 +00:00
return 0 , & otterError . NoDataFound { }
2024-06-25 19:55:43 +00:00
}
return 0 , result . Error
2024-06-14 12:50:29 +00:00
}
log . WithFields ( log . Fields {
"anthrove_user_id" : anthroveUserID ,
"anthrove_user_fav_count" : count ,
} ) . Trace ( "database: got user favorite count" )
return count , nil
}
2024-06-14 13:03:34 +00:00
2024-06-22 21:23:23 +00:00
func GetUserSourceLinks ( ctx context . Context , db * gorm . DB , anthroveUserID models . AnthroveUserID ) ( map [ string ] models . UserSource , error ) {
2024-06-22 20:06:36 +00:00
var userSources [ ] models . UserSource
2024-06-22 21:23:23 +00:00
userSourceMap := make ( map [ string ] models . UserSource )
2024-06-14 13:03:34 +00:00
2024-06-25 19:55:43 +00:00
if anthroveUserID == "" {
2024-06-26 08:02:54 +00:00
return nil , & otterError . EntityValidationFailed { Reason : otterError . AnthroveUserIDIsEmpty }
2024-06-25 19:55:43 +00:00
}
if len ( anthroveUserID ) != 25 {
2024-06-26 08:02:54 +00:00
return nil , & otterError . EntityValidationFailed { Reason : otterError . AnthroveUserIDToShort }
2024-06-25 19:55:43 +00:00
}
result := db . WithContext ( ctx ) . Model ( & models . UserSource { } ) . Where ( "user_id = ?" , string ( anthroveUserID ) ) . Find ( & userSources )
if result . Error != nil {
if errors . Is ( result . Error , gorm . ErrRecordNotFound ) {
2024-06-26 08:02:54 +00:00
return nil , & otterError . NoDataFound { }
2024-06-25 19:55:43 +00:00
}
return nil , result . Error
2024-06-14 13:03:34 +00:00
}
for _ , userSource := range userSources {
2024-06-22 20:06:36 +00:00
var source models . Source
2024-06-25 19:55:43 +00:00
result = db . WithContext ( ctx ) . Model ( & models . Source { } ) . Where ( "id = ?" , userSource . SourceID ) . First ( & source )
if result . Error != nil {
if errors . Is ( result . Error , gorm . ErrRecordNotFound ) {
2024-06-26 08:02:54 +00:00
return nil , & otterError . NoDataFound { }
2024-06-25 19:55:43 +00:00
}
return nil , result . Error
2024-06-14 13:03:34 +00:00
}
2024-06-22 21:23:23 +00:00
userSourceMap [ source . DisplayName ] = models . UserSource {
UserID : userSource . AccountID ,
AccountUsername : userSource . AccountUsername ,
Source : models . Source {
2024-06-14 13:03:34 +00:00
DisplayName : source . DisplayName ,
Domain : source . Domain ,
Icon : source . Icon ,
} ,
}
}
log . WithFields ( log . Fields {
"anthrove_user_id" : anthroveUserID ,
} ) . Trace ( "database: got user source link" )
return userSourceMap , nil
}
2024-06-14 13:04:45 +00:00
2024-06-28 10:15:51 +00:00
func GetUserSourceBySourceID ( ctx context . Context , db * gorm . DB , anthroveUserID models . AnthroveUserID , sourceID models . AnthroveSourceID ) ( * models . UserSource , error ) {
2024-06-28 12:16:28 +00:00
var userSource models . UserSource
2024-06-25 19:55:43 +00:00
2024-06-23 19:23:38 +00:00
if anthroveUserID == "" {
2024-06-26 08:02:54 +00:00
return nil , & otterError . EntityValidationFailed { Reason : otterError . AnthroveUserIDIsEmpty }
2024-06-25 19:55:43 +00:00
}
if len ( anthroveUserID ) != 25 {
2024-06-26 08:02:54 +00:00
return nil , & otterError . EntityValidationFailed { Reason : otterError . AnthroveUserIDToShort }
2024-06-23 19:23:38 +00:00
}
if sourceID == "" {
2024-06-26 08:02:54 +00:00
return nil , & otterError . EntityValidationFailed { Reason : "sourceID cannot be empty" }
2024-06-20 20:45:03 +00:00
}
2024-06-25 19:55:43 +00:00
if len ( sourceID ) != 25 {
2024-06-26 08:02:54 +00:00
return nil , & otterError . EntityValidationFailed { Reason : "sourceID needs to be 25 characters long" }
2024-06-25 19:55:43 +00:00
}
2024-06-14 13:04:45 +00:00
2024-06-28 12:16:28 +00:00
result := db . WithContext ( ctx ) . Model ( & models . UserSource { } ) . InnerJoins ( "Source" , db . Where ( "id = ?" , sourceID ) ) . Where ( "user_id = ?" , string ( anthroveUserID ) ) . First ( & userSource )
2024-06-25 19:55:43 +00:00
if result . Error != nil {
if errors . Is ( result . Error , gorm . ErrRecordNotFound ) {
2024-06-26 08:02:54 +00:00
return nil , & otterError . NoDataFound { }
2024-06-25 19:55:43 +00:00
}
return nil , result . Error
2024-06-14 13:04:45 +00:00
}
log . WithFields ( log . Fields {
2024-06-23 19:23:38 +00:00
"anthrove_user_id" : anthroveUserID ,
"source_id" : sourceID ,
2024-06-14 13:04:45 +00:00
} ) . Trace ( "database: got specified user source link" )
2024-06-28 12:16:28 +00:00
return & userSource , nil
2024-06-14 13:04:45 +00:00
}
2024-06-14 13:07:23 +00:00
2024-06-28 10:15:51 +00:00
func GetAllUsers ( ctx context . Context , db * gorm . DB ) ( [ ] models . User , error ) {
2024-06-22 20:06:36 +00:00
var users [ ] models . User
2024-06-14 13:09:11 +00:00
2024-06-25 19:55:43 +00:00
result := db . WithContext ( ctx ) . Model ( & models . User { } ) . Find ( & users )
if result . Error != nil {
if errors . Is ( result . Error , gorm . ErrRecordNotFound ) {
2024-06-26 08:02:54 +00:00
return nil , & otterError . NoDataFound { }
2024-06-25 19:55:43 +00:00
}
return nil , result . Error
2024-06-14 13:09:11 +00:00
}
log . WithFields ( log . Fields {
2024-06-28 10:15:51 +00:00
"anthrove_user_id_count" : len ( users ) ,
2024-06-14 13:09:11 +00:00
} ) . Trace ( "database: got all anthrove user IDs" )
2024-06-28 10:15:51 +00:00
return users , nil
2024-06-14 13:09:11 +00:00
}
2024-06-14 13:11:13 +00:00
2024-07-15 14:06:19 +00:00
// TODO: FIX THE TEST
2024-06-23 20:35:46 +00:00
func GetUserFavoriteWithPagination ( ctx context . Context , db * gorm . DB , anthroveUserID models . AnthroveUserID , skip int , limit int ) ( * models . FavoriteList , error ) {
2024-06-22 21:23:23 +00:00
var favoritePosts [ ] models . Post
2024-06-14 13:11:13 +00:00
2024-06-25 19:55:43 +00:00
if anthroveUserID == "" {
2024-06-26 08:02:54 +00:00
return nil , & otterError . EntityValidationFailed { Reason : otterError . AnthroveUserIDIsEmpty }
2024-06-25 19:55:43 +00:00
}
if len ( anthroveUserID ) != 25 {
2024-06-26 08:02:54 +00:00
return nil , & otterError . EntityValidationFailed { Reason : otterError . AnthroveUserIDToShort }
2024-06-25 19:55:43 +00:00
}
2024-07-15 14:06:19 +00:00
db . WithContext ( ctx ) . Joins ( "RIGHT JOIN \"UserFavorites\" AS of ON \"Post\".id = of.post_id AND of.user_id = ?" , anthroveUserID ) . Preload ( "References" ) . Offset ( skip ) . Limit ( limit ) . Find ( & favoritePosts )
2024-06-14 13:11:13 +00:00
log . WithFields ( log . Fields {
"anthrove_user_id" : anthroveUserID ,
"anthrove_user_fav_count" : len ( favoritePosts ) ,
} ) . Trace ( "database: got all anthrove user favorites" )
2024-06-22 21:23:23 +00:00
return & models . FavoriteList { Posts : favoritePosts } , nil
2024-06-14 13:11:13 +00:00
}
2024-06-14 13:16:31 +00:00
2024-06-23 19:23:38 +00:00
func GetUserTagWitRelationToFavedPosts ( ctx context . Context , db * gorm . DB , anthroveUserID models . AnthroveUserID ) ( [ ] models . TagsWithFrequency , error ) {
2024-06-27 14:11:16 +00:00
var queryUserFavorites [ ] selectFrequencyTag
2024-06-25 19:55:43 +00:00
if anthroveUserID == "" {
2024-06-26 08:02:54 +00:00
return nil , & otterError . EntityValidationFailed { Reason : otterError . AnthroveUserIDIsEmpty }
2024-06-25 19:55:43 +00:00
}
if len ( anthroveUserID ) != 25 {
2024-06-26 08:02:54 +00:00
return nil , & otterError . EntityValidationFailed { Reason : otterError . AnthroveUserIDToShort }
2024-06-25 19:55:43 +00:00
}
2024-06-27 19:37:29 +00:00
rows , err := db . WithContext ( ctx ) . Raw (
2024-06-27 14:11:16 +00:00
` WITH user_posts AS (
2024-06-27 19:37:29 +00:00
SELECT post_id FROM "UserFavorites" WHERE user_id = $ 1
)
SELECT post_tags . tag_name AS tag_name , count ( * ) AS count , ( SELECT tag_type FROM "Tag" WHERE "Tag" . name = post_tags . tag_name LIMIT 1 ) AS tag_type FROM post_tags , user_posts WHERE post_tags . post_id IN ( user_posts . post_id ) GROUP BY post_tags . tag_name ORDER BY tag_type DESC , tag_name DESC ` , anthroveUserID ) . Rows ( )
if err != nil {
if errors . Is ( err , gorm . ErrRecordNotFound ) {
2024-06-26 08:02:54 +00:00
return nil , & otterError . NoDataFound { }
2024-06-25 19:55:43 +00:00
}
2024-06-27 19:37:29 +00:00
return nil , err
2024-06-14 13:16:31 +00:00
}
2024-06-27 19:37:29 +00:00
var userFavoritesFrequency = make ( [ ] models . TagsWithFrequency , 0 )
defer rows . Close ( )
for rows . Next ( ) {
var tagName string
var count int64
var tagType string
rows . Scan ( & tagName , & count , & tagType )
userFavoritesFrequency = append ( userFavoritesFrequency , models . TagsWithFrequency {
Frequency : count ,
Tags : models . Tag {
Name : tagName ,
Type : models . TagType ( tagType ) ,
} ,
} )
2024-06-14 13:16:31 +00:00
}
log . WithFields ( log . Fields {
"anthrove_user_id" : anthroveUserID ,
2024-06-27 14:11:16 +00:00
"tag_amount" : len ( queryUserFavorites ) ,
2024-06-14 13:16:31 +00:00
} ) . Trace ( "database: got user tag node with relation to faved posts" )
2024-06-27 14:11:16 +00:00
return userFavoritesFrequency , nil
2024-06-14 13:16:31 +00:00
}
2024-07-01 11:42:53 +00:00
func UpdateUserSourceScrapeTimeInterval ( ctx context . Context , db * gorm . DB , anthroveUserID models . AnthroveUserID , sourceID models . AnthroveSourceID , scrapeTime models . AnthroveScrapeTimeInterval ) error {
if anthroveUserID == "" {
return & otterError . EntityValidationFailed { Reason : otterError . AnthroveUserIDIsEmpty }
}
if len ( anthroveUserID ) != 25 {
return & otterError . EntityValidationFailed { Reason : otterError . AnthroveUserIDToShort }
}
if sourceID == "" {
return & otterError . EntityValidationFailed { Reason : otterError . AnthroveSourceIDEmpty }
}
if len ( sourceID ) != 25 {
return & otterError . EntityValidationFailed { Reason : otterError . AnthroveSourceIDToShort }
}
if scrapeTime == 0 {
return & otterError . EntityValidationFailed { Reason : "ScrapeTimeInterval cannot be empty" }
}
userSource := & models . UserSource {
UserID : string ( anthroveUserID ) ,
}
result := db . WithContext ( ctx ) . Model ( & userSource ) . Update ( "scrape_time_interval" , scrapeTime )
if result . Error != nil {
return result . Error
}
return nil
}
func UpdateUserSourceLastScrapeTime ( ctx context . Context , db * gorm . DB , anthroveUserID models . AnthroveUserID , sourceID models . AnthroveSourceID , lastScrapeTime models . AnthroveUserLastScrapeTime ) error {
if anthroveUserID == "" {
return & otterError . EntityValidationFailed { Reason : otterError . AnthroveUserIDIsEmpty }
}
if len ( anthroveUserID ) != 25 {
return & otterError . EntityValidationFailed { Reason : otterError . AnthroveUserIDToShort }
}
if sourceID == "" {
return & otterError . EntityValidationFailed { Reason : otterError . AnthroveSourceIDEmpty }
}
if len ( sourceID ) != 25 {
return & otterError . EntityValidationFailed { Reason : otterError . AnthroveSourceIDToShort }
}
if time . Time . IsZero ( time . Time ( lastScrapeTime ) ) {
return & otterError . EntityValidationFailed { Reason : "LastScrapeTime cannot be empty" }
}
userSource := & models . UserSource {
UserID : string ( anthroveUserID ) ,
}
result := db . WithContext ( ctx ) . Model ( & userSource ) . Update ( "last_scrape_time" , time . Time ( lastScrapeTime ) )
if result . Error != nil {
return result . Error
}
return nil
}
func UpdateUserSourceValidation ( ctx context . Context , db * gorm . DB , anthroveUserID models . AnthroveUserID , sourceID models . AnthroveSourceID , valid bool ) error {
if anthroveUserID == "" {
return & otterError . EntityValidationFailed { Reason : otterError . AnthroveUserIDIsEmpty }
}
if len ( anthroveUserID ) != 25 {
return & otterError . EntityValidationFailed { Reason : otterError . AnthroveUserIDToShort }
}
if sourceID == "" {
return & otterError . EntityValidationFailed { Reason : otterError . AnthroveSourceIDEmpty }
}
if len ( sourceID ) != 25 {
return & otterError . EntityValidationFailed { Reason : otterError . AnthroveSourceIDToShort }
}
userSource := & models . UserSource {
UserID : string ( anthroveUserID ) ,
}
result := db . WithContext ( ctx ) . Model ( & userSource ) . Update ( "account_validate" , valid )
if result . Error != nil {
return result . Error
}
return nil
}