diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml new file mode 100644 index 000000000..9006009d3 --- /dev/null +++ b/.github/workflows/codeql-analysis.yml @@ -0,0 +1,72 @@ +# For most projects, this workflow file will not need changing; you simply need +# to commit it to your repository. +# +# You may wish to alter this file to override the set of languages analyzed, +# or to provide custom queries or build logic. +# +# ******** NOTE ******** +# We have attempted to detect the languages in your repository. Please check +# the `language` matrix defined below to confirm you have the correct set of +# supported CodeQL languages. +# +name: "CodeQL" + +on: + push: + branches: [ "develop", master ] + pull_request: + # The branches below must be a subset of the branches above + branches: [ "develop" ] + schedule: + - cron: '33 22 * * 2' + +jobs: + analyze: + name: Analyze + runs-on: ubuntu-latest + permissions: + actions: read + contents: read + security-events: write + + strategy: + fail-fast: false + matrix: + language: [ 'go', 'javascript' ] + # CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python', 'ruby' ] + # Learn more about CodeQL language support at https://aka.ms/codeql-docs/language-support + + steps: + - name: Checkout repository + uses: actions/checkout@v3 + + # Initializes the CodeQL tools for scanning. + - name: Initialize CodeQL + uses: github/codeql-action/init@v2 + with: + languages: ${{ matrix.language }} + # If you wish to specify custom queries, you can do so here or in a config file. + # By default, queries listed here will override any specified in a config file. + # Prefix the list here with "+" to use these queries and those in the config file. + + # Details on CodeQL's query packs refer to : https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-code-scanning#using-queries-in-ql-packs + # queries: security-extended,security-and-quality + + + # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). + # If this step fails, then you should remove it and run the build manually (see below) + - name: Autobuild + uses: github/codeql-action/autobuild@v2 + + # ℹ️ Command-line programs to run using the OS shell. + # 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun + + # If the Autobuild fails above, remove it and uncomment the following three lines. + # modify them (or add more) to build your code if your project, please refer to the EXAMPLE below for guidance. + + # - run: | + # echo "Run, Build Application using script" + # ./location_of_script_within_repo/buildscript.sh + + - name: Perform CodeQL Analysis + uses: github/codeql-action/analyze@v2 diff --git a/api/graph/generated/generated.go b/api/graph/generated/generated.go index 9f4973a86..a123c87af 100644 --- a/api/graph/generated/generated.go +++ b/api/graph/generated/generated.go @@ -46,6 +46,7 @@ type ResolverRoot interface { Post() PostResolver Query() QueryResolver Rating() RatingResolver + Sitemap() SitemapResolver Sitemaps() SitemapsResolver Space() SpaceResolver Tag() TagResolver @@ -281,9 +282,11 @@ type ComplexityRoot struct { } Sitemap struct { - CreatedAt func(childComplexity int) int - ID func(childComplexity int) int - Slug func(childComplexity int) int + CreatedAt func(childComplexity int) int + ID func(childComplexity int) int + PublishedDate func(childComplexity int) int + Slug func(childComplexity int) int + UpdatedAt func(childComplexity int) int } Sitemaps struct { @@ -483,6 +486,9 @@ type RatingResolver interface { SpaceID(ctx context.Context, obj *models.Rating) (int, error) } +type SitemapResolver interface { + PublishedDate(ctx context.Context, obj *models.Sitemap) (*time.Time, error) +} type SitemapsResolver interface { Categories(ctx context.Context, obj *models.Sitemaps) ([]*models.Sitemap, error) Tags(ctx context.Context, obj *models.Sitemaps) ([]*models.Sitemap, error) @@ -1847,6 +1853,13 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in return e.complexity.Sitemap.ID(childComplexity), true + case "Sitemap.published_date": + if e.complexity.Sitemap.PublishedDate == nil { + break + } + + return e.complexity.Sitemap.PublishedDate(childComplexity), true + case "Sitemap.slug": if e.complexity.Sitemap.Slug == nil { break @@ -1854,6 +1867,13 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in return e.complexity.Sitemap.Slug(childComplexity), true + case "Sitemap.updated_at": + if e.complexity.Sitemap.UpdatedAt == nil { + break + } + + return e.complexity.Sitemap.UpdatedAt(childComplexity), true + case "Sitemaps.categories": if e.complexity.Sitemaps.Categories == nil { break @@ -2590,6 +2610,8 @@ type Sitemap { slug: String! id: ID! created_at: Time + published_date: Time + updated_at: Time } type Sitemaps { @@ -12461,6 +12483,88 @@ func (ec *executionContext) fieldContext_Sitemap_created_at(ctx context.Context, return fc, nil } +func (ec *executionContext) _Sitemap_published_date(ctx context.Context, field graphql.CollectedField, obj *models.Sitemap) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_Sitemap_published_date(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return ec.resolvers.Sitemap().PublishedDate(rctx, obj) + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.(*time.Time) + fc.Result = res + return ec.marshalOTime2ᚖtimeᚐTime(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_Sitemap_published_date(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "Sitemap", + Field: field, + IsMethod: true, + IsResolver: true, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return nil, errors.New("field of type Time does not have child fields") + }, + } + return fc, nil +} + +func (ec *executionContext) _Sitemap_updated_at(ctx context.Context, field graphql.CollectedField, obj *models.Sitemap) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_Sitemap_updated_at(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.UpdatedAt, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.(time.Time) + fc.Result = res + return ec.marshalOTime2timeᚐTime(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_Sitemap_updated_at(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "Sitemap", + Field: field, + IsMethod: false, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return nil, errors.New("field of type Time does not have child fields") + }, + } + return fc, nil +} + func (ec *executionContext) _Sitemaps_categories(ctx context.Context, field graphql.CollectedField, obj *models.Sitemaps) (ret graphql.Marshaler) { fc, err := ec.fieldContext_Sitemaps_categories(ctx, field) if err != nil { @@ -12503,6 +12607,10 @@ func (ec *executionContext) fieldContext_Sitemaps_categories(ctx context.Context return ec.fieldContext_Sitemap_id(ctx, field) case "created_at": return ec.fieldContext_Sitemap_created_at(ctx, field) + case "published_date": + return ec.fieldContext_Sitemap_published_date(ctx, field) + case "updated_at": + return ec.fieldContext_Sitemap_updated_at(ctx, field) } return nil, fmt.Errorf("no field named %q was found under type Sitemap", field.Name) }, @@ -12552,6 +12660,10 @@ func (ec *executionContext) fieldContext_Sitemaps_tags(ctx context.Context, fiel return ec.fieldContext_Sitemap_id(ctx, field) case "created_at": return ec.fieldContext_Sitemap_created_at(ctx, field) + case "published_date": + return ec.fieldContext_Sitemap_published_date(ctx, field) + case "updated_at": + return ec.fieldContext_Sitemap_updated_at(ctx, field) } return nil, fmt.Errorf("no field named %q was found under type Sitemap", field.Name) }, @@ -12601,6 +12713,10 @@ func (ec *executionContext) fieldContext_Sitemaps_users(ctx context.Context, fie return ec.fieldContext_Sitemap_id(ctx, field) case "created_at": return ec.fieldContext_Sitemap_created_at(ctx, field) + case "published_date": + return ec.fieldContext_Sitemap_published_date(ctx, field) + case "updated_at": + return ec.fieldContext_Sitemap_updated_at(ctx, field) } return nil, fmt.Errorf("no field named %q was found under type Sitemap", field.Name) }, @@ -12650,6 +12766,10 @@ func (ec *executionContext) fieldContext_Sitemaps_formats(ctx context.Context, f return ec.fieldContext_Sitemap_id(ctx, field) case "created_at": return ec.fieldContext_Sitemap_created_at(ctx, field) + case "published_date": + return ec.fieldContext_Sitemap_published_date(ctx, field) + case "updated_at": + return ec.fieldContext_Sitemap_updated_at(ctx, field) } return nil, fmt.Errorf("no field named %q was found under type Sitemap", field.Name) }, @@ -12699,6 +12819,10 @@ func (ec *executionContext) fieldContext_Sitemaps_posts(ctx context.Context, fie return ec.fieldContext_Sitemap_id(ctx, field) case "created_at": return ec.fieldContext_Sitemap_created_at(ctx, field) + case "published_date": + return ec.fieldContext_Sitemap_published_date(ctx, field) + case "updated_at": + return ec.fieldContext_Sitemap_updated_at(ctx, field) } return nil, fmt.Errorf("no field named %q was found under type Sitemap", field.Name) }, @@ -12748,6 +12872,10 @@ func (ec *executionContext) fieldContext_Sitemaps_claims(ctx context.Context, fi return ec.fieldContext_Sitemap_id(ctx, field) case "created_at": return ec.fieldContext_Sitemap_created_at(ctx, field) + case "published_date": + return ec.fieldContext_Sitemap_published_date(ctx, field) + case "updated_at": + return ec.fieldContext_Sitemap_updated_at(ctx, field) } return nil, fmt.Errorf("no field named %q was found under type Sitemap", field.Name) }, @@ -12797,6 +12925,10 @@ func (ec *executionContext) fieldContext_Sitemaps_claimants(ctx context.Context, return ec.fieldContext_Sitemap_id(ctx, field) case "created_at": return ec.fieldContext_Sitemap_created_at(ctx, field) + case "published_date": + return ec.fieldContext_Sitemap_published_date(ctx, field) + case "updated_at": + return ec.fieldContext_Sitemap_updated_at(ctx, field) } return nil, fmt.Errorf("no field named %q was found under type Sitemap", field.Name) }, @@ -12846,6 +12978,10 @@ func (ec *executionContext) fieldContext_Sitemaps_ratings(ctx context.Context, f return ec.fieldContext_Sitemap_id(ctx, field) case "created_at": return ec.fieldContext_Sitemap_created_at(ctx, field) + case "published_date": + return ec.fieldContext_Sitemap_published_date(ctx, field) + case "updated_at": + return ec.fieldContext_Sitemap_updated_at(ctx, field) } return nil, fmt.Errorf("no field named %q was found under type Sitemap", field.Name) }, @@ -19456,19 +19592,40 @@ func (ec *executionContext) _Sitemap(ctx context.Context, sel ast.SelectionSet, out.Values[i] = ec._Sitemap_slug(ctx, field, obj) if out.Values[i] == graphql.Null { - invalids++ + atomic.AddUint32(&invalids, 1) } case "id": out.Values[i] = ec._Sitemap_id(ctx, field, obj) if out.Values[i] == graphql.Null { - invalids++ + atomic.AddUint32(&invalids, 1) } case "created_at": out.Values[i] = ec._Sitemap_created_at(ctx, field, obj) + case "published_date": + field := field + + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + } + }() + res = ec._Sitemap_published_date(ctx, field, obj) + return res + } + + out.Concurrently(i, func() graphql.Marshaler { + return innerFunc(ctx) + + }) + case "updated_at": + + out.Values[i] = ec._Sitemap_updated_at(ctx, field, obj) + default: panic("unknown field " + strconv.Quote(field.Name)) } diff --git a/api/graph/models/sitemap.go b/api/graph/models/sitemap.go index a0082ed39..f9954a576 100644 --- a/api/graph/models/sitemap.go +++ b/api/graph/models/sitemap.go @@ -4,9 +4,11 @@ import "time" // Sitemap model type Sitemap struct { - Slug string `json:"slug"` - ID string `json:"id"` - CreatedAt time.Time `json:"created_at"` + Slug string `json:"slug"` + ID string `json:"id"` + CreatedAt time.Time `json:"created_at"` + UpdatedAt time.Time `json:"updated_at"` + PublishedAt time.Time `json:"published_at"` } // Sitemaps model diff --git a/api/graph/resolvers/sitemaps.go b/api/graph/resolvers/sitemaps.go new file mode 100644 index 000000000..7882023e0 --- /dev/null +++ b/api/graph/resolvers/sitemaps.go @@ -0,0 +1,258 @@ +package resolvers + +import ( + "context" + "encoding/json" + "fmt" + "net/http" + "time" + + "github.com/factly/dega-api/config" + "github.com/factly/dega-api/graph/generated" + "github.com/factly/dega-api/graph/models" + "github.com/factly/dega-api/graph/validator" + "github.com/spf13/viper" +) + +func (r *queryResolver) Sitemap(ctx context.Context) (*models.Sitemaps, error) { + var ok models.Sitemaps = "OKAY" + return &ok, nil +} + +func (r *sitemapsResolver) Categories(ctx context.Context, obj *models.Sitemaps) ([]*models.Sitemap, error) { + sID, err := validator.GetSpace(ctx) + if err != nil { + return nil, err + } + + categories := []models.Category{} + + config.DB.Model(&models.Category{}).Where("space_id in (?)", sID).Find(&categories) + nodes := []*models.Sitemap{} + + for _, category := range categories { + sitemap := &models.Sitemap{ + ID: fmt.Sprint(category.ID), + Slug: category.Slug, + CreatedAt: category.CreatedAt, + UpdatedAt: category.UpdatedAt, + } + nodes = append(nodes, sitemap) + } + return nodes, nil +} + +func (r *sitemapsResolver) Tags(ctx context.Context, obj *models.Sitemaps) ([]*models.Sitemap, error) { + sID, err := validator.GetSpace(ctx) + if err != nil { + return nil, err + } + tags := []models.Tag{} + + config.DB.Model(&models.Tag{}).Where("space_id in (?)", sID).Find(&tags) + nodes := []*models.Sitemap{} + + for _, tag := range tags { + sitemap := &models.Sitemap{ + ID: fmt.Sprint(tag.ID), + Slug: tag.Slug, + CreatedAt: tag.CreatedAt, + UpdatedAt: tag.UpdatedAt, + } + nodes = append(nodes, sitemap) + } + return nodes, nil +} + +func (r *sitemapsResolver) Users(ctx context.Context, obj *models.Sitemaps) ([]*models.Sitemap, error) { + + sID, err := validator.GetSpace(ctx) + if err != nil { + return nil, nil + } + + post := &models.Post{} + post.SpaceID = sID + + err = config.DB.First(post).Error + if err != nil { + return nil, nil + } + + postAuthor := &models.PostAuthor{} + postAuthor.PostID = post.ID + + err = config.DB.First(postAuthor).Error + if err != nil { + return nil, nil + } + + space := &models.Space{} + space.ID = sID + + err = config.DB.First(space).Error + if err != nil { + return nil, nil + } + + url := fmt.Sprint(viper.GetString("kavach_url"), "/organisations/", space.OrganisationID, "/users") + + req, err := http.NewRequest("GET", url, nil) + if err != nil { + return nil, nil + } + + req.Header.Set("Content-Type", "application/json") + req.Header.Set("X-User", fmt.Sprint(postAuthor.AuthorID)) + client := &http.Client{} + resp, err := client.Do(req) + + if err != nil { + return nil, nil + } + + defer resp.Body.Close() + + users := []*models.User{} + err = json.NewDecoder(resp.Body).Decode(&users) + + if err != nil { + return nil, nil + } + + nodes := []*models.Sitemap{} + + for _, user := range users { + sitemap := &models.Sitemap{ + ID: fmt.Sprint(user.ID), + Slug: fmt.Sprint(user.ID), + CreatedAt: user.CreatedAt, + UpdatedAt: user.UpdatedAt, + } + nodes = append(nodes, sitemap) + } + return nodes, nil +} + +func (r *sitemapsResolver) Formats(ctx context.Context, obj *models.Sitemaps) ([]*models.Sitemap, error) { + sID, err := validator.GetSpace(ctx) + if err != nil { + return nil, err + } + formats := []models.Format{} + + config.DB.Model(&models.Format{}).Where("space_id in (?)", sID).Find(&formats) + nodes := []*models.Sitemap{} + + for _, format := range formats { + sitemap := &models.Sitemap{ + ID: fmt.Sprint(format.ID), + Slug: format.Slug, + CreatedAt: format.CreatedAt, + UpdatedAt: format.UpdatedAt, + } + nodes = append(nodes, sitemap) + } + return nodes, nil +} + +func (r *sitemapsResolver) Posts(ctx context.Context, obj *models.Sitemaps) ([]*models.Sitemap, error) { + sID, err := validator.GetSpace(ctx) + if err != nil { + return nil, err + } + posts := []models.Post{} + + config.DB.Model(&models.Post{}).Where("space_id in (?)", sID).Find(&posts) + nodes := []*models.Sitemap{} + + for _, post := range posts { + var publishedDate time.Time + if post.PublishedDate == nil { + publishedDate = time.Time{} + } else { + publishedDate = *post.PublishedDate + } + + sitemap := &models.Sitemap{ + ID: fmt.Sprint(post.ID), + Slug: post.Slug, + CreatedAt: post.CreatedAt, + UpdatedAt: post.UpdatedAt, + PublishedAt: publishedDate, + } + nodes = append(nodes, sitemap) + } + return nodes, nil +} + +func (r *sitemapsResolver) Claims(ctx context.Context, obj *models.Sitemaps) ([]*models.Sitemap, error) { + sID, err := validator.GetSpace(ctx) + if err != nil { + return nil, err + } + claims := []models.Claim{} + + config.DB.Model(&models.Claim{}).Where("space_id in (?)", sID).Find(&claims) + nodes := []*models.Sitemap{} + + for _, claim := range claims { + sitemap := &models.Sitemap{ + ID: fmt.Sprint(claim.ID), + Slug: claim.Slug, + CreatedAt: claim.CreatedAt, + UpdatedAt: claim.UpdatedAt, + } + nodes = append(nodes, sitemap) + } + return nodes, nil +} + +func (r *sitemapsResolver) Claimants(ctx context.Context, obj *models.Sitemaps) ([]*models.Sitemap, error) { + sID, err := validator.GetSpace(ctx) + if err != nil { + return nil, err + } + claimants := []models.Claimant{} + + config.DB.Model(&models.Claimant{}).Where("space_id in (?)", sID).Find(&claimants) + nodes := []*models.Sitemap{} + + for _, claimant := range claimants { + sitemap := &models.Sitemap{ + ID: fmt.Sprint(claimant.ID), + Slug: claimant.Slug, + CreatedAt: claimant.CreatedAt, + UpdatedAt: claimant.UpdatedAt, + } + nodes = append(nodes, sitemap) + } + return nodes, nil +} + +func (r *sitemapsResolver) Ratings(ctx context.Context, obj *models.Sitemaps) ([]*models.Sitemap, error) { + sID, err := validator.GetSpace(ctx) + if err != nil { + return nil, err + } + ratings := []models.Rating{} + + config.DB.Model(&models.Rating{}).Where("space_id in (?)", sID).Find(&ratings) + nodes := []*models.Sitemap{} + + for _, rating := range ratings { + sitemap := &models.Sitemap{ + ID: fmt.Sprint(rating.ID), + Slug: rating.Slug, + CreatedAt: rating.CreatedAt, + UpdatedAt: rating.UpdatedAt, + } + nodes = append(nodes, sitemap) + } + return nodes, nil +} + +// Sitemaps model resolver +func (r *Resolver) Sitemaps() generated.SitemapsResolver { return &sitemapsResolver{r} } + +type sitemapsResolver struct{ *Resolver } diff --git a/api/graph/schema.graphql b/api/graph/schema.graphql index c58d0ae73..46f952fbf 100644 --- a/api/graph/schema.graphql +++ b/api/graph/schema.graphql @@ -260,6 +260,8 @@ type Sitemap { slug: String! id: ID! created_at: Time + published_date: Time + updated_at: Time } type Sitemaps { diff --git a/docker-compose.yml b/docker-compose.yml index ded36955e..367cb2f18 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -25,6 +25,7 @@ services: image: minio/minio ports: - "9000:9000" + - "9002:9002" volumes: - ~/factly/dega/minio/data:/export - ~/factly/dega/minio/config:/root/.minio @@ -33,7 +34,7 @@ services: - MINIO_SECRET_KEY=miniosecret networks: - dega - command: server /export + command: server -console-address :9002 /export createbuckets: image: minio/mc diff --git a/server/service/core/action/category/create.go b/server/service/core/action/category/create.go index ed70d36ff..893ca1d11 100644 --- a/server/service/core/action/category/create.go +++ b/server/service/core/action/category/create.go @@ -5,14 +5,13 @@ import ( "encoding/json" "errors" "net/http" - "reflect" "github.com/factly/x/loggerx" + "github.com/jinzhu/gorm/dialects/postgres" "gorm.io/gorm" "github.com/factly/dega-server/config" "github.com/factly/dega-server/service/core/model" - "github.com/factly/dega-server/test" "github.com/factly/dega-server/util" "github.com/factly/x/errorx" "github.com/factly/x/meilisearchx" @@ -112,21 +111,33 @@ func create(w http.ResponseWriter, r *http.Request) { } // Store HTML description - var description string - if len(category.Description.RawMessage) > 0 && !reflect.DeepEqual(category.Description, test.NilJsonb()) { - description, err = util.HTMLDescription(category.Description) + var htmlDescription string + var jsonDescription postgres.Jsonb + if len(category.Description.RawMessage) > 0 { + htmlDescription, err = util.GetHTMLDescription(category.Description) if err != nil { loggerx.Error(err) - errorx.Render(w, errorx.Parser(errorx.GetMessage("cannot parse category description", http.StatusUnprocessableEntity))) + errorx.Render(w, errorx.Parser(errorx.DecodeError())) + return + } + + jsonDescription, err = util.GetJSONDescription(category.Description) + if err != nil { + loggerx.Error(err) + errorx.Render(w, errorx.Parser(errorx.DecodeError())) return } } result := &model.Category{ + Base: config.Base{ + CreatedAt: category.CreatedAt, + UpdatedAt: category.UpdatedAt, + }, Name: category.Name, - Description: category.Description, + Description: jsonDescription, BackgroundColour: category.BackgroundColour, - HTMLDescription: description, + HTMLDescription: htmlDescription, Slug: slugx.Approve(&config.DB, categorySlug, sID, tableName), ParentID: parentID, MediumID: mediumID, diff --git a/server/service/core/action/category/route.go b/server/service/core/action/category/route.go index d44328126..228bb87f8 100644 --- a/server/service/core/action/category/route.go +++ b/server/service/core/action/category/route.go @@ -1,6 +1,8 @@ package category import ( + "time" + "github.com/factly/dega-server/config" "github.com/factly/dega-server/util" "github.com/go-chi/chi" @@ -9,6 +11,8 @@ import ( // category request body type category struct { + CreatedAt time.Time `json:"created_at"` + UpdatedAt time.Time `json:"updated_at"` Name string `json:"name" validate:"required,max=500"` Slug string `json:"slug"` BackgroundColour postgres.Jsonb `json:"background_colour" validate:"required" swaggertype:"primitive,string"` diff --git a/server/service/core/action/category/update.go b/server/service/core/action/category/update.go index 1052cebf2..46145f6fc 100644 --- a/server/service/core/action/category/update.go +++ b/server/service/core/action/category/update.go @@ -4,13 +4,11 @@ import ( "encoding/json" "errors" "net/http" - "reflect" "strconv" "time" "github.com/factly/dega-server/config" "github.com/factly/dega-server/service/core/model" - "github.com/factly/dega-server/test" "github.com/factly/dega-server/util" "github.com/factly/x/errorx" "github.com/factly/x/loggerx" @@ -20,6 +18,7 @@ import ( "github.com/factly/x/slugx" "github.com/factly/x/validationx" "github.com/go-chi/chi" + "github.com/jinzhu/gorm/dialects/postgres" "gorm.io/gorm" ) @@ -135,24 +134,33 @@ func update(w http.ResponseWriter, r *http.Request) { } // Store HTML description - var description string - if len(category.Description.RawMessage) > 0 && !reflect.DeepEqual(category.Description, test.NilJsonb()) { - description, err = util.HTMLDescription(category.Description) + var htmlDescription string + var jsonDescription postgres.Jsonb + if len(category.Description.RawMessage) > 0 { + htmlDescription, err = util.GetHTMLDescription(category.Description) if err != nil { loggerx.Error(err) - errorx.Render(w, errorx.Parser(errorx.GetMessage("cannot parse category description", http.StatusUnprocessableEntity))) + errorx.Render(w, errorx.Parser(errorx.DecodeError())) + return + } + + jsonDescription, err = util.GetJSONDescription(category.Description) + if err != nil { + loggerx.Error(err) + errorx.Render(w, errorx.Parser(errorx.DecodeError())) return } } tx := config.DB.Begin() updateMap := map[string]interface{}{ - "updated_at": time.Now(), + "created_at": category.CreatedAt, + "updated_at": category.UpdatedAt, "updated_by_id": uID, "name": category.Name, "slug": categorySlug, - "description": category.Description, - "html_description": description, + "description": jsonDescription, + "html_description": htmlDescription, "medium_id": category.MediumID, "is_featured": category.IsFeatured, "meta_fields": category.MetaFields, @@ -169,6 +177,14 @@ func update(w http.ResponseWriter, r *http.Request) { updateMap["parent_id"] = nil } + if category.CreatedAt.IsZero() { + updateMap["created_at"] = result.CreatedAt + } + + if category.UpdatedAt.IsZero() { + updateMap["updated_at"] = time.Now() + } + err = tx.Model(&result).Updates(&updateMap).Preload("Medium").Preload("ParentCategory").First(&result).Error if err != nil { tx.Rollback() diff --git a/server/service/core/action/format/create.go b/server/service/core/action/format/create.go index 402f5a1ff..20a61d8bb 100644 --- a/server/service/core/action/format/create.go +++ b/server/service/core/action/format/create.go @@ -105,6 +105,10 @@ func create(w http.ResponseWriter, r *http.Request) { } result := &model.Format{ + Base: config.Base{ + CreatedAt: format.CreatedAt, + UpdatedAt: format.UpdatedAt, + }, Name: format.Name, Description: format.Description, Slug: slugx.Approve(&config.DB, formatSlug, sID, tableName), diff --git a/server/service/core/action/format/route.go b/server/service/core/action/format/route.go index 3b1a2b3e7..fe80a8cf9 100644 --- a/server/service/core/action/format/route.go +++ b/server/service/core/action/format/route.go @@ -1,6 +1,8 @@ package format import ( + "time" + "github.com/factly/dega-server/config" "github.com/factly/dega-server/util" "github.com/go-chi/chi" @@ -9,6 +11,8 @@ import ( // format model type format struct { + CreatedAt time.Time `json:"created_at"` + UpdatedAt time.Time `json:"updated_at"` Name string `json:"name" validate:"required,min=3,max=50"` Slug string `json:"slug"` Description string `json:"description"` diff --git a/server/service/core/action/format/update.go b/server/service/core/action/format/update.go index a9fa99c6a..bdce74cdc 100644 --- a/server/service/core/action/format/update.go +++ b/server/service/core/action/format/update.go @@ -115,7 +115,8 @@ func update(w http.ResponseWriter, r *http.Request) { tx := config.DB.Begin() updateMap := map[string]interface{}{ - "updated_at": time.Now(), + "created_at": format.CreatedAt, + "updated_at": format.UpdatedAt, "updated_by_id": uint(uID), "name": format.Name, "slug": formatSlug, @@ -130,7 +131,15 @@ func update(w http.ResponseWriter, r *http.Request) { if format.MediumID == 0 { updateMap["medium_id"] = nil } - + + if format.CreatedAt.IsZero() { + updateMap["created_at"] = result.CreatedAt + } + + if format.UpdatedAt.IsZero() { + updateMap["updated_at"] = time.Now() + } + tx.Model(&result).Updates(&updateMap).Preload("Medium").First(&result) // Update into meili index diff --git a/server/service/core/action/medium/create.go b/server/service/core/action/medium/create.go index d53cac08d..0948ed773 100644 --- a/server/service/core/action/medium/create.go +++ b/server/service/core/action/medium/create.go @@ -109,6 +109,10 @@ func create(w http.ResponseWriter, r *http.Request) { tableName := stmt.Schema.Table med := model.Medium{ + Base: config.Base{ + CreatedAt: medium.CreatedAt, + UpdatedAt: medium.UpdatedAt, + }, Name: medium.Name, Slug: slugx.Approve(&config.DB, mediumSlug, sID, tableName), Title: medium.Title, diff --git a/server/service/core/action/medium/route.go b/server/service/core/action/medium/route.go index 579cb171f..2bb7b7d13 100644 --- a/server/service/core/action/medium/route.go +++ b/server/service/core/action/medium/route.go @@ -1,6 +1,8 @@ package medium import ( + "time" + "github.com/factly/dega-server/config" "github.com/factly/dega-server/util" @@ -10,6 +12,8 @@ import ( // medium model type medium struct { + CreatedAt time.Time `json:"created_at"` + UpdatedAt time.Time `json:"updated_at"` Name string `json:"name" validate:"required"` Slug string `json:"slug"` Type string `json:"type" validate:"required"` diff --git a/server/service/core/action/medium/update.go b/server/service/core/action/medium/update.go index 33928dfce..f92372e57 100644 --- a/server/service/core/action/medium/update.go +++ b/server/service/core/action/medium/update.go @@ -104,20 +104,25 @@ func update(w http.ResponseWriter, r *http.Request) { } tx := config.DB.Begin() - err = tx.Model(&result).Updates(model.Medium{ - Base: config.Base{UpdatedByID: uint(uID)}, - Name: medium.Name, - Slug: mediumSlug, - Title: medium.Title, - Type: medium.Type, - Description: medium.Description, - AltText: medium.AltText, - Caption: medium.Caption, - FileSize: medium.FileSize, - URL: medium.URL, - Dimensions: medium.Dimensions, - MetaFields: medium.MetaFields, - }).First(&result).Error + + updateMap := map[string]interface{}{ + "created_at": medium.CreatedAt, + "updated_at": medium.UpdatedAt, + "updated_by_id": uint(uID), + "name": medium.Name, + "slug": mediumSlug, + "title": medium.Title, + "type": medium.Type, + "alt_text": medium.AltText, + "caption": medium.Caption, + "file_size": medium.FileSize, + "url": medium.URL, + "dimensions": medium.Dimensions, + "description": medium.Description, + "meta_fields": medium.MetaFields, + } + + err = tx.Model(&result).Updates(&updateMap).First(&result).Error if err != nil { tx.Rollback() diff --git a/server/service/core/action/menu/create.go b/server/service/core/action/menu/create.go index 239a63d12..6606cc5d9 100644 --- a/server/service/core/action/menu/create.go +++ b/server/service/core/action/menu/create.go @@ -87,6 +87,10 @@ func create(w http.ResponseWriter, r *http.Request) { } result := &model.Menu{ + Base: config.Base{ + CreatedAt: menu.CreatedAt, + UpdatedAt: menu.UpdatedAt, + }, Name: menu.Name, Menu: menu.Menu, Slug: slugx.Approve(&config.DB, menuSlug, sID, tableName), diff --git a/server/service/core/action/menu/route.go b/server/service/core/action/menu/route.go index 7ac8fe1fb..4c1070a26 100644 --- a/server/service/core/action/menu/route.go +++ b/server/service/core/action/menu/route.go @@ -1,6 +1,8 @@ package menu import ( + "time" + "github.com/factly/dega-server/config" "github.com/factly/dega-server/util" "github.com/go-chi/chi" @@ -9,6 +11,8 @@ import ( // menu request body type menu struct { + CreatedAt time.Time `json:"created_at"` + UpdatedAt time.Time `json:"updated_at"` Name string `json:"name" validate:"required,min=3,max=50"` Slug string `json:"slug"` Menu postgres.Jsonb `json:"menu" swaggertype:"primitive,string"` diff --git a/server/service/core/action/menu/update.go b/server/service/core/action/menu/update.go index ba7b05198..e276ff316 100644 --- a/server/service/core/action/menu/update.go +++ b/server/service/core/action/menu/update.go @@ -114,13 +114,17 @@ func update(w http.ResponseWriter, r *http.Request) { tx := config.DB.Begin() - err = tx.Model(&result).Updates(model.Menu{ - Base: config.Base{UpdatedByID: uint(uID)}, - Name: menu.Name, - Slug: menuSlug, - Menu: menu.Menu, - MetaFields: menu.MetaFields, - }).First(&result).Error + updateMap := map[string]interface{}{ + "created_at": menu.CreatedAt, + "updated_at": menu.UpdatedAt, + "updated_by_id": uint(uID), + "name": menu.Name, + "slug": menuSlug, + "menu": menu.Menu, + "meta_fields": menu.MetaFields, + } + + err = tx.Model(&result).Updates(&updateMap).First(&result).Error if err != nil { tx.Rollback() diff --git a/server/service/core/action/page/create.go b/server/service/core/action/page/create.go index 2e1675e32..3da14c003 100644 --- a/server/service/core/action/page/create.go +++ b/server/service/core/action/page/create.go @@ -6,12 +6,10 @@ import ( "errors" "fmt" "net/http" - "reflect" "github.com/factly/dega-server/config" "github.com/factly/dega-server/service/core/action/author" "github.com/factly/dega-server/service/core/model" - "github.com/factly/dega-server/test" "github.com/factly/dega-server/util" "github.com/factly/x/errorx" "github.com/factly/x/loggerx" @@ -20,6 +18,7 @@ import ( "github.com/factly/x/renderx" "github.com/factly/x/slugx" "github.com/factly/x/validationx" + "github.com/jinzhu/gorm/dialects/postgres" "gorm.io/gorm" ) @@ -86,25 +85,37 @@ func create(w http.ResponseWriter, r *http.Request) { } // Store HTML description - var description string - if len(page.Description.RawMessage) > 0 && !reflect.DeepEqual(page.Description, test.NilJsonb()) { - description, err = util.HTMLDescription(page.Description) + var htmlDescription string + var jsonDescription postgres.Jsonb + if len(page.Description.RawMessage) > 0 { + htmlDescription, err = util.GetHTMLDescription(page.Description) if err != nil { loggerx.Error(err) - errorx.Render(w, errorx.Parser(errorx.GetMessage("cannot parse post description", http.StatusUnprocessableEntity))) + errorx.Render(w, errorx.Parser(errorx.DecodeError())) + return + } + + jsonDescription, err = util.GetJSONDescription(page.Description) + if err != nil { + loggerx.Error(err) + errorx.Render(w, errorx.Parser(errorx.DecodeError())) return } } result.Post = model.Post{ + Base: config.Base{ + CreatedAt: page.CreatedAt, + UpdatedAt: page.UpdatedAt, + }, Title: page.Title, Slug: slugx.Approve(&config.DB, postSlug, sID, tableName), Status: page.Status, IsPage: true, Subtitle: page.Subtitle, Excerpt: page.Excerpt, - Description: page.Description, - HTMLDescription: description, + Description: jsonDescription, + HTMLDescription: htmlDescription, IsHighlighted: page.IsHighlighted, IsSticky: page.IsSticky, FeaturedMediumID: featuredMediumID, diff --git a/server/service/core/action/page/route.go b/server/service/core/action/page/route.go index f56d72ff0..e3352adc0 100644 --- a/server/service/core/action/page/route.go +++ b/server/service/core/action/page/route.go @@ -12,6 +12,8 @@ import ( // page request body type page struct { + CreatedAt time.Time `json:"created_at"` + UpdatedAt time.Time `json:"updated_at"` Title string `json:"title" validate:"required,min=3,max=150"` Subtitle string `json:"subtitle"` Slug string `json:"slug"` diff --git a/server/service/core/action/page/update.go b/server/service/core/action/page/update.go index d89c977bc..40f048081 100644 --- a/server/service/core/action/page/update.go +++ b/server/service/core/action/page/update.go @@ -6,13 +6,12 @@ import ( "errors" "fmt" "net/http" - "reflect" "strconv" + "time" "github.com/factly/dega-server/config" "github.com/factly/dega-server/service/core/action/author" "github.com/factly/dega-server/service/core/model" - "github.com/factly/dega-server/test" "github.com/factly/dega-server/util" "github.com/factly/dega-server/util/arrays" "github.com/factly/x/errorx" @@ -23,6 +22,7 @@ import ( "github.com/factly/x/slugx" "github.com/factly/x/validationx" "github.com/go-chi/chi" + "github.com/jinzhu/gorm/dialects/postgres" "gorm.io/gorm" ) @@ -121,12 +121,20 @@ func update(w http.ResponseWriter, r *http.Request) { } // Store HTML description - var description string - if len(page.Description.RawMessage) > 0 && !reflect.DeepEqual(page.Description, test.NilJsonb()) { - description, err = util.HTMLDescription(page.Description) + var htmlDescription string + var jsonDescription postgres.Jsonb + if len(page.Description.RawMessage) > 0 { + htmlDescription, err = util.GetHTMLDescription(page.Description) if err != nil { loggerx.Error(err) - errorx.Render(w, errorx.Parser(errorx.GetMessage("cannot parse page description", http.StatusUnprocessableEntity))) + errorx.Render(w, errorx.Parser(errorx.DecodeError())) + return + } + + jsonDescription, err = util.GetJSONDescription(page.Description) + if err != nil { + loggerx.Error(err) + errorx.Render(w, errorx.Parser(errorx.DecodeError())) return } } @@ -160,6 +168,8 @@ func update(w http.ResponseWriter, r *http.Request) { } updateMap := map[string]interface{}{ + "created_at": page.CreatedAt, + "updated_at": page.UpdatedAt, "updated_by_id": uint(uID), "title": page.Title, "slug": pageSlug, @@ -167,8 +177,8 @@ func update(w http.ResponseWriter, r *http.Request) { "status": page.Status, "published_date": page.PublishedDate, "excerpt": page.Excerpt, - "description": page.Description, - "html_description": description, + "description": jsonDescription, + "html_description": htmlDescription, "is_highlighted": page.IsHighlighted, "is_sticky": page.IsSticky, "format_id": page.FormatID, @@ -185,6 +195,14 @@ func update(w http.ResponseWriter, r *http.Request) { updateMap["featured_medium_id"] = nil } + if page.CreatedAt.IsZero() { + updateMap["created_at"] = result.CreatedAt + } + + if page.UpdatedAt.IsZero() { + updateMap["updated_at"] = time.Now() + } + err = tx.Model(&result.Post).Omit("Tags", "Categories").Updates(&updateMap).Preload("Medium").Preload("Format").Preload("Tags").Preload("Categories").First(&result.Post).Error if err != nil { diff --git a/server/service/core/action/post/create.go b/server/service/core/action/post/create.go index d634793a4..1dd030c59 100644 --- a/server/service/core/action/post/create.go +++ b/server/service/core/action/post/create.go @@ -6,14 +6,12 @@ import ( "errors" "fmt" "net/http" - "reflect" "time" "github.com/factly/dega-server/config" "github.com/factly/dega-server/service/core/action/author" "github.com/factly/dega-server/service/core/model" factCheckModel "github.com/factly/dega-server/service/fact-check/model" - "github.com/factly/dega-server/test" "github.com/factly/dega-server/util" "github.com/factly/x/errorx" "github.com/factly/x/loggerx" @@ -179,24 +177,35 @@ func createPost(ctx context.Context, post post, status string) (*postData, error featuredMediumID = nil } - // Store HTML description - var description string - if len(post.Description.RawMessage) > 0 && !reflect.DeepEqual(post.Description, test.NilJsonb()) { - description, err = util.HTMLDescription(post.Description) + var htmlDescription string + var jsonDescription postgres.Jsonb + if len(post.Description.RawMessage) > 0 { + htmlDescription, err = util.GetHTMLDescription(post.Description) if err != nil { - return nil, errorx.GetMessage("cannot parse post description", http.StatusUnprocessableEntity) + loggerx.Error(err) + return nil, errorx.GetMessage("could not get html description", 422) + } + + jsonDescription, err = util.GetJSONDescription(post.Description) + if err != nil { + loggerx.Error(err) + return nil, errorx.GetMessage("could not get json description", 422) } } result.Post = model.Post{ + Base: config.Base{ + CreatedAt: post.CreatedAt, + UpdatedAt: post.UpdatedAt, + }, Title: post.Title, Slug: slugx.Approve(&config.DB, postSlug, sID, tableName), Status: status, IsPage: post.IsPage, Subtitle: post.Subtitle, Excerpt: post.Excerpt, - Description: post.Description, - HTMLDescription: description, + Description: jsonDescription, + HTMLDescription: htmlDescription, IsHighlighted: post.IsHighlighted, IsSticky: post.IsSticky, FeaturedMediumID: featuredMediumID, diff --git a/server/service/core/action/post/route.go b/server/service/core/action/post/route.go index 4e63bd29f..b124cbe04 100644 --- a/server/service/core/action/post/route.go +++ b/server/service/core/action/post/route.go @@ -13,6 +13,8 @@ import ( // post request body type post struct { + CreatedAt time.Time `json:"created_at"` + UpdatedAt time.Time `json:"updated_at"` Title string `json:"title" validate:"required,max=500"` Subtitle string `json:"subtitle"` Slug string `json:"slug"` diff --git a/server/service/core/action/post/update.go b/server/service/core/action/post/update.go index e3814c340..56fd8d16f 100644 --- a/server/service/core/action/post/update.go +++ b/server/service/core/action/post/update.go @@ -6,7 +6,6 @@ import ( "errors" "fmt" "net/http" - "reflect" "strconv" "time" @@ -14,7 +13,6 @@ import ( "github.com/factly/dega-server/service/core/action/author" "github.com/factly/dega-server/service/core/model" factCheckModel "github.com/factly/dega-server/service/fact-check/model" - "github.com/factly/dega-server/test" "github.com/factly/dega-server/util" "github.com/factly/dega-server/util/arrays" "github.com/factly/x/errorx" @@ -135,13 +133,20 @@ func update(w http.ResponseWriter, r *http.Request) { postSlug = slugx.Approve(&config.DB, slugx.Make(post.Title), sID, tableName) } - // Store HTML description - var description string - if len(post.Description.RawMessage) > 0 && !reflect.DeepEqual(post.Description, test.NilJsonb()) { - description, err = util.HTMLDescription(post.Description) + var htmlDescription string + var jsonDescription postgres.Jsonb + if len(post.Description.RawMessage) > 0 { + htmlDescription, err = util.GetHTMLDescription(post.Description) if err != nil { loggerx.Error(err) - errorx.Render(w, errorx.Parser(errorx.GetMessage("cannot parse post description", http.StatusUnprocessableEntity))) + errorx.Render(w, errorx.Parser(errorx.DecodeError())) + return + } + + jsonDescription, err = util.GetJSONDescription(post.Description) + if err != nil { + loggerx.Error(err) + errorx.Render(w, errorx.Parser(errorx.DecodeError())) return } } @@ -175,14 +180,15 @@ func update(w http.ResponseWriter, r *http.Request) { } updateMap := map[string]interface{}{ - "updated_at": time.Now(), + "created_at": post.CreatedAt, + "updated_at": post.UpdatedAt, "updated_by_id": uint(uID), "title": post.Title, "slug": postSlug, "subtitle": post.Subtitle, "excerpt": post.Excerpt, - "description": post.Description, - "html_description": description, + "description": jsonDescription, + "html_description": htmlDescription, "is_highlighted": post.IsHighlighted, "is_sticky": post.IsSticky, "is_featured": post.IsFeatured, @@ -199,6 +205,14 @@ func update(w http.ResponseWriter, r *http.Request) { updateMap["featured_medium_id"] = nil } + if post.CreatedAt.IsZero() { + updateMap["created_at"] = result.CreatedAt + } + + if post.UpdatedAt.IsZero() { + updateMap["updated_at"] = time.Now() + } + oldStatus := result.Post.Status // Check if post status is changed back to draft or ready from published if oldStatus == "publish" && (post.Status == "draft" || post.Status == "ready") { diff --git a/server/service/core/action/space/route.go b/server/service/core/action/space/route.go index d92d4c325..e084e3d27 100644 --- a/server/service/core/action/space/route.go +++ b/server/service/core/action/space/route.go @@ -1,6 +1,8 @@ package space import ( + "time" + "github.com/factly/dega-server/config" "github.com/factly/dega-server/service/core/action/role" "github.com/go-chi/chi" @@ -9,6 +11,8 @@ import ( // space request body type space struct { + CreatedAt time.Time `json:"created_at"` + UpdatedAt time.Time `json:"updated_at"` Name string `json:"name" validate:"required,min=3,max=50"` Slug string `json:"slug"` SiteTitle string `json:"site_title"` diff --git a/server/service/core/action/tag/create.go b/server/service/core/action/tag/create.go index f5df69af0..54f13e76b 100644 --- a/server/service/core/action/tag/create.go +++ b/server/service/core/action/tag/create.go @@ -5,11 +5,9 @@ import ( "encoding/json" "errors" "net/http" - "reflect" "github.com/factly/dega-server/config" "github.com/factly/dega-server/service/core/model" - "github.com/factly/dega-server/test" "github.com/factly/dega-server/util" "github.com/factly/x/errorx" "github.com/factly/x/loggerx" @@ -18,6 +16,7 @@ import ( "github.com/factly/x/renderx" "github.com/factly/x/slugx" "github.com/factly/x/validationx" + "github.com/jinzhu/gorm/dialects/postgres" "gorm.io/gorm" ) @@ -87,13 +86,20 @@ func create(w http.ResponseWriter, r *http.Request) { return } - // Store HTML description - var description string - if len(tag.Description.RawMessage) > 0 && !reflect.DeepEqual(tag.Description, test.NilJsonb()) { - description, err = util.HTMLDescription(tag.Description) + var htmlDescription string + var jsonDescription postgres.Jsonb + if len(tag.Description.RawMessage) > 0 { + htmlDescription, err = util.GetHTMLDescription(tag.Description) if err != nil { loggerx.Error(err) - errorx.Render(w, errorx.Parser(errorx.GetMessage("cannot parse tag description", http.StatusUnprocessableEntity))) + errorx.Render(w, errorx.Parser(errorx.DecodeError())) + return + } + + jsonDescription, err = util.GetJSONDescription(tag.Description) + if err != nil { + loggerx.Error(err) + errorx.Render(w, errorx.Parser(errorx.DecodeError())) return } } @@ -104,11 +110,15 @@ func create(w http.ResponseWriter, r *http.Request) { } result := &model.Tag{ + Base: config.Base{ + CreatedAt: tag.CreatedAt, + UpdatedAt: tag.UpdatedAt, + }, Name: tag.Name, Slug: slugx.Approve(&config.DB, tagSlug, sID, tableName), BackgroundColour: tag.BackgroundColour, - Description: tag.Description, - HTMLDescription: description, + Description: jsonDescription, + HTMLDescription: htmlDescription, SpaceID: uint(sID), MediumID: mediumID, IsFeatured: tag.IsFeatured, diff --git a/server/service/core/action/tag/route.go b/server/service/core/action/tag/route.go index 14aa2136d..327cd0695 100644 --- a/server/service/core/action/tag/route.go +++ b/server/service/core/action/tag/route.go @@ -1,6 +1,8 @@ package tag import ( + "time" + "github.com/factly/dega-server/config" "github.com/factly/dega-server/util" "github.com/go-chi/chi" @@ -9,6 +11,8 @@ import ( // tag model type tag struct { + CreatedAt time.Time `json:"created_at"` + UpdatedAt time.Time `json:"updated_at"` Name string `json:"name" validate:"required,max=500"` Slug string `json:"slug"` IsFeatured bool `json:"is_featured"` diff --git a/server/service/core/action/tag/update.go b/server/service/core/action/tag/update.go index a70f73186..599b0cfda 100644 --- a/server/service/core/action/tag/update.go +++ b/server/service/core/action/tag/update.go @@ -4,13 +4,11 @@ import ( "encoding/json" "errors" "net/http" - "reflect" "strconv" "time" "github.com/factly/dega-server/config" "github.com/factly/dega-server/service/core/model" - "github.com/factly/dega-server/test" "github.com/factly/dega-server/util" "github.com/factly/x/errorx" "github.com/factly/x/loggerx" @@ -20,6 +18,7 @@ import ( "github.com/factly/x/slugx" "github.com/factly/x/validationx" "github.com/go-chi/chi" + "github.com/jinzhu/gorm/dialects/postgres" "gorm.io/gorm" ) @@ -114,12 +113,20 @@ func update(w http.ResponseWriter, r *http.Request) { } // Store HTML description - var description string - if len(tag.Description.RawMessage) > 0 && !reflect.DeepEqual(tag.Description, test.NilJsonb()) { - description, err = util.HTMLDescription(tag.Description) + var htmlDescription string + var jsonDescription postgres.Jsonb + if len(tag.Description.RawMessage) > 0 { + htmlDescription, err = util.GetHTMLDescription(tag.Description) if err != nil { loggerx.Error(err) - errorx.Render(w, errorx.Parser(errorx.GetMessage("cannot parse tag description", http.StatusUnprocessableEntity))) + errorx.Render(w, errorx.Parser(errorx.DecodeError())) + return + } + + jsonDescription, err = util.GetJSONDescription(tag.Description) + if err != nil { + loggerx.Error(err) + errorx.Render(w, errorx.Parser(errorx.DecodeError())) return } } @@ -127,12 +134,13 @@ func update(w http.ResponseWriter, r *http.Request) { tx := config.DB.Begin() updateMap := map[string]interface{}{ - "updated_at": time.Now(), + "created_at": tag.CreatedAt, + "updated_at": tag.UpdatedAt, "updated_by_id": uint(uID), "name": tag.Name, "slug": tagSlug, - "description": tag.Description, - "html_description": description, + "description": jsonDescription, + "html_description": htmlDescription, "meta_fields": tag.MetaFields, "meta": tag.Meta, "header_code": tag.HeaderCode, @@ -145,6 +153,14 @@ func update(w http.ResponseWriter, r *http.Request) { updateMap["medium_id"] = nil } + if tag.CreatedAt.IsZero() { + updateMap["created_at"] = result.CreatedAt + } + + if tag.UpdatedAt.IsZero() { + updateMap["updated_at"] = time.Now() + } + tx.Model(&result).Select("IsFeatured").Updates(model.Tag{IsFeatured: tag.IsFeatured}) err = tx.Model(&result).Updates(&updateMap).Preload("Medium").First(&result).Error diff --git a/server/service/fact-check/action/claim/create.go b/server/service/fact-check/action/claim/create.go index fab1e1fb5..a5f24c41a 100644 --- a/server/service/fact-check/action/claim/create.go +++ b/server/service/fact-check/action/claim/create.go @@ -5,11 +5,9 @@ import ( "encoding/json" "errors" "net/http" - "reflect" "github.com/factly/dega-server/config" "github.com/factly/dega-server/service/fact-check/model" - "github.com/factly/dega-server/test" "github.com/factly/dega-server/util" "github.com/factly/x/errorx" "github.com/factly/x/loggerx" @@ -18,6 +16,7 @@ import ( "github.com/factly/x/renderx" "github.com/factly/x/slugx" "github.com/factly/x/validationx" + "github.com/jinzhu/gorm/dialects/postgres" "gorm.io/gorm" ) @@ -88,13 +87,20 @@ func create(w http.ResponseWriter, r *http.Request) { } } - // Store HTML description - var description string - if len(claim.Description.RawMessage) > 0 && !reflect.DeepEqual(claim.Description, test.NilJsonb()) { - description, err = util.HTMLDescription(claim.Description) + var htmlDescription string + var jsonDescription postgres.Jsonb + if len(claim.Description.RawMessage) > 0 { + htmlDescription, err = util.GetHTMLDescription(claim.Description) if err != nil { loggerx.Error(err) - errorx.Render(w, errorx.Parser(errorx.GetMessage("cannot parse claim description", http.StatusUnprocessableEntity))) + errorx.Render(w, errorx.Parser(errorx.DecodeError())) + return + } + + jsonDescription, err = util.GetJSONDescription(claim.Description) + if err != nil { + loggerx.Error(err) + errorx.Render(w, errorx.Parser(errorx.DecodeError())) return } } @@ -105,13 +111,17 @@ func create(w http.ResponseWriter, r *http.Request) { } result := &model.Claim{ + Base: config.Base{ + CreatedAt: claim.CreatedAt, + UpdatedAt: claim.UpdatedAt, + }, Claim: claim.Claim, Slug: slugx.Approve(&config.DB, claimSlug, sID, tableName), ClaimDate: claim.ClaimDate, CheckedDate: claim.CheckedDate, ClaimSources: claim.ClaimSources, - Description: claim.Description, - HTMLDescription: description, + Description: jsonDescription, + HTMLDescription: htmlDescription, ClaimantID: claim.ClaimantID, RatingID: claim.RatingID, Fact: claim.Fact, diff --git a/server/service/fact-check/action/claim/route.go b/server/service/fact-check/action/claim/route.go index 8e1c75994..e78ca7ebe 100644 --- a/server/service/fact-check/action/claim/route.go +++ b/server/service/fact-check/action/claim/route.go @@ -11,6 +11,8 @@ import ( ) type claim struct { + CreatedAt time.Time `json:"created_at"` + UpdatedAt time.Time `json:"updated_at"` Claim string `json:"claim" validate:"required,max=5000"` Slug string `json:"slug"` ClaimDate *time.Time `json:"claim_date" ` diff --git a/server/service/fact-check/action/claim/update.go b/server/service/fact-check/action/claim/update.go index 281b41bc0..736e1b511 100644 --- a/server/service/fact-check/action/claim/update.go +++ b/server/service/fact-check/action/claim/update.go @@ -4,12 +4,10 @@ import ( "encoding/json" "errors" "net/http" - "reflect" "strconv" "github.com/factly/dega-server/config" "github.com/factly/dega-server/service/fact-check/model" - "github.com/factly/dega-server/test" "github.com/factly/dega-server/util" "github.com/factly/x/errorx" "github.com/factly/x/loggerx" @@ -19,6 +17,7 @@ import ( "github.com/factly/x/slugx" "github.com/factly/x/validationx" "github.com/go-chi/chi" + "github.com/jinzhu/gorm/dialects/postgres" "gorm.io/gorm" ) @@ -115,53 +114,52 @@ func update(w http.ResponseWriter, r *http.Request) { } } - // Store HTML description - var description string - if len(claim.Description.RawMessage) > 0 && !reflect.DeepEqual(claim.Description, test.NilJsonb()) { - description, err = util.HTMLDescription(claim.Description) + var htmlDescription string + var jsonDescription postgres.Jsonb + if len(claim.Description.RawMessage) > 0 { + htmlDescription, err = util.GetHTMLDescription(claim.Description) if err != nil { loggerx.Error(err) - errorx.Render(w, errorx.Parser(errorx.GetMessage("cannot parse claim description", http.StatusUnprocessableEntity))) + errorx.Render(w, errorx.Parser(errorx.DecodeError())) return } - } - - tx := config.DB.Begin() - mediumID := &claim.MediumID - result.MediumID = &claim.MediumID - if claim.MediumID == 0 { - err = tx.Model(&result).Updates(map[string]interface{}{"medium_id": nil}).Error - mediumID = nil + jsonDescription, err = util.GetJSONDescription(claim.Description) if err != nil { - tx.Rollback() loggerx.Error(err) - errorx.Render(w, errorx.Parser(errorx.DBError())) + errorx.Render(w, errorx.Parser(errorx.DecodeError())) return } } - tx.Model(&result).Select("ClaimDate", "CheckedDate").Updates(model.Claim{ - ClaimDate: claim.ClaimDate, - CheckedDate: claim.CheckedDate, - }) - err = tx.Model(&result).Updates(model.Claim{ - Base: config.Base{UpdatedByID: uint(uID)}, - Claim: claim.Claim, - Slug: claimSlug, - ClaimSources: claim.ClaimSources, - Description: claim.Description, - HTMLDescription: description, - ClaimantID: claim.ClaimantID, - RatingID: claim.RatingID, - Fact: claim.Fact, - ReviewSources: claim.ReviewSources, - MetaFields: claim.MetaFields, - Meta: claim.Meta, - HeaderCode: claim.HeaderCode, - FooterCode: claim.FooterCode, - MediumID: mediumID, - }).Preload("Rating").Preload("Rating.Medium").Preload("Claimant").Preload("Claimant.Medium").Preload("Medium").First(&result).Error + tx := config.DB.Begin() + + updateMap := map[string]interface{}{ + "created_at": claim.CreatedAt, + "updated_at": claim.UpdatedAt, + "updated_by_id": uint(uID), + "claim": claim.Claim, + "slug": claimSlug, + "claim_sources": claim.ClaimSources, + "description": jsonDescription, + "html_description": htmlDescription, + "claimant_id": claim.ClaimantID, + "rating_id": claim.RatingID, + "fact": claim.Fact, + "review_sources": claim.ReviewSources, + "meta_fields": claim.MetaFields, + "claim_date": claim.ClaimDate, + "checked_date": claim.CheckedDate, + "meta": claim.Meta, + "header_code": claim.HeaderCode, + "footer_code": claim.FooterCode, + "medium_id": claim.MediumID, + } + if claim.MediumID == 0 { + updateMap["medium_id"] = nil + } + + err = tx.Model(&result).Updates(&updateMap).Preload("Rating").Preload("Rating.Medium").Preload("Claimant").Preload("Claimant.Medium").Preload("Medium").First(&result).Error if err != nil { tx.Rollback() diff --git a/server/service/fact-check/action/claimant/create.go b/server/service/fact-check/action/claimant/create.go index 960fd3201..007e6ac60 100644 --- a/server/service/fact-check/action/claimant/create.go +++ b/server/service/fact-check/action/claimant/create.go @@ -5,11 +5,9 @@ import ( "encoding/json" "errors" "net/http" - "reflect" "github.com/factly/dega-server/config" "github.com/factly/dega-server/service/fact-check/model" - "github.com/factly/dega-server/test" "github.com/factly/dega-server/util" "github.com/factly/x/errorx" "github.com/factly/x/loggerx" @@ -18,6 +16,7 @@ import ( "github.com/factly/x/renderx" "github.com/factly/x/slugx" "github.com/factly/x/validationx" + "github.com/jinzhu/gorm/dialects/postgres" "gorm.io/gorm" ) @@ -92,22 +91,33 @@ func create(w http.ResponseWriter, r *http.Request) { return } - var description string - // Store HTML description - if len(claimant.Description.RawMessage) > 0 && !reflect.DeepEqual(claimant.Description, test.NilJsonb()) { - description, err = util.HTMLDescription(claimant.Description) + var htmlDescription string + var jsonDescription postgres.Jsonb + if len(claimant.Description.RawMessage) > 0 { + htmlDescription, err = util.GetHTMLDescription(claimant.Description) if err != nil { loggerx.Error(err) - errorx.Render(w, errorx.Parser(errorx.GetMessage("cannot parse claimant description", http.StatusUnprocessableEntity))) + errorx.Render(w, errorx.Parser(errorx.DecodeError())) + return + } + + jsonDescription, err = util.GetJSONDescription(claimant.Description) + if err != nil { + loggerx.Error(err) + errorx.Render(w, errorx.Parser(errorx.DecodeError())) return } } result := &model.Claimant{ + Base: config.Base{ + CreatedAt: claimant.CreatedAt, + UpdatedAt: claimant.UpdatedAt, + }, Name: claimant.Name, Slug: slugx.Approve(&config.DB, claimantSlug, sID, tableName), - Description: claimant.Description, - HTMLDescription: description, + Description: jsonDescription, + HTMLDescription: htmlDescription, MediumID: mediumID, IsFeatured: claimant.IsFeatured, SpaceID: uint(sID), diff --git a/server/service/fact-check/action/claimant/route.go b/server/service/fact-check/action/claimant/route.go index 02c433d9e..c6699e71c 100644 --- a/server/service/fact-check/action/claimant/route.go +++ b/server/service/fact-check/action/claimant/route.go @@ -1,6 +1,8 @@ package claimant import ( + "time" + "github.com/factly/dega-server/config" "github.com/factly/dega-server/util" "github.com/go-chi/chi" @@ -9,6 +11,8 @@ import ( // claimant model type claimant struct { + CreatedAt time.Time `json:"created_at"` + UpdatedAt time.Time `json:"updated_at"` Name string `json:"name" validate:"required,max=500"` Slug string `json:"slug"` IsFeatured bool `json:"is_featured"` diff --git a/server/service/fact-check/action/claimant/update.go b/server/service/fact-check/action/claimant/update.go index acac88b43..b1fa011c8 100644 --- a/server/service/fact-check/action/claimant/update.go +++ b/server/service/fact-check/action/claimant/update.go @@ -4,13 +4,11 @@ import ( "encoding/json" "errors" "net/http" - "reflect" "strconv" "time" "github.com/factly/dega-server/config" "github.com/factly/dega-server/service/fact-check/model" - "github.com/factly/dega-server/test" "github.com/factly/dega-server/util" "github.com/factly/x/errorx" "github.com/factly/x/loggerx" @@ -20,6 +18,7 @@ import ( "github.com/factly/x/slugx" "github.com/factly/x/validationx" "github.com/go-chi/chi" + "github.com/jinzhu/gorm/dialects/postgres" "gorm.io/gorm" ) @@ -114,25 +113,33 @@ func update(w http.ResponseWriter, r *http.Request) { return } - // Store HTML description - var description string - if len(claimant.Description.RawMessage) > 0 && !reflect.DeepEqual(claimant.Description, test.NilJsonb()) { - description, err = util.HTMLDescription(claimant.Description) + var htmlDescription string + var jsonDescription postgres.Jsonb + if len(claimant.Description.RawMessage) > 0 { + htmlDescription, err = util.GetHTMLDescription(claimant.Description) if err != nil { loggerx.Error(err) - errorx.Render(w, errorx.Parser(errorx.GetMessage("cannot parse claimant description", http.StatusUnprocessableEntity))) + errorx.Render(w, errorx.Parser(errorx.DecodeError())) + return + } + + jsonDescription, err = util.GetJSONDescription(claimant.Description) + if err != nil { + loggerx.Error(err) + errorx.Render(w, errorx.Parser(errorx.DecodeError())) return } } tx := config.DB.Begin() updateMap := map[string]interface{}{ - "updated_at": time.Now(), + "created_at": claimant.CreatedAt, + "updated_at": claimant.UpdatedAt, "updated_by_id": uID, "name": claimant.Name, "slug": claimantSlug, - "description": claimant.Description, - "html_description": description, + "description": jsonDescription, + "html_description": htmlDescription, "medium_id": claimant.MediumID, "tag_line": claimant.TagLine, "is_featured": claimant.IsFeatured, @@ -145,6 +152,14 @@ func update(w http.ResponseWriter, r *http.Request) { updateMap["medium_id"] = nil } + if claimant.CreatedAt.IsZero() { + updateMap["created_at"] = result.CreatedAt + } + + if claimant.UpdatedAt.IsZero() { + updateMap["updated_at"] = time.Now() + } + err = tx.Model(&result).Updates(&updateMap).Preload("Medium").First(&result).Error if err != nil { diff --git a/server/service/fact-check/action/rating/create.go b/server/service/fact-check/action/rating/create.go index 2e02eecf8..f5f08f98c 100644 --- a/server/service/fact-check/action/rating/create.go +++ b/server/service/fact-check/action/rating/create.go @@ -5,11 +5,9 @@ import ( "encoding/json" "errors" "net/http" - "reflect" "github.com/factly/dega-server/config" "github.com/factly/dega-server/service/fact-check/model" - "github.com/factly/dega-server/test" "github.com/factly/dega-server/util" "github.com/factly/x/errorx" "github.com/factly/x/loggerx" @@ -18,6 +16,7 @@ import ( "github.com/factly/x/renderx" "github.com/factly/x/slugx" "github.com/factly/x/validationx" + "github.com/jinzhu/gorm/dialects/postgres" "gorm.io/gorm" ) @@ -105,24 +104,35 @@ func create(w http.ResponseWriter, r *http.Request) { mediumID = nil } - // Store HTML description - var description string - if len(rating.Description.RawMessage) > 0 && !reflect.DeepEqual(rating.Description, test.NilJsonb()) { - description, err = util.HTMLDescription(rating.Description) + var htmlDescription string + var jsonDescription postgres.Jsonb + if len(rating.Description.RawMessage) > 0 { + htmlDescription, err = util.GetHTMLDescription(rating.Description) if err != nil { loggerx.Error(err) - errorx.Render(w, errorx.Parser(errorx.GetMessage("cannot parse rating description", http.StatusUnprocessableEntity))) + errorx.Render(w, errorx.Parser(errorx.DecodeError())) + return + } + + jsonDescription, err = util.GetJSONDescription(rating.Description) + if err != nil { + loggerx.Error(err) + errorx.Render(w, errorx.Parser(errorx.DecodeError())) return } } result := &model.Rating{ + Base: config.Base{ + CreatedAt: rating.CreatedAt, + UpdatedAt: rating.UpdatedAt, + }, Name: rating.Name, Slug: slugx.Approve(&config.DB, ratingSlug, sID, tableName), BackgroundColour: rating.BackgroundColour, TextColour: rating.TextColour, - Description: rating.Description, - HTMLDescription: description, + Description: jsonDescription, + HTMLDescription: htmlDescription, MediumID: mediumID, SpaceID: uint(sID), NumericValue: rating.NumericValue, diff --git a/server/service/fact-check/action/rating/default.go b/server/service/fact-check/action/rating/default.go index a6451bf36..8508d3c69 100644 --- a/server/service/fact-check/action/rating/default.go +++ b/server/service/fact-check/action/rating/default.go @@ -69,7 +69,15 @@ func createDefaults(w http.ResponseWriter, r *http.Request) { for i := range ratings { ratings[i].SpaceID = uint(sID) - ratings[i].HTMLDescription, err = util.HTMLDescription(ratings[i].Description) + ratings[i].HTMLDescription, err = util.GetHTMLDescription(ratings[i].Description) + if err != nil { + tx.Rollback() + loggerx.Error(err) + errorx.Render(w, errorx.Parser(errorx.GetMessage("cannot parse rating description", http.StatusUnprocessableEntity))) + return + } + + ratings[i].Description, err = util.GetJSONDescription(ratings[i].Description) if err != nil { tx.Rollback() loggerx.Error(err) diff --git a/server/service/fact-check/action/rating/route.go b/server/service/fact-check/action/rating/route.go index 9b0fc9479..fbf09d192 100644 --- a/server/service/fact-check/action/rating/route.go +++ b/server/service/fact-check/action/rating/route.go @@ -1,6 +1,8 @@ package rating import ( + "time" + "github.com/factly/dega-server/config" "github.com/factly/dega-server/util" "github.com/go-chi/chi" @@ -9,6 +11,8 @@ import ( // rating model type rating struct { + CreatedAt time.Time `json:"created_at"` + UpdatedAt time.Time `json:"updated_at"` Name string `json:"name" validate:"required,max=500"` Slug string `json:"slug"` BackgroundColour postgres.Jsonb `json:"background_colour" validate:"required" swaggertype:"primitive,string"` diff --git a/server/service/fact-check/action/rating/update.go b/server/service/fact-check/action/rating/update.go index 0d94313ad..b628aed6b 100644 --- a/server/service/fact-check/action/rating/update.go +++ b/server/service/fact-check/action/rating/update.go @@ -4,12 +4,10 @@ import ( "encoding/json" "errors" "net/http" - "reflect" "strconv" "github.com/factly/dega-server/config" "github.com/factly/dega-server/service/fact-check/model" - "github.com/factly/dega-server/test" "github.com/factly/dega-server/util" "github.com/factly/x/errorx" "github.com/factly/x/loggerx" @@ -19,6 +17,7 @@ import ( "github.com/factly/x/slugx" "github.com/factly/x/validationx" "github.com/go-chi/chi" + "github.com/jinzhu/gorm/dialects/postgres" "gorm.io/gorm" ) @@ -127,47 +126,49 @@ func update(w http.ResponseWriter, r *http.Request) { } } - // Store HTML description - var description string - if len(rating.Description.RawMessage) > 0 && !reflect.DeepEqual(rating.Description, test.NilJsonb()) { - description, err = util.HTMLDescription(rating.Description) + var htmlDescription string + var jsonDescription postgres.Jsonb + if len(rating.Description.RawMessage) > 0 { + htmlDescription, err = util.GetHTMLDescription(rating.Description) if err != nil { loggerx.Error(err) - errorx.Render(w, errorx.Parser(errorx.GetMessage("cannot parse rating description", http.StatusUnprocessableEntity))) + errorx.Render(w, errorx.Parser(errorx.DecodeError())) return } - } - - tx := config.DB.Begin() - mediumID := &rating.MediumID - result.MediumID = &rating.MediumID - if rating.MediumID == 0 { - err = tx.Model(&result).Updates(map[string]interface{}{"medium_id": nil}).Error - mediumID = nil + jsonDescription, err = util.GetJSONDescription(rating.Description) if err != nil { - tx.Rollback() loggerx.Error(err) - errorx.Render(w, errorx.Parser(errorx.DBError())) + errorx.Render(w, errorx.Parser(errorx.DecodeError())) return } } - err = tx.Model(&result).Updates(model.Rating{ - Base: config.Base{UpdatedByID: uint(uID)}, - Name: rating.Name, - Slug: ratingSlug, - BackgroundColour: rating.BackgroundColour, - TextColour: rating.TextColour, - MediumID: mediumID, - Description: rating.Description, - HTMLDescription: description, - NumericValue: rating.NumericValue, - MetaFields: rating.MetaFields, - Meta: rating.Meta, - HeaderCode: rating.HeaderCode, - FooterCode: rating.FooterCode, - }).Preload("Medium").First(&result).Error + tx := config.DB.Begin() + + updateMap := map[string]interface{}{ + "created_at": rating.CreatedAt, + "updated_at": rating.UpdatedAt, + "updated_by_id": uint(uID), + "name": rating.Name, + "slug": ratingSlug, + "background_colour": rating.BackgroundColour, + "text_colour": rating.TextColour, + "medium_id": rating.MediumID, + "description": jsonDescription, + "html_description": htmlDescription, + "numeric_value": rating.NumericValue, + "meta_fields": rating.MetaFields, + "meta": rating.Meta, + "header_code": rating.HeaderCode, + "footer_code": rating.FooterCode, + } + + if rating.MediumID == 0 { + updateMap["medium_id"] = nil + } + + err = tx.Model(&result).Updates(&updateMap).Preload("Medium").First(&result).Error if err != nil { tx.Rollback() diff --git a/server/service/podcast/action/create.go b/server/service/podcast/action/create.go index a74d55ae4..a59d4de48 100644 --- a/server/service/podcast/action/create.go +++ b/server/service/podcast/action/create.go @@ -5,12 +5,10 @@ import ( "encoding/json" "errors" "net/http" - "reflect" "github.com/factly/dega-server/config" coreModel "github.com/factly/dega-server/service/core/model" "github.com/factly/dega-server/service/podcast/model" - "github.com/factly/dega-server/test" "github.com/factly/dega-server/util" "github.com/factly/x/errorx" "github.com/factly/x/loggerx" @@ -19,6 +17,7 @@ import ( "github.com/factly/x/renderx" "github.com/factly/x/slugx" "github.com/factly/x/validationx" + "github.com/jinzhu/gorm/dialects/postgres" "gorm.io/gorm" ) @@ -99,20 +98,32 @@ func create(w http.ResponseWriter, r *http.Request) { } // Store HTML description - var description string - if len(podcast.Description.RawMessage) > 0 && !reflect.DeepEqual(podcast.Description, test.NilJsonb()) { - description, err = util.HTMLDescription(podcast.Description) + var htmlDescription string + var jsonDescription postgres.Jsonb + if len(podcast.Description.RawMessage) > 0 { + htmlDescription, err = util.GetHTMLDescription(podcast.Description) if err != nil { loggerx.Error(err) - errorx.Render(w, errorx.Parser(errorx.GetMessage("cannot parse podcast description", http.StatusUnprocessableEntity))) + errorx.Render(w, errorx.Parser(errorx.DecodeError())) + return + } + + jsonDescription, err = util.GetJSONDescription(podcast.Description) + if err != nil { + loggerx.Error(err) + errorx.Render(w, errorx.Parser(errorx.DecodeError())) return } } result := &model.Podcast{ + Base: config.Base{ + CreatedAt: podcast.CreatedAt, + UpdatedAt: podcast.UpdatedAt, + }, Title: podcast.Title, - Description: podcast.Description, - HTMLDescription: description, + Description: jsonDescription, + HTMLDescription: htmlDescription, Slug: slugx.Approve(&config.DB, podcastSlug, sID, tableName), Language: podcast.Language, MediumID: mediumID, diff --git a/server/service/podcast/action/episode/create.go b/server/service/podcast/action/episode/create.go index 9352ef1dc..46fa1e12c 100644 --- a/server/service/podcast/action/episode/create.go +++ b/server/service/podcast/action/episode/create.go @@ -6,13 +6,12 @@ import ( "errors" "fmt" "net/http" - "reflect" "github.com/factly/dega-server/config" "github.com/factly/dega-server/service/core/action/author" "github.com/factly/dega-server/service/podcast/model" - "github.com/factly/dega-server/test" "github.com/factly/dega-server/util" + "github.com/jinzhu/gorm/dialects/postgres" "github.com/factly/x/errorx" "github.com/factly/x/loggerx" @@ -92,21 +91,33 @@ func create(w http.ResponseWriter, r *http.Request) { podcastID = nil } - // Store HTML description - var description string - if len(episode.Description.RawMessage) > 0 && !reflect.DeepEqual(episode.Description, test.NilJsonb()) { - description, err = util.HTMLDescription(episode.Description) + var htmlDescription string + var jsonDescription postgres.Jsonb + if len(episode.Description.RawMessage) > 0 { + htmlDescription, err = util.GetHTMLDescription(episode.Description) if err != nil { loggerx.Error(err) - errorx.Render(w, errorx.Parser(errorx.GetMessage("cannot parse episode description", http.StatusUnprocessableEntity))) + errorx.Render(w, errorx.Parser(errorx.DecodeError())) + return + } + + jsonDescription, err = util.GetJSONDescription(episode.Description) + if err != nil { + loggerx.Error(err) + errorx.Render(w, errorx.Parser(errorx.DecodeError())) return } } + result := &episodeData{} result.Episode = model.Episode{ + Base: config.Base{ + CreatedAt: episode.CreatedAt, + UpdatedAt: episode.UpdatedAt, + }, Title: episode.Title, - Description: episode.Description, - HTMLDescription: description, + Description: jsonDescription, + HTMLDescription: htmlDescription, Slug: slugx.Approve(&config.DB, episodeSlug, sID, tableName), Season: episode.Season, Episode: episode.Episode, diff --git a/server/service/podcast/action/episode/route.go b/server/service/podcast/action/episode/route.go index 8754b18a8..d3f12f639 100644 --- a/server/service/podcast/action/episode/route.go +++ b/server/service/podcast/action/episode/route.go @@ -13,6 +13,8 @@ import ( // episode model type episode struct { + CreatedAt time.Time `json:"created_at"` + UpdatedAt time.Time `json:"updated_at"` Title string `json:"title" validate:"required,max=500"` Slug string `json:"slug"` Season int `json:"season" validate:"required"` diff --git a/server/service/podcast/action/episode/update.go b/server/service/podcast/action/episode/update.go index cb9e53cc1..742913f94 100644 --- a/server/service/podcast/action/episode/update.go +++ b/server/service/podcast/action/episode/update.go @@ -5,13 +5,11 @@ import ( "errors" "fmt" "net/http" - "reflect" "strconv" "github.com/factly/dega-server/config" "github.com/factly/dega-server/service/core/action/author" "github.com/factly/dega-server/service/podcast/model" - "github.com/factly/dega-server/test" "github.com/factly/dega-server/util" "github.com/factly/dega-server/util/arrays" "github.com/factly/x/errorx" @@ -22,6 +20,7 @@ import ( "github.com/factly/x/slugx" "github.com/factly/x/validationx" "github.com/go-chi/chi" + "github.com/jinzhu/gorm/dialects/postgres" "gorm.io/gorm" ) @@ -109,144 +108,138 @@ func update(w http.ResponseWriter, r *http.Request) { episodeSlug = slugx.Approve(&config.DB, slugx.Make(episode.Title), sID, tableName) } - // Store HTML description - var description string - if len(episode.Description.RawMessage) > 0 && !reflect.DeepEqual(episode.Description, test.NilJsonb()) { - description, err = util.HTMLDescription(episode.Description) + var htmlDescription string + var jsonDescription postgres.Jsonb + if len(episode.Description.RawMessage) > 0 { + htmlDescription, err = util.GetHTMLDescription(episode.Description) if err != nil { loggerx.Error(err) - errorx.Render(w, errorx.Parser(errorx.GetMessage("cannot parse episode description", http.StatusUnprocessableEntity))) + errorx.Render(w, errorx.Parser(errorx.DecodeError())) return } - } - tx := config.DB.Begin() - mediumID := &episode.MediumID - result.MediumID = &episode.MediumID - if episode.MediumID == 0 { - err = tx.Model(&result.Episode).Updates(map[string]interface{}{"medium_id": nil}).Error - mediumID = nil + jsonDescription, err = util.GetJSONDescription(episode.Description) if err != nil { - tx.Rollback() loggerx.Error(err) - errorx.Render(w, errorx.Parser(errorx.DBError())) + errorx.Render(w, errorx.Parser(errorx.DecodeError())) return } - } - podcastID := &episode.PodcastID - result.PodcastID = &episode.PodcastID - if episode.PodcastID == 0 { - err = tx.Model(&result.Episode).Updates(map[string]interface{}{"podcast_id": nil}).Error - podcastID = nil - if err != nil { - tx.Rollback() - loggerx.Error(err) - errorx.Render(w, errorx.Parser(errorx.DBError())) - return + tx := config.DB.Begin() + + updateMap := map[string]interface{}{ + "created_at": episode.CreatedAt, + "updated_at": episode.UpdatedAt, + "updated_by_id": uint(uID), + "title": episode.Title, + "slug": episodeSlug, + "html_description": htmlDescription, + "description": jsonDescription, + "season": episode.Season, + "episode": episode.Episode, + "audio_url": episode.AudioURL, + "podcast_id": episode.PodcastID, + "published_date": episode.PublishedDate, + "medium_id": episode.MediumID, + "meta_fields": episode.MetaFields, } - } - tx.Model(&result.Episode).Select("PublishedDate").Updates(model.Episode{PublishedDate: episode.PublishedDate}) - tx.Model(&result.Episode).Updates(model.Episode{ - Base: config.Base{UpdatedByID: uint(uID)}, - Title: episode.Title, - HTMLDescription: description, - Description: episode.Description, - Slug: slugx.Approve(&config.DB, episodeSlug, sID, tableName), - Season: episode.Season, - Episode: episode.Episode, - AudioURL: episode.AudioURL, - PodcastID: podcastID, - MediumID: mediumID, - MetaFields: episode.MetaFields, - }).Preload("Medium").Preload("Podcast").Preload("Podcast.Medium").First(&result.Episode) - - // fetch old authors - prevEpisodeAuthors := make([]model.EpisodeAuthor, 0) - tx.Model(&model.EpisodeAuthor{}).Where(&model.EpisodeAuthor{ - EpisodeID: uint(result.Episode.ID), - }).Find(&prevEpisodeAuthors) - - prevAuthorIDs := make([]uint, 0) - for _, each := range prevEpisodeAuthors { - prevAuthorIDs = append(prevAuthorIDs, each.AuthorID) - } + if episode.MediumID == 0 { + updateMap["medium_id"] = nil + } - toCreateIDs, toDeleteIDs := arrays.Difference(prevAuthorIDs, episode.AuthorIDs) + if episode.PodcastID == 0 { + updateMap["podcast_id"] = nil + } - if len(toDeleteIDs) > 0 { - tx.Model(&model.EpisodeAuthor{}).Where("author_id IN (?)", toDeleteIDs).Delete(&model.EpisodeAuthor{}) - } + tx.Model(&result.Episode).Updates(&updateMap).Preload("Medium").Preload("Podcast").Preload("Podcast.Medium").First(&result.Episode) + + // fetch old authors + prevEpisodeAuthors := make([]model.EpisodeAuthor, 0) + tx.Model(&model.EpisodeAuthor{}).Where(&model.EpisodeAuthor{ + EpisodeID: uint(result.Episode.ID), + }).Find(&prevEpisodeAuthors) + + prevAuthorIDs := make([]uint, 0) + for _, each := range prevEpisodeAuthors { + prevAuthorIDs = append(prevAuthorIDs, each.AuthorID) + } + + toCreateIDs, toDeleteIDs := arrays.Difference(prevAuthorIDs, episode.AuthorIDs) + + if len(toDeleteIDs) > 0 { + tx.Model(&model.EpisodeAuthor{}).Where("author_id IN (?)", toDeleteIDs).Delete(&model.EpisodeAuthor{}) + } + + if len(toCreateIDs) > 0 { + createEpisodeAuthors := make([]model.EpisodeAuthor, 0) + for _, each := range toCreateIDs { + epiAuth := model.EpisodeAuthor{ + EpisodeID: uint(result.Episode.ID), + AuthorID: each, + } + createEpisodeAuthors = append(createEpisodeAuthors, epiAuth) + } - if len(toCreateIDs) > 0 { - createEpisodeAuthors := make([]model.EpisodeAuthor, 0) - for _, each := range toCreateIDs { - epiAuth := model.EpisodeAuthor{ - EpisodeID: uint(result.Episode.ID), - AuthorID: each, + if err = tx.Model(&model.EpisodeAuthor{}).Create(&createEpisodeAuthors).Error; err != nil { + tx.Rollback() + loggerx.Error(err) + errorx.Render(w, errorx.Parser(errorx.DBError())) + return } - createEpisodeAuthors = append(createEpisodeAuthors, epiAuth) } - if err = tx.Model(&model.EpisodeAuthor{}).Create(&createEpisodeAuthors).Error; err != nil { - tx.Rollback() + // Fetch current authors + authorMap, err := author.All(r.Context()) + if err != nil { loggerx.Error(err) errorx.Render(w, errorx.Parser(errorx.DBError())) return } - } - - // Fetch current authors - authorMap, err := author.All(r.Context()) - if err != nil { - loggerx.Error(err) - errorx.Render(w, errorx.Parser(errorx.DBError())) - return - } - authorEpisodes := make([]model.EpisodeAuthor, 0) - tx.Model(&model.EpisodeAuthor{}).Where(&model.EpisodeAuthor{ - EpisodeID: uint(id), - }).Find(&authorEpisodes) + authorEpisodes := make([]model.EpisodeAuthor, 0) + tx.Model(&model.EpisodeAuthor{}).Where(&model.EpisodeAuthor{ + EpisodeID: uint(id), + }).Find(&authorEpisodes) - for _, each := range authorEpisodes { - result.Authors = append(result.Authors, authorMap[fmt.Sprint(each.AuthorID)]) - } + for _, each := range authorEpisodes { + result.Authors = append(result.Authors, authorMap[fmt.Sprint(each.AuthorID)]) + } - // Update into meili index - var publishedDate int64 - if result.PublishedDate == nil { - publishedDate = 0 - } else { - publishedDate = result.PublishedDate.Unix() - } - meiliObj := map[string]interface{}{ - "id": result.Episode.ID, - "kind": "episode", - "title": result.Title, - "slug": result.Slug, - "season": result.Season, - "episode": result.Episode, - "audio_url": result.AudioURL, - "podcast_id": result.PodcastID, - "description": result.Description, - "published_date": publishedDate, - "space_id": result.SpaceID, - "medium_id": result.MediumID, - } + // Update into meili index + var publishedDate int64 + if result.PublishedDate == nil { + publishedDate = 0 + } else { + publishedDate = result.PublishedDate.Unix() + } + meiliObj := map[string]interface{}{ + "id": result.Episode.ID, + "kind": "episode", + "title": result.Title, + "slug": result.Slug, + "season": result.Season, + "episode": result.Episode, + "audio_url": result.AudioURL, + "podcast_id": result.PodcastID, + "description": result.Description, + "published_date": publishedDate, + "space_id": result.SpaceID, + "medium_id": result.MediumID, + } - if config.SearchEnabled() { - _ = meilisearchx.UpdateDocument("dega", meiliObj) - } + if config.SearchEnabled() { + _ = meilisearchx.UpdateDocument("dega", meiliObj) + } - tx.Commit() - if util.CheckNats() { - if err = util.NC.Publish("episode.updated", result); err != nil { - loggerx.Error(err) - errorx.Render(w, errorx.Parser(errorx.InternalServerError())) - return + tx.Commit() + if util.CheckNats() { + if err = util.NC.Publish("episode.updated", result); err != nil { + loggerx.Error(err) + errorx.Render(w, errorx.Parser(errorx.InternalServerError())) + return + } } + renderx.JSON(w, http.StatusOK, result) } - renderx.JSON(w, http.StatusOK, result) } diff --git a/server/service/podcast/action/route.go b/server/service/podcast/action/route.go index 0acd41519..e32453052 100644 --- a/server/service/podcast/action/route.go +++ b/server/service/podcast/action/route.go @@ -1,6 +1,8 @@ package podcast import ( + "time" + "github.com/factly/dega-server/config" "github.com/factly/dega-server/util" "github.com/go-chi/chi" @@ -9,6 +11,8 @@ import ( // podcast model type podcast struct { + CreatedAt time.Time `json:"created_at"` + UpdatedAt time.Time `json:"updated_at"` Title string `json:"title" validate:"required,max=500"` Slug string `json:"slug"` Language string `json:"language" validate:"required"` diff --git a/server/service/podcast/action/update.go b/server/service/podcast/action/update.go index db5a72281..2b056207b 100644 --- a/server/service/podcast/action/update.go +++ b/server/service/podcast/action/update.go @@ -4,13 +4,11 @@ import ( "encoding/json" "errors" "net/http" - "reflect" "strconv" "github.com/factly/dega-server/config" coreModel "github.com/factly/dega-server/service/core/model" "github.com/factly/dega-server/service/podcast/model" - "github.com/factly/dega-server/test" "github.com/factly/dega-server/util" "github.com/factly/x/errorx" "github.com/factly/x/loggerx" @@ -20,6 +18,7 @@ import ( "github.com/factly/x/slugx" "github.com/factly/x/validationx" "github.com/go-chi/chi" + "github.com/jinzhu/gorm/dialects/postgres" "gorm.io/gorm" ) @@ -114,13 +113,20 @@ func update(w http.ResponseWriter, r *http.Request) { return } - // Store HTML description - var description string - if len(podcast.Description.RawMessage) > 0 && !reflect.DeepEqual(podcast.Description, test.NilJsonb()) { - description, err = util.HTMLDescription(podcast.Description) + var htmlDescription string + var jsonDescription postgres.Jsonb + if len(podcast.Description.RawMessage) > 0 { + htmlDescription, err = util.GetHTMLDescription(podcast.Description) if err != nil { loggerx.Error(err) - errorx.Render(w, errorx.Parser(errorx.GetMessage("cannot parse podcast description", http.StatusUnprocessableEntity))) + errorx.Render(w, errorx.Parser(errorx.DecodeError())) + return + } + + jsonDescription, err = util.GetJSONDescription(podcast.Description) + if err != nil { + loggerx.Error(err) + errorx.Render(w, errorx.Parser(errorx.DecodeError())) return } } @@ -140,44 +146,31 @@ func update(w http.ResponseWriter, r *http.Request) { _ = config.DB.Model(&result).Association("Categories").Clear() } - mediumID := &podcast.MediumID - result.MediumID = &podcast.MediumID + updateMap := map[string]interface{}{ + "created_at": podcast.CreatedAt, + "updated_at": podcast.UpdatedAt, + "updated_by_id": uint(uID), + "title": podcast.Title, + "slug": podcastSlug, + "html_description": htmlDescription, + "description": jsonDescription, + "medium_id": podcast.MediumID, + "meta_fields": podcast.MetaFields, + "language": podcast.Language, + "primary_category_id": podcast.PrimaryCategoryID, + "header_code": podcast.HeaderCode, + "footer_code": podcast.FooterCode, + } + if podcast.MediumID == 0 { - err = tx.Model(&result).Omit("Categories").Updates(map[string]interface{}{"medium_id": nil}).Error - mediumID = nil - if err != nil { - tx.Rollback() - loggerx.Error(err) - errorx.Render(w, errorx.Parser(errorx.DBError())) - return - } + updateMap["medium_id"] = nil } - primaryCategoryID := &podcast.PrimaryCategoryID - result.PrimaryCategoryID = &podcast.PrimaryCategoryID if podcast.PrimaryCategoryID == 0 { - err = tx.Model(&result).Omit("Categories").Updates(map[string]interface{}{"primary_category_id": nil}).Error - primaryCategoryID = nil - if err != nil { - tx.Rollback() - loggerx.Error(err) - errorx.Render(w, errorx.Parser(errorx.DBError())) - return - } + updateMap["primary_category_id"] = nil } - tx.Model(&result).Omit("Categories").Updates(model.Podcast{ - Base: config.Base{UpdatedByID: uint(uID)}, - HTMLDescription: description, - Description: podcast.Description, - Slug: slugx.Approve(&config.DB, podcastSlug, sID, tableName), - Language: podcast.Language, - MediumID: mediumID, - PrimaryCategoryID: primaryCategoryID, - HeaderCode: podcast.HeaderCode, - FooterCode: podcast.FooterCode, - MetaFields: podcast.MetaFields, - }).Preload("Categories").Preload("Medium").First(&result) + tx.Model(&result).Omit("Categories").Updates(&updateMap).Preload("Categories").Preload("Medium").First(&result) // Update into meili index meiliObj := map[string]interface{}{ diff --git a/server/util/description.go b/server/util/description.go deleted file mode 100644 index 7268a097f..000000000 --- a/server/util/description.go +++ /dev/null @@ -1,21 +0,0 @@ -package util - -import ( - "encoding/json" - - "github.com/factly/x/editorx" - "github.com/jinzhu/gorm/dialects/postgres" -) - -func HTMLDescription(jsonData postgres.Jsonb) (string, error) { - editorjsBlocks := make(map[string]interface{}) - err := json.Unmarshal(jsonData.RawMessage, &editorjsBlocks) - if err != nil { - return "", err - } - description, err := editorx.EditorjsToHTML(editorjsBlocks) - if err != nil { - return "", err - } - return description, nil -} diff --git a/server/util/scooter.go b/server/util/scooter.go new file mode 100644 index 000000000..27a9391d8 --- /dev/null +++ b/server/util/scooter.go @@ -0,0 +1,30 @@ +package util + +import ( + "encoding/json" + + "github.com/jinzhu/gorm/dialects/postgres" +) + +type Description struct { + HTML string + JSON postgres.Jsonb +} + +func GetHTMLDescription(jsonData postgres.Jsonb) (string, error) { + var description Description + err := json.Unmarshal(jsonData.RawMessage, &description) + if err != nil { + return "", err + } + return description.HTML, nil +} + +func GetJSONDescription(jsonData postgres.Jsonb) (postgres.Jsonb, error) { + var description Description + err := json.Unmarshal(jsonData.RawMessage, &description) + if err != nil { + return postgres.Jsonb{}, err + } + return description.JSON, nil +} diff --git a/studio/.npmrc b/studio/.npmrc new file mode 100644 index 000000000..521a9f7c0 --- /dev/null +++ b/studio/.npmrc @@ -0,0 +1 @@ +legacy-peer-deps=true diff --git a/studio/package-lock.json b/studio/package-lock.json index 7ccd30bb4..4ec03bc5b 100644 --- a/studio/package-lock.json +++ b/studio/package-lock.json @@ -17,6 +17,7 @@ "@editorjs/quote": "^2.3.0", "@editorjs/raw": "^2.1.2", "@editorjs/table": "^1.2.2", + "@factly/scooter": "^0.0.7", "@testing-library/jest-dom": "^4.2.4", "@testing-library/react": "^9.5.0", "@testing-library/user-event": "^7.2.1", @@ -2372,6 +2373,15 @@ "resolved": "https://registry.npmjs.org/@editorjs/table/-/table-1.3.0.tgz", "integrity": "sha512-3/gr7IkjsYuECndCpcBSKzZQHos7C9QU1ach8avyVbXB3VLAa1RyGjgocu0Ct4d02HdxirrYZ7+vP1Na+s04GQ==" }, + "node_modules/@factly/scooter": { + "version": "0.0.7", + "resolved": "https://registry.npmjs.org/@factly/scooter/-/scooter-0.0.7.tgz", + "integrity": "sha512-qkK7me6DuQUBMBBzGOq5xrFQdR8qae6r3S+QMFIoDCuzBZHRxgcTRpW3VQmHh+q6hQvn3uEY6WBtUiwgUHxjoA==", + "peerDependencies": { + "react": "^18.2.0", + "react-dom": "^18.2.0" + } + }, "node_modules/@hapi/address": { "version": "2.1.4", "resolved": "https://registry.npmjs.org/@hapi/address/-/address-2.1.4.tgz", @@ -11423,11 +11433,22 @@ } }, "node_modules/follow-redirects": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.1.tgz", - "integrity": "sha512-HWqDgT7ZEkqRzBvc2s64vSZ/hfOceEol3ac/7tKwzuvEyWx3/4UegXh5oBOIotkGsObyk3xznnSRVADBgWSQVg==", + "version": "1.15.1", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.1.tgz", + "integrity": "sha512-yLAMQs+k0b2m7cVxpS1VKJVvoz7SS9Td1zss3XRwXj+ZDH00RJgnuLx7E44wx02kQLrdM3aOOy+FpzS7+8OizA==", + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/RubenVerborgh" + } + ], "engines": { "node": ">=4.0" + }, + "peerDependenciesMeta": { + "debug": { + "optional": true + } } }, "node_modules/for-in": { @@ -16015,6 +16036,10 @@ "dependencies": { "@babel/runtime": "^7.12.1", "tiny-warning": "^1.0.3" + }, + "peerDependencies": { + "prop-types": "^15.0.0", + "react": "^0.14.0 || ^15.0.0 || ^16.0.0 || ^17.0.0" } }, "node_modules/mini-css-extract-plugin": { @@ -16314,9 +16339,9 @@ "optional": true }, "node_modules/nanoid": { - "version": "3.1.23", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.1.23.tgz", - "integrity": "sha512-FiB0kzdP0FFVGDKlRLEQ1BgDzU87dy5NnzjeW9YZNt+/c3+q82EQDUwniSAUxp/F0gFNI1ZhKU1FqYsMuqZVnw==", + "version": "3.3.4", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.4.tgz", + "integrity": "sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw==", "bin": { "nanoid": "bin/nanoid.cjs" }, @@ -20093,7 +20118,7 @@ "node_modules/path-to-regexp/node_modules/isarray": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", - "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=" + "integrity": "sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ==" }, "node_modules/path-type": { "version": "3.0.0", @@ -22599,11 +22624,11 @@ } }, "node_modules/react-router": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/react-router/-/react-router-5.2.0.tgz", - "integrity": "sha512-smz1DUuFHRKdcJC0jobGo8cVbhO3x50tCL4icacOlcwDOEQPq4TMqwx3sY1TP+DvtTgz4nm3thuo7A+BK2U0Dw==", + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/react-router/-/react-router-5.3.1.tgz", + "integrity": "sha512-v+zwjqb7bakqgF+wMVKlAPTca/cEmPOvQ9zt7gpSNyPXau1+0qvuYZ5BWzzNDP1y6s15zDwgb9rPN63+SIniRQ==", "dependencies": { - "@babel/runtime": "^7.1.2", + "@babel/runtime": "^7.12.13", "history": "^4.9.0", "hoist-non-react-statics": "^3.1.0", "loose-envify": "^1.3.1", @@ -22613,20 +22638,26 @@ "react-is": "^16.6.0", "tiny-invariant": "^1.0.2", "tiny-warning": "^1.0.0" + }, + "peerDependencies": { + "react": ">=15" } }, "node_modules/react-router-dom": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-5.2.0.tgz", - "integrity": "sha512-gxAmfylo2QUjcwxI63RhQ5G85Qqt4voZpUXSEqCwykV0baaOTQDR1f0PmY8AELqIyVc0NEZUj0Gov5lNGcXgsA==", + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-5.3.1.tgz", + "integrity": "sha512-f0pj/gMAbv9e8gahTmCEY20oFhxhrmHwYeIwH5EO5xu0qme+wXtsdB8YfUOAZzUz4VaXmb58m3ceiLtjMhqYmQ==", "dependencies": { - "@babel/runtime": "^7.1.2", + "@babel/runtime": "^7.12.13", "history": "^4.9.0", "loose-envify": "^1.3.1", "prop-types": "^15.6.2", - "react-router": "5.2.0", + "react-router": "5.3.1", "tiny-invariant": "^1.0.2", "tiny-warning": "^1.0.0" + }, + "peerDependencies": { + "react": ">=15" } }, "node_modules/react-scripts": { @@ -25918,9 +25949,9 @@ "integrity": "sha1-QFQRqOfmM5/mTbmiNN4R3DHgK9Q=" }, "node_modules/tiny-invariant": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/tiny-invariant/-/tiny-invariant-1.1.0.tgz", - "integrity": "sha512-ytxQvrb1cPc9WBEI/HSeYYoGD0kWnGEOR8RY6KomWLBVhqz0RgTwVO9dLrGz7dC+nN9llyI7OKAgRq8Vq4ZBSw==" + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/tiny-invariant/-/tiny-invariant-1.2.0.tgz", + "integrity": "sha512-1Uhn/aqw5C6RI4KejVeTg6mIS7IqxnLJ8Mv2tV5rTc0qWobay7pDUz6Wi392Cnc8ak1H0F2cjoRzb2/AW4+Fvg==" }, "node_modules/tiny-warning": { "version": "1.0.3", @@ -29541,6 +29572,11 @@ "resolved": "https://registry.npmjs.org/@editorjs/table/-/table-1.3.0.tgz", "integrity": "sha512-3/gr7IkjsYuECndCpcBSKzZQHos7C9QU1ach8avyVbXB3VLAa1RyGjgocu0Ct4d02HdxirrYZ7+vP1Na+s04GQ==" }, + "@factly/scooter": { + "version": "0.0.7", + "resolved": "https://registry.npmjs.org/@factly/scooter/-/scooter-0.0.7.tgz", + "integrity": "sha512-qkK7me6DuQUBMBBzGOq5xrFQdR8qae6r3S+QMFIoDCuzBZHRxgcTRpW3VQmHh+q6hQvn3uEY6WBtUiwgUHxjoA==" + }, "@hapi/address": { "version": "2.1.4", "resolved": "https://registry.npmjs.org/@hapi/address/-/address-2.1.4.tgz", @@ -37114,9 +37150,9 @@ } }, "follow-redirects": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.1.tgz", - "integrity": "sha512-HWqDgT7ZEkqRzBvc2s64vSZ/hfOceEol3ac/7tKwzuvEyWx3/4UegXh5oBOIotkGsObyk3xznnSRVADBgWSQVg==" + "version": "1.15.1", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.1.tgz", + "integrity": "sha512-yLAMQs+k0b2m7cVxpS1VKJVvoz7SS9Td1zss3XRwXj+ZDH00RJgnuLx7E44wx02kQLrdM3aOOy+FpzS7+8OizA==" }, "for-in": { "version": "1.0.2", @@ -41051,9 +41087,9 @@ "optional": true }, "nanoid": { - "version": "3.1.23", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.1.23.tgz", - "integrity": "sha512-FiB0kzdP0FFVGDKlRLEQ1BgDzU87dy5NnzjeW9YZNt+/c3+q82EQDUwniSAUxp/F0gFNI1ZhKU1FqYsMuqZVnw==" + "version": "3.3.4", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.4.tgz", + "integrity": "sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw==" }, "nanomatch": { "version": "1.2.13", @@ -43867,7 +43903,7 @@ "isarray": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", - "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=" + "integrity": "sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ==" } } }, @@ -45979,11 +46015,11 @@ } }, "react-router": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/react-router/-/react-router-5.2.0.tgz", - "integrity": "sha512-smz1DUuFHRKdcJC0jobGo8cVbhO3x50tCL4icacOlcwDOEQPq4TMqwx3sY1TP+DvtTgz4nm3thuo7A+BK2U0Dw==", + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/react-router/-/react-router-5.3.1.tgz", + "integrity": "sha512-v+zwjqb7bakqgF+wMVKlAPTca/cEmPOvQ9zt7gpSNyPXau1+0qvuYZ5BWzzNDP1y6s15zDwgb9rPN63+SIniRQ==", "requires": { - "@babel/runtime": "^7.1.2", + "@babel/runtime": "^7.12.13", "history": "^4.9.0", "hoist-non-react-statics": "^3.1.0", "loose-envify": "^1.3.1", @@ -45996,15 +46032,15 @@ } }, "react-router-dom": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-5.2.0.tgz", - "integrity": "sha512-gxAmfylo2QUjcwxI63RhQ5G85Qqt4voZpUXSEqCwykV0baaOTQDR1f0PmY8AELqIyVc0NEZUj0Gov5lNGcXgsA==", + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-5.3.1.tgz", + "integrity": "sha512-f0pj/gMAbv9e8gahTmCEY20oFhxhrmHwYeIwH5EO5xu0qme+wXtsdB8YfUOAZzUz4VaXmb58m3ceiLtjMhqYmQ==", "requires": { - "@babel/runtime": "^7.1.2", + "@babel/runtime": "^7.12.13", "history": "^4.9.0", "loose-envify": "^1.3.1", "prop-types": "^15.6.2", - "react-router": "5.2.0", + "react-router": "5.3.1", "tiny-invariant": "^1.0.2", "tiny-warning": "^1.0.0" } @@ -46098,8 +46134,7 @@ "react-side-effect": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/react-side-effect/-/react-side-effect-2.1.1.tgz", - "integrity": "sha512-2FoTQzRNTncBVtnzxFOk2mCpcfxQpenBMbk5kSVBg5UcPqV9fRbgY2zhb7GTWWOlpFmAxhClBDlIq8Rsubz1yQ==", - "requires": {} + "integrity": "sha512-2FoTQzRNTncBVtnzxFOk2mCpcfxQpenBMbk5kSVBg5UcPqV9fRbgY2zhb7GTWWOlpFmAxhClBDlIq8Rsubz1yQ==" }, "react-test-renderer": { "version": "16.14.0", @@ -48709,9 +48744,9 @@ "integrity": "sha1-QFQRqOfmM5/mTbmiNN4R3DHgK9Q=" }, "tiny-invariant": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/tiny-invariant/-/tiny-invariant-1.1.0.tgz", - "integrity": "sha512-ytxQvrb1cPc9WBEI/HSeYYoGD0kWnGEOR8RY6KomWLBVhqz0RgTwVO9dLrGz7dC+nN9llyI7OKAgRq8Vq4ZBSw==" + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/tiny-invariant/-/tiny-invariant-1.2.0.tgz", + "integrity": "sha512-1Uhn/aqw5C6RI4KejVeTg6mIS7IqxnLJ8Mv2tV5rTc0qWobay7pDUz6Wi392Cnc8ak1H0F2cjoRzb2/AW4+Fvg==" }, "tiny-warning": { "version": "1.0.3", diff --git a/studio/package.json b/studio/package.json index ab6022149..37afaabd3 100644 --- a/studio/package.json +++ b/studio/package.json @@ -16,6 +16,7 @@ "@editorjs/quote": "^2.3.0", "@editorjs/raw": "^2.1.2", "@editorjs/table": "^1.2.2", + "@factly/scooter": "^0.0.7", "@testing-library/jest-dom": "^4.2.4", "@testing-library/react": "^9.5.0", "@testing-library/user-event": "^7.2.1", diff --git a/studio/public/config.js b/studio/public/config.js index 7f685ccd9..af754abb5 100644 --- a/studio/public/config.js +++ b/studio/public/config.js @@ -4,3 +4,4 @@ window.REACT_APP_COMPANION_URL = 'http://127.0.0.1:3020'; window.PUBLIC_URL = 'http://127.0.0.1:4455/.factly/dega/studio'; window.REACT_APP_KAVACH_PUBLIC_URL = 'http://127.0.0.1:4455/.factly/kavach/web'; window.REACT_APP_SACH_API_URL = 'https://sach-server.factly.in'; +window.REACT_APP_IFRAMELY_URL = 'http://127.0.0.1:4455/.factly/dega/server/meta'; diff --git a/studio/src/App.js b/studio/src/App.js index dd3b49973..9d8fddfc5 100644 --- a/studio/src/App.js +++ b/studio/src/App.js @@ -1,6 +1,6 @@ import React from 'react'; import { BrowserRouter as Router, Route, Switch, Link } from 'react-router-dom'; -import 'antd/dist/antd.less'; +import 'antd/dist/antd.css'; import BasicLayout from './layouts/basic'; //Routes import routes from './config/routesConfig'; diff --git a/studio/src/components/FormItems/DescriptionInput.js b/studio/src/components/FormItems/DescriptionInput.js index db265cd9d..16a161856 100644 --- a/studio/src/components/FormItems/DescriptionInput.js +++ b/studio/src/components/FormItems/DescriptionInput.js @@ -1,21 +1,42 @@ import React from 'react'; import { Form } from 'antd'; -import Editor from '../Editor'; +import axios from 'axios'; +// import Editor from '../Editor'; +import { Editor } from '@factly/scooter'; +import { MEDIA_API } from '../../constants/media'; const DescriptionInput = ({ name = 'description', label = 'Description', noLabel = false, - onChange = () => {}, + onChange = (data) => console.log({ data }), inputProps, formItemProps, + initialValue, }) => { inputProps = { ...inputProps, onChange }; formItemProps = noLabel ? formItemProps : { ...formItemProps, label }; return ( - + {/* */} + console.log({ json, html })} + {...inputProps} + initialValue={initialValue} + uploadEndpoint={window.REACT_APP_COMPANION_URL} + iframelyEndpoint={window.REACT_APP_IFRAMELY_URL} + imagesFetcher={(currentPage) => + axios + .get(MEDIA_API, { + params: { page: currentPage, limit: 12 }, + }) + .then((res) => res.data) + } + /> ); }; diff --git a/studio/src/pages/categories/components/CategoryForm.js b/studio/src/pages/categories/components/CategoryForm.js index 2ec0c0196..16bf14ed1 100644 --- a/studio/src/pages/categories/components/CategoryForm.js +++ b/studio/src/pages/categories/components/CategoryForm.js @@ -114,7 +114,7 @@ const CategoryForm = ({ onCreate, data = {} }) => { @@ -198,6 +198,7 @@ const CategoryForm = ({ onCreate, data = {} }) => { placeholder: 'Enter Description...', basic: true, }} + initialValue={formData.description} /> diff --git a/studio/src/pages/categories/index.js b/studio/src/pages/categories/index.js index 8ab89a5f1..085cb01a2 100644 --- a/studio/src/pages/categories/index.js +++ b/studio/src/pages/categories/index.js @@ -79,6 +79,11 @@ function Categories({ permission }) { style={{ width: '100%' }} onValuesChange={(changedValues, allValues) => { if (!changedValues.q) { + if (changedValues.q === '') { + const { q, ...filtersWithoutQuery } = filters; + setFilters({ ...filtersWithoutQuery }); + return; + } setFilters({ ...filters, ...changedValues }); } }} diff --git a/studio/src/pages/claimants/components/ClaimantForm.js b/studio/src/pages/claimants/components/ClaimantForm.js index 51e62a0b6..ce0b298ab 100644 --- a/studio/src/pages/claimants/components/ClaimantForm.js +++ b/studio/src/pages/claimants/components/ClaimantForm.js @@ -90,6 +90,7 @@ const ClaimantForm = ({ onCreate, data = {} }) => { placeholder: 'Enter Description...', basic: true, }} + initialValue={data.description} /> diff --git a/studio/src/pages/claimants/index.js b/studio/src/pages/claimants/index.js index 282190878..307b896af 100644 --- a/studio/src/pages/claimants/index.js +++ b/studio/src/pages/claimants/index.js @@ -81,6 +81,11 @@ function Claimants({ permission }) { style={{ maxWidth: '100%' }} onValuesChange={(changedValues, allValues) => { if (!changedValues.q) { + if (changedValues.q === '') { + const { q, ...filtersWithoutQuery } = filters; + setFilters({ ...filtersWithoutQuery }); + return; + } setFilters({ ...filters, ...changedValues }); } }} diff --git a/studio/src/pages/claims/components/ClaimForm.js b/studio/src/pages/claims/components/ClaimForm.js index e4f90395c..449225837 100644 --- a/studio/src/pages/claims/components/ClaimForm.js +++ b/studio/src/pages/claims/components/ClaimForm.js @@ -187,7 +187,10 @@ const ClaimForm = ({ onCreate, data = {} }) => { - + diff --git a/studio/src/pages/episodes/components/EpisodeForm.js b/studio/src/pages/episodes/components/EpisodeForm.js index ea3a5bc98..62b8b8c10 100644 --- a/studio/src/pages/episodes/components/EpisodeForm.js +++ b/studio/src/pages/episodes/components/EpisodeForm.js @@ -94,6 +94,7 @@ const EpisodeForm = ({ onCreate, data = {} }) => { diff --git a/studio/src/pages/fact-checks/components/FactCheckForm.js b/studio/src/pages/fact-checks/components/FactCheckForm.js index 5538e70b0..22410e47a 100644 --- a/studio/src/pages/fact-checks/components/FactCheckForm.js +++ b/studio/src/pages/fact-checks/components/FactCheckForm.js @@ -315,7 +315,11 @@ function FactCheckForm({ onCreate, data = {}, actions = {}, format }) { /> ) : null} - + Post Settings} placement="right" diff --git a/studio/src/pages/media/index.js b/studio/src/pages/media/index.js index cd2c5952a..355f86e93 100644 --- a/studio/src/pages/media/index.js +++ b/studio/src/pages/media/index.js @@ -82,6 +82,11 @@ function Media({ permission }) { style={{ width: '100%', marginBottom: '1rem' }} onValuesChange={(changedValues, allValues) => { if (!changedValues.q) { + if (changedValues.q === '') { + const { q, ...filtersWithoutQuery } = filters; + setFilters({ ...filtersWithoutQuery }); + return; + } setFilters({ ...filters, ...changedValues }); } }} diff --git a/studio/src/pages/podcasts/components/PodcastForm.js b/studio/src/pages/podcasts/components/PodcastForm.js index b63179ad8..01a72bf2b 100644 --- a/studio/src/pages/podcasts/components/PodcastForm.js +++ b/studio/src/pages/podcasts/components/PodcastForm.js @@ -80,6 +80,7 @@ const PodcastForm = ({ onCreate, data = {} }) => { diff --git a/studio/src/pages/posts/components/PostForm.js b/studio/src/pages/posts/components/PostForm.js index 3b55948d2..668841f81 100644 --- a/studio/src/pages/posts/components/PostForm.js +++ b/studio/src/pages/posts/components/PostForm.js @@ -244,6 +244,7 @@ function PostForm({ onCreate, data = {}, actions = {}, format, page = false }) { { placeholder: 'Enter Description...', basic: true, }} + initialValue={data.description} /> diff --git a/studio/src/pages/spaces/EditSpace.js b/studio/src/pages/spaces/EditSpace.js index d1cb7463e..49d497a98 100644 --- a/studio/src/pages/spaces/EditSpace.js +++ b/studio/src/pages/spaces/EditSpace.js @@ -20,9 +20,7 @@ function EditSpace() { }); const onCreate = (values) => { - dispatch(updateSpace({ ...space, ...values })).then(() => - history.push(`/admin/spaces/${id}/edit`), - ); + dispatch(updateSpace({ ...space, ...values })).then(() => history.push(`/admin/spaces`)); }; if (loading) return ; diff --git a/studio/src/pages/spaces/EditSpace.test.js b/studio/src/pages/spaces/EditSpace.test.js index 0df076239..e4d8a4ddd 100644 --- a/studio/src/pages/spaces/EditSpace.test.js +++ b/studio/src/pages/spaces/EditSpace.test.js @@ -268,7 +268,7 @@ describe('Spaces Edit component', () => { }, test: 'test', }); - expect(push).toHaveBeenCalledWith('/admin/spaces/11/edit'); + expect(push).toHaveBeenCalledWith('/admin/spaces'); done(); }, 0); }); diff --git a/studio/src/pages/spaces/components/SpaceEditForm.js b/studio/src/pages/spaces/components/SpaceEditForm.js index e4e8c3c84..71607a5db 100644 --- a/studio/src/pages/spaces/components/SpaceEditForm.js +++ b/studio/src/pages/spaces/components/SpaceEditForm.js @@ -43,7 +43,7 @@ const SpaceEditForm = ({ onCreate, data = {} }) => { values.meta_fields = getJsonValue(values.meta_fields); } onCreate(values); - onReset(); + // onReset(); }} scrollToFirstError={true} onFinishFailed={(errors) => { diff --git a/studio/src/pages/tags/components/TagForm.js b/studio/src/pages/tags/components/TagForm.js index 8f61dc94b..ac1445f1e 100644 --- a/studio/src/pages/tags/components/TagForm.js +++ b/studio/src/pages/tags/components/TagForm.js @@ -143,6 +143,7 @@ const TagForm = ({ onCreate, data = {} }) => { placeholder: 'Enter Description...', basic: true, }} + initialValue={data.description} /> diff --git a/studio/src/pages/tags/index.js b/studio/src/pages/tags/index.js index a4e6570c8..0084a2779 100644 --- a/studio/src/pages/tags/index.js +++ b/studio/src/pages/tags/index.js @@ -82,6 +82,11 @@ function Tags({ permission }) { style={{ width: '100%' }} onValuesChange={(changedValues, allValues) => { if (!changedValues.q) { + if (changedValues.q === '') { + const { q, ...filtersWithoutQuery } = filters; + setFilters({ ...filtersWithoutQuery }); + return; + } setFilters({ ...filters, ...changedValues }); } }} diff --git a/studio/src/pages/website/AnalyticsForm.js b/studio/src/pages/website/AnalyticsForm.js index ce9736420..57a5f4a03 100644 --- a/studio/src/pages/website/AnalyticsForm.js +++ b/studio/src/pages/website/AnalyticsForm.js @@ -42,7 +42,7 @@ function AnalyticsForm() { name="create-space" onFinish={(values) => { onCreate(values); - onReset(); + // onReset(); }} scrollToFirstError={true} onFinishFailed={(errors) => { diff --git a/studio/src/pages/website/Branding.js b/studio/src/pages/website/Branding.js index 8bf8867b2..0ee15a58f 100644 --- a/studio/src/pages/website/Branding.js +++ b/studio/src/pages/website/Branding.js @@ -46,13 +46,12 @@ function Branding() { name="create-space" onFinish={(values) => { onCreate(values); - onReset(); + //onReset(); }} scrollToFirstError={true} onFinishFailed={(errors) => { //let name = errors.errorFields[0].name[0]; // if (['name', 'slug'].includes(name)) { - console.log({ errors }); // } }} onValuesChange={() => { diff --git a/studio/src/pages/website/CodeInjection.js b/studio/src/pages/website/CodeInjection.js index 3c366a8bc..7e1eec535 100644 --- a/studio/src/pages/website/CodeInjection.js +++ b/studio/src/pages/website/CodeInjection.js @@ -44,7 +44,7 @@ function CodeInjection() { name="code-injection" onFinish={(values) => { onCreate(values); - onReset(); + // onReset(); }} scrollToFirstError={true} onFinishFailed={(errors) => { diff --git a/studio/src/pages/website/components/WebsiteEditForm.js b/studio/src/pages/website/components/WebsiteEditForm.js index 94e2daa32..615c1f89a 100644 --- a/studio/src/pages/website/components/WebsiteEditForm.js +++ b/studio/src/pages/website/components/WebsiteEditForm.js @@ -35,13 +35,12 @@ const WebsiteEditForm = ({ onCreate, data = {} }) => { values.meta_fields = getJsonValue(values.meta_fields); } onCreate(values); - onReset(); + // onReset(); }} scrollToFirstError={true} onFinishFailed={(errors) => { //let name = errors.errorFields[0].name[0]; // if (['name', 'slug'].includes(name)) { - console.log({ errors }); // } }} onValuesChange={() => { diff --git a/website/yarn.lock b/website/yarn.lock index 7c6abdd34..f5faf2a4c 100644 --- a/website/yarn.lock +++ b/website/yarn.lock @@ -2194,9 +2194,9 @@ async-limiter@~1.0.0: integrity sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ== async@^2.6.2: - version "2.6.3" - resolved "https://registry.yarnpkg.com/async/-/async-2.6.3.tgz#d72625e2344a3656e3a3ad4fa749fa83299d82ff" - integrity sha512-zflvls11DCy+dQWzTW2dzuilv8Z5X/pjfmZOWba6TNIVDm+2UDaJmXSOXlasHKfNBs8oo3M0aT50fDEWfKZjXg== + version "2.6.4" + resolved "https://registry.yarnpkg.com/async/-/async-2.6.4.tgz#706b7ff6084664cd7eae713f6f965433b5504221" + integrity sha512-mzo5dfJYwAn29PeiJ0zvwTo04zj8HDJj0Mn8TD7sno7q12prdbnasKJHhkm2c1LgrhlJ0teaea8860oxi51mGA== dependencies: lodash "^4.17.14" @@ -2218,11 +2218,11 @@ autoprefixer@^10.2.0, autoprefixer@^10.2.5: postcss-value-parser "^4.1.0" axios@^0.21.1: - version "0.21.1" - resolved "https://registry.yarnpkg.com/axios/-/axios-0.21.1.tgz#22563481962f4d6bde9a76d516ef0e5d3c09b2b8" - integrity sha512-dKQiRHxGD9PPRIUNIWvZhPTPpl1rf/OxTYKsqKUDjBwYylTvV7SjSHJb9ratfyzM6wCdLCOYLzs73qpg5c4iGA== + version "0.21.4" + resolved "https://registry.yarnpkg.com/axios/-/axios-0.21.4.tgz#c67b90dc0568e5c1cf2b0b858c43ba28e2eda575" + integrity sha512-ut5vewkiu8jjGBdqpM44XxjuCjq9LAKeHVmoVfHVzy8eHgxxq8SbAVQNovDA8mVi05kP0Ea/n/UzcSHcTJQfNg== dependencies: - follow-redirects "^1.10.0" + follow-redirects "^1.14.0" babel-loader@^8.2.2: version "8.2.2" @@ -2447,9 +2447,9 @@ browserslist@^4.0.0, browserslist@^4.14.5, browserslist@^4.16.0, browserslist@^4 node-releases "^1.1.71" buffer-from@^1.0.0: - version "1.1.1" - resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.1.tgz#32713bc028f75c02fdb710d7c7bcec1f2c6070ef" - integrity sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A== + version "1.1.2" + resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.2.tgz#2b146a6fd72e80b4f55d255f35ed59a3a9a41bd5" + integrity sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ== buffer-indexof@^1.0.0: version "1.1.1" @@ -2966,11 +2966,11 @@ cosmiconfig@^7.0.0: yaml "^1.10.0" cross-fetch@^3.0.4: - version "3.1.4" - resolved "https://registry.yarnpkg.com/cross-fetch/-/cross-fetch-3.1.4.tgz#9723f3a3a247bf8b89039f3a380a9244e8fa2f39" - integrity sha512-1eAtFWdIubi6T4XPy6ei9iUFoKpUkIF971QLN8lIvvvwueI65+Nw5haMNKUwfJxabqlIIDODJKGrQ66gxC0PbQ== + version "3.1.5" + resolved "https://registry.yarnpkg.com/cross-fetch/-/cross-fetch-3.1.5.tgz#e1389f44d9e7ba767907f7af8454787952ab534f" + integrity sha512-lvb1SBsI0Z7GDwmuid+mU3kWVBwTVUbe7S0H52yaaAdQOXq2YktTCZdlAcNKFzE6QtRz0snpw9bNiPeOIkkQvw== dependencies: - node-fetch "2.6.1" + node-fetch "2.6.7" cross-spawn@7.0.3, cross-spawn@^7.0.3: version "7.0.3" @@ -3717,11 +3717,9 @@ events@^3.2.0: integrity sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q== eventsource@^1.0.7: - version "1.1.0" - resolved "https://registry.yarnpkg.com/eventsource/-/eventsource-1.1.0.tgz#00e8ca7c92109e94b0ddf32dac677d841028cfaf" - integrity sha512-VSJjT5oCNrFvCS6igjzPAt5hBzQ2qPBFIbJ03zLI9SE0mxwZpMw6BfJrbFHm1a141AavMEB8JHmBhWAd66PfCg== - dependencies: - original "^1.0.0" + version "1.1.2" + resolved "https://registry.yarnpkg.com/eventsource/-/eventsource-1.1.2.tgz#bc75ae1c60209e7cb1541231980460343eaea7c2" + integrity sha512-xAH3zWhgO2/3KIniEKYPr8plNSzlGINOUqYj0m0u7AB81iRw8b/3E73W6AuU+6klLbaSFmZnaETQ2lXPfAydrA== execa@^1.0.0: version "1.0.0" @@ -4004,10 +4002,10 @@ flux@^4.0.1: fbemitter "^3.0.0" fbjs "^3.0.0" -follow-redirects@^1.0.0, follow-redirects@^1.10.0: - version "1.14.1" - resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.14.1.tgz#d9114ded0a1cfdd334e164e6662ad02bfd91ff43" - integrity sha512-HWqDgT7ZEkqRzBvc2s64vSZ/hfOceEol3ac/7tKwzuvEyWx3/4UegXh5oBOIotkGsObyk3xznnSRVADBgWSQVg== +follow-redirects@^1.0.0, follow-redirects@^1.14.0: + version "1.15.1" + resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.1.tgz#0ca6a452306c9b276e4d3127483e29575e207ad5" + integrity sha512-yLAMQs+k0b2m7cVxpS1VKJVvoz7SS9Td1zss3XRwXj+ZDH00RJgnuLx7E44wx02kQLrdM3aOOy+FpzS7+8OizA== for-in@^1.0.2: version "1.0.2" @@ -5693,9 +5691,9 @@ minimatch@3.0.4, minimatch@^3.0.4: brace-expansion "^1.1.7" minimist@^1.2.0, minimist@^1.2.5: - version "1.2.5" - resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.5.tgz#67d66014b66a6a8aaa0c083c5fd58df4e4e97602" - integrity sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw== + version "1.2.6" + resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.6.tgz#8637a5b759ea0d6e98702cfb3a9283323c93af44" + integrity sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q== mixin-deep@^1.2.0: version "1.3.2" @@ -5761,9 +5759,9 @@ nan@^2.12.1: integrity sha512-M2ufzIiINKCuDfBSAUr1vWQ+vuVcA9kqx8JJUsbQi6yf1uGRyb7HfpdfUr5qLXf3B/t8dPvcjhKMmlfnP47EzQ== nanoid@^3.1.23: - version "3.1.23" - resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.1.23.tgz#f744086ce7c2bc47ee0a8472574d5c78e4183a81" - integrity sha512-FiB0kzdP0FFVGDKlRLEQ1BgDzU87dy5NnzjeW9YZNt+/c3+q82EQDUwniSAUxp/F0gFNI1ZhKU1FqYsMuqZVnw== + version "3.3.4" + resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.4.tgz#730b67e3cd09e2deacf03c027c81c9d9dbc5e8ab" + integrity sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw== nanomatch@^1.2.9: version "1.2.13" @@ -5812,10 +5810,12 @@ node-emoji@^1.10.0: dependencies: lodash.toarray "^4.4.0" -node-fetch@2.6.1: - version "2.6.1" - resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.1.tgz#045bd323631f76ed2e2b55573394416b639a0052" - integrity sha512-V4aYg89jEoVRxRb2fJdAg8FHvI7cEyYdVAh94HH0UIK8oJxUfkjlDQN9RbMx+bEjP7+ggMiFRprSti032Oipxw== +node-fetch@2.6.7: + version "2.6.7" + resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.7.tgz#24de9fba827e3b4ae44dc8b20256a379160052ad" + integrity sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ== + dependencies: + whatwg-url "^5.0.0" node-forge@^0.10.0: version "0.10.0" @@ -6012,13 +6012,6 @@ opn@^5.5.0: dependencies: is-wsl "^1.1.0" -original@^1.0.0: - version "1.0.2" - resolved "https://registry.yarnpkg.com/original/-/original-1.0.2.tgz#e442a61cffe1c5fd20a65f3261c26663b303f25f" - integrity sha512-hyBVl6iqqUOJ8FqRe+l/gS8H+kKYjrEndd5Pm1MfBtsEKA038HkkdbAl/72EAXGyonD/PFsvmVG+EvcIpliMBg== - dependencies: - url-parse "^1.4.3" - p-cancelable@^1.0.0: version "1.1.0" resolved "https://registry.yarnpkg.com/p-cancelable/-/p-cancelable-1.1.0.tgz#d078d15a3af409220c886f1d9a0ca2e441ab26cc" @@ -7676,9 +7669,9 @@ source-map-resolve@^0.5.0: urix "^0.1.0" source-map-support@~0.5.12, source-map-support@~0.5.19: - version "0.5.19" - resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.19.tgz#a98b62f86dcaf4f67399648c085291ab9e8fed61" - integrity sha512-Wonm7zOCIJzBGQdB+thsPar0kYuCIzYvxZwlBa87yi/Mdjv7Tip2cyVbLj5o0cFPN4EVkuTwb3GDDyUx2DGnGw== + version "0.5.21" + resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.21.tgz#04fe7c7f9e1ed2d662233c28cb2b35b9f63f6e4f" + integrity sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w== dependencies: buffer-from "^1.0.0" source-map "^0.6.0" @@ -7979,9 +7972,9 @@ terser-webpack-plugin@^5.1.2, terser-webpack-plugin@^5.1.3: terser "^5.7.0" terser@^4.6.3: - version "4.8.0" - resolved "https://registry.yarnpkg.com/terser/-/terser-4.8.0.tgz#63056343d7c70bb29f3af665865a46fe03a0df17" - integrity sha512-EAPipTNeWsb/3wLPeup1tVPaXfIaU68xMnVdPafIL1TV05OhASArYyIfFvnvJCNrR2NIOvDVNNTFRa+Re2MWyw== + version "4.8.1" + resolved "https://registry.yarnpkg.com/terser/-/terser-4.8.1.tgz#a00e5634562de2239fd404c649051bf6fc21144f" + integrity sha512-4GnLC0x667eJG0ewJTa6z/yXrbLGv80D9Ru6HIpCQmO+Q4PfEtBFi0ObSckqwL6VyQv/7ENJieXHo2ANmdQwgw== dependencies: commander "^2.20.0" source-map "~0.6.1" @@ -8078,6 +8071,11 @@ totalist@^1.0.0: resolved "https://registry.yarnpkg.com/totalist/-/totalist-1.1.0.tgz#a4d65a3e546517701e3e5c37a47a70ac97fe56df" integrity sha512-gduQwd1rOdDMGxFG1gEvhV88Oirdo2p+KjoYFU7k2g+i7n6AFFbDQ5kMPUsW0pNbfQsB/cwXvT1i4Bue0s9g5g== +tr46@~0.0.3: + version "0.0.3" + resolved "https://registry.yarnpkg.com/tr46/-/tr46-0.0.3.tgz#8184fd347dac9cdc185992f3a6622e14b9d9ab6a" + integrity sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw== + trim-trailing-lines@^1.0.0: version "1.1.4" resolved "https://registry.yarnpkg.com/trim-trailing-lines/-/trim-trailing-lines-1.1.4.tgz#bd4abbec7cc880462f10b2c8b5ce1d8d1ec7c2c0" @@ -8358,7 +8356,7 @@ url-parse-lax@^3.0.0: dependencies: prepend-http "^2.0.0" -url-parse@^1.4.3, url-parse@^1.5.1: +url-parse@^1.5.1: version "1.5.1" resolved "https://registry.yarnpkg.com/url-parse/-/url-parse-1.5.1.tgz#d5fa9890af8a5e1f274a2c98376510f6425f6e3b" integrity sha512-HOfCOUJt7iSYzEx/UqgtwKRMC6EU91NFhsCHMv9oM03VJcVo2Qrp8T8kI9D7amFf1cu+/3CEhgb3rF9zL7k85Q== @@ -8502,6 +8500,11 @@ web-namespaces@^1.0.0, web-namespaces@^1.1.2: resolved "https://registry.yarnpkg.com/web-namespaces/-/web-namespaces-1.1.4.tgz#bc98a3de60dadd7faefc403d1076d529f5e030ec" integrity sha512-wYxSGajtmoP4WxfejAPIr4l0fVh+jeMXZb08wNc0tMg6xsfZXj3cECqIK0G7ZAqUq0PP8WlMDtaOGVBTAWztNw== +webidl-conversions@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-3.0.1.tgz#24534275e2a7bc6be7bc86611cc16ae0a5654871" + integrity sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ== + webpack-bundle-analyzer@^4.4.2: version "4.4.2" resolved "https://registry.yarnpkg.com/webpack-bundle-analyzer/-/webpack-bundle-analyzer-4.4.2.tgz#39898cf6200178240910d629705f0f3493f7d666" @@ -8656,6 +8659,14 @@ websocket-extensions@>=0.1.1: resolved "https://registry.yarnpkg.com/websocket-extensions/-/websocket-extensions-0.1.4.tgz#7f8473bc839dfd87608adb95d7eb075211578a42" integrity sha512-OqedPIGOfsDlo31UNwYbCFMSaO9m9G/0faIHj5/dZFDMFqPTcx6UwqyOy3COEaEOg/9VsGIpdqn62W5KhoKSpg== +whatwg-url@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-5.0.0.tgz#966454e8765462e37644d3626f6742ce8b70965d" + integrity sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw== + dependencies: + tr46 "~0.0.3" + webidl-conversions "^3.0.0" + which-boxed-primitive@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz#13757bc89b209b049fe5d86430e21cf40a89a8e6"