admin: Check all theme/exercice attribute are in sync with repo
This commit is contained in:
parent
5e262b75a3
commit
74f388a2b9
18 changed files with 818 additions and 142 deletions
|
@ -1,9 +1,11 @@
|
|||
package api
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"log"
|
||||
"net/http"
|
||||
"path"
|
||||
"reflect"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
@ -32,6 +34,8 @@ func declareExercicesRoutes(router *gin.RouterGroup) {
|
|||
apiExercicesRoutes.PATCH("", partUpdateExercice)
|
||||
apiExercicesRoutes.DELETE("", deleteExercice)
|
||||
|
||||
apiExercicesRoutes.POST("/diff-sync", APIDiffExerciceWithRemote)
|
||||
|
||||
apiExercicesRoutes.GET("/stats.json", getExerciceStats)
|
||||
|
||||
apiExercicesRoutes.GET("/history.json", getExerciceHistory)
|
||||
|
@ -91,8 +95,8 @@ func declareExercicesRoutes(router *gin.RouterGroup) {
|
|||
|
||||
// Remote
|
||||
router.GET("/remote/themes/:thid/exercices/:exid", sync.ApiGetRemoteExercice)
|
||||
router.GET("/remote/themes/:thid/exercices/:exid/hints", sync.ApiGetRemoteExerciceHints)
|
||||
router.GET("/remote/themes/:thid/exercices/:exid/flags", sync.ApiGetRemoteExerciceFlags)
|
||||
router.GET("/remote/themes/:thid/exercices/:exid/hints", sync.ApiGetRemoteExerciceHints)
|
||||
}
|
||||
|
||||
type Exercice struct {
|
||||
|
@ -130,7 +134,7 @@ func ExerciceHandler(c *gin.Context) {
|
|||
|
||||
c.Set("theme", theme)
|
||||
} else {
|
||||
c.Set("theme", &fic.Theme{Path: sync.StandaloneExercicesDirectory})
|
||||
c.Set("theme", &fic.StandaloneExercicesTheme)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1275,3 +1279,343 @@ func updateExerciceTags(c *gin.Context) {
|
|||
exercice.WipeTags()
|
||||
addExerciceTag(c)
|
||||
}
|
||||
|
||||
type syncDiff struct {
|
||||
Field string `json:"field"`
|
||||
Link string `json:"link"`
|
||||
Before interface{} `json:"be"`
|
||||
After interface{} `json:"af"`
|
||||
}
|
||||
|
||||
func diffExerciceWithRemote(exercice *fic.Exercice, theme *fic.Theme) ([]syncDiff, error) {
|
||||
var diffs []syncDiff
|
||||
|
||||
// Compare exercice attributes
|
||||
thid := exercice.Path[:strings.Index(exercice.Path, "/")]
|
||||
exid := exercice.Path[strings.Index(exercice.Path, "/")+1:]
|
||||
exercice_remote, err := sync.GetRemoteExercice(thid, exid, theme)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for _, field := range reflect.VisibleFields(reflect.TypeOf(*exercice)) {
|
||||
if ((field.Name == "Image") && path.Base(reflect.ValueOf(*exercice_remote).FieldByName(field.Name).String()) != path.Base(reflect.ValueOf(*exercice).FieldByName(field.Name).String())) || ((field.Name == "Depend") && (((exercice_remote.Depend == nil || exercice.Depend == nil) && exercice.Depend != exercice_remote.Depend) || (exercice_remote.Depend != nil && exercice.Depend != nil && *exercice.Depend != *exercice_remote.Depend))) || (field.Name != "Image" && field.Name != "Depend" && !reflect.ValueOf(*exercice_remote).FieldByName(field.Name).Equal(reflect.ValueOf(*exercice).FieldByName(field.Name))) {
|
||||
if !field.IsExported() || field.Name == "Id" || field.Name == "IdTheme" || field.Name == "IssueKind" || field.Name == "Coefficient" || field.Name == "BackgroundColor" {
|
||||
continue
|
||||
}
|
||||
|
||||
diffs = append(diffs, syncDiff{
|
||||
Field: field.Name,
|
||||
Link: fmt.Sprintf("exercices/%d", exercice.Id),
|
||||
Before: reflect.ValueOf(*exercice).FieldByName(field.Name).Interface(),
|
||||
After: reflect.ValueOf(*exercice_remote).FieldByName(field.Name).Interface(),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// Compare files
|
||||
files, err := exercice.GetFiles()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Unable to GetFiles: %w", err)
|
||||
}
|
||||
|
||||
files_remote, err := sync.GetRemoteExerciceFiles(thid, exid)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Unable to GetRemoteFiles: %w", err)
|
||||
}
|
||||
|
||||
for i, file_remote := range files_remote {
|
||||
if len(files) <= i {
|
||||
diffs = append(diffs, syncDiff{
|
||||
Field: fmt.Sprintf("files[%d]", i),
|
||||
Link: fmt.Sprintf("exercices/%d", exercice.Id),
|
||||
Before: nil,
|
||||
After: file_remote,
|
||||
})
|
||||
continue
|
||||
}
|
||||
|
||||
for _, field := range reflect.VisibleFields(reflect.TypeOf(*file_remote)) {
|
||||
if !field.IsExported() || field.Name == "Id" || field.Name == "IdExercice" {
|
||||
continue
|
||||
}
|
||||
if ((field.Name == "Path") && path.Base(reflect.ValueOf(*file_remote).FieldByName(field.Name).String()) != path.Base(reflect.ValueOf(*files[i]).FieldByName(field.Name).String())) || ((field.Name == "Checksum" || field.Name == "ChecksumShown") && !bytes.Equal(reflect.ValueOf(*file_remote).FieldByName(field.Name).Bytes(), reflect.ValueOf(*files[i]).FieldByName(field.Name).Bytes())) || (field.Name != "Checksum" && field.Name != "ChecksumShown" && field.Name != "Path" && !reflect.ValueOf(*file_remote).FieldByName(field.Name).Equal(reflect.ValueOf(*files[i]).FieldByName(field.Name))) {
|
||||
diffs = append(diffs, syncDiff{
|
||||
Field: fmt.Sprintf("files[%d].%s", i, field.Name),
|
||||
Link: fmt.Sprintf("exercices/%d", exercice.Id),
|
||||
Before: reflect.ValueOf(*files[i]).FieldByName(field.Name).Interface(),
|
||||
After: reflect.ValueOf(*file_remote).FieldByName(field.Name).Interface(),
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Compare flags
|
||||
flags, err := exercice.GetFlags()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Unable to GetFlags: %w", err)
|
||||
}
|
||||
|
||||
flags_remote, err := sync.GetRemoteExerciceFlags(thid, exid)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Unable to GetRemoteFlags: %w", err)
|
||||
}
|
||||
|
||||
var flags_not_found []interface{}
|
||||
var flags_extra_found []interface{}
|
||||
|
||||
for i, flag_remote := range flags_remote {
|
||||
if key_remote, ok := flag_remote.(*fic.FlagKey); ok {
|
||||
found := false
|
||||
|
||||
for _, flag := range flags {
|
||||
if key, ok := flag.(*fic.FlagKey); ok && (key.Label == key_remote.Label || key.Order == key_remote.Order) {
|
||||
found = true
|
||||
|
||||
// Parse flag label
|
||||
if len(key.Label) > 3 && key.Label[0] == '%' {
|
||||
spl := strings.Split(key.Label, "%")
|
||||
key.Label = strings.Join(spl[2:], "%")
|
||||
}
|
||||
|
||||
for _, field := range reflect.VisibleFields(reflect.TypeOf(*key_remote)) {
|
||||
if !field.IsExported() || field.Name == "Id" || field.Name == "IdExercice" {
|
||||
continue
|
||||
}
|
||||
if (field.Name == "Checksum" && !bytes.Equal(key.Checksum, key_remote.Checksum)) || (field.Name == "CaptureRegexp" && ((key.CaptureRegexp == nil || key_remote.CaptureRegexp == nil) && key.CaptureRegexp != key_remote.CaptureRegexp) || (key.CaptureRegexp != nil && key_remote.CaptureRegexp != nil && *key.CaptureRegexp != *key_remote.CaptureRegexp)) || (field.Name != "Checksum" && field.Name != "CaptureRegexp" && !reflect.ValueOf(*key_remote).FieldByName(field.Name).Equal(reflect.ValueOf(*key).FieldByName(field.Name))) {
|
||||
diffs = append(diffs, syncDiff{
|
||||
Field: fmt.Sprintf("flags[%d].%s", i, field.Name),
|
||||
Link: fmt.Sprintf("exercices/%d/flags#flag-%d", exercice.Id, key.Id),
|
||||
Before: reflect.ValueOf(*key).FieldByName(field.Name).Interface(),
|
||||
After: reflect.ValueOf(*key_remote).FieldByName(field.Name).Interface(),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if !found {
|
||||
flags_not_found = append(flags_not_found, key_remote)
|
||||
}
|
||||
} else if mcq_remote, ok := flag_remote.(*fic.MCQ); ok {
|
||||
found := false
|
||||
|
||||
for _, flag := range flags {
|
||||
if mcq, ok := flag.(*fic.MCQ); ok && (mcq.Title == mcq_remote.Title || mcq.Order == mcq_remote.Order) {
|
||||
found = true
|
||||
|
||||
for _, field := range reflect.VisibleFields(reflect.TypeOf(*mcq_remote)) {
|
||||
if !field.IsExported() || field.Name == "Id" || field.Name == "IdExercice" {
|
||||
continue
|
||||
}
|
||||
if field.Name == "Entries" {
|
||||
var not_found []*fic.MCQ_entry
|
||||
var extra_found []*fic.MCQ_entry
|
||||
|
||||
for i, entry_remote := range mcq_remote.Entries {
|
||||
found := false
|
||||
|
||||
for j, entry := range mcq.Entries {
|
||||
if entry.Label == entry_remote.Label {
|
||||
for _, field := range reflect.VisibleFields(reflect.TypeOf(*entry_remote)) {
|
||||
if field.Name == "Id" {
|
||||
continue
|
||||
}
|
||||
|
||||
if !reflect.ValueOf(*entry_remote).FieldByName(field.Name).Equal(reflect.ValueOf(*entry).FieldByName(field.Name)) {
|
||||
diffs = append(diffs, syncDiff{
|
||||
Field: fmt.Sprintf("flags[%d].entries[%d].%s", i, j, field.Name),
|
||||
Link: fmt.Sprintf("exercices/%d/flags#quiz-%d", exercice.Id, mcq.Id),
|
||||
Before: reflect.ValueOf(*mcq.Entries[j]).FieldByName(field.Name).Interface(),
|
||||
After: reflect.ValueOf(*entry_remote).FieldByName(field.Name).Interface(),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
found = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if !found {
|
||||
not_found = append(not_found, entry_remote)
|
||||
}
|
||||
}
|
||||
|
||||
for _, entry := range mcq.Entries {
|
||||
found := false
|
||||
for _, entry_remote := range mcq_remote.Entries {
|
||||
if entry.Label == entry_remote.Label {
|
||||
found = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if !found {
|
||||
extra_found = append(extra_found, entry)
|
||||
}
|
||||
}
|
||||
|
||||
if len(not_found) > 0 || len(extra_found) > 0 {
|
||||
diffs = append(diffs, syncDiff{
|
||||
Field: fmt.Sprintf("flags[%d].entries", i, field.Name),
|
||||
Link: fmt.Sprintf("exercices/%d/flags", exercice.Id),
|
||||
Before: extra_found,
|
||||
After: not_found,
|
||||
})
|
||||
}
|
||||
} else if !reflect.ValueOf(*mcq_remote).FieldByName(field.Name).Equal(reflect.ValueOf(*mcq).FieldByName(field.Name)) {
|
||||
diffs = append(diffs, syncDiff{
|
||||
Field: fmt.Sprintf("flags[%d].%s", i, field.Name),
|
||||
Link: fmt.Sprintf("exercices/%d/flags", exercice.Id),
|
||||
Before: reflect.ValueOf(*mcq).FieldByName(field.Name).Interface(),
|
||||
After: reflect.ValueOf(*mcq_remote).FieldByName(field.Name).Interface(),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if !found {
|
||||
flags_not_found = append(flags_not_found, mcq_remote)
|
||||
}
|
||||
} else if label_remote, ok := flag_remote.(*fic.FlagLabel); ok {
|
||||
found := false
|
||||
|
||||
for _, flag := range flags {
|
||||
if label, ok := flag.(*fic.FlagLabel); ok && (label.Label == label_remote.Label || label.Order == label_remote.Order) {
|
||||
found = true
|
||||
|
||||
for _, field := range reflect.VisibleFields(reflect.TypeOf(*label_remote)) {
|
||||
if !field.IsExported() || field.Name == "Id" || field.Name == "IdExercice" {
|
||||
continue
|
||||
}
|
||||
if !reflect.ValueOf(*label_remote).FieldByName(field.Name).Equal(reflect.ValueOf(*label).FieldByName(field.Name)) {
|
||||
diffs = append(diffs, syncDiff{
|
||||
Field: fmt.Sprintf("flags[%d].%s", i, field.Name),
|
||||
Link: fmt.Sprintf("exercices/%d/flags#flag-%d", exercice.Id, label.Id),
|
||||
Before: reflect.ValueOf(*label).FieldByName(field.Name).Interface(),
|
||||
After: reflect.ValueOf(*label_remote).FieldByName(field.Name).Interface(),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if !found {
|
||||
flags_not_found = append(flags_not_found, label_remote)
|
||||
}
|
||||
} else {
|
||||
log.Printf("unknown flag type: %T", flag_remote)
|
||||
}
|
||||
}
|
||||
|
||||
for _, flag := range flags {
|
||||
if key, ok := flag.(*fic.FlagKey); ok {
|
||||
found := false
|
||||
|
||||
for _, flag_remote := range flags_remote {
|
||||
if key_remote, ok := flag_remote.(*fic.FlagKey); ok && (key.Label == key_remote.Label || key.Order == key_remote.Order) {
|
||||
found = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if !found {
|
||||
flags_extra_found = append(flags_extra_found, flag)
|
||||
}
|
||||
} else if mcq, ok := flag.(*fic.MCQ); ok {
|
||||
found := false
|
||||
|
||||
for _, flag_remote := range flags_remote {
|
||||
if mcq_remote, ok := flag_remote.(*fic.MCQ); ok && (mcq.Title == mcq_remote.Title || mcq.Order == mcq_remote.Order) {
|
||||
found = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if !found {
|
||||
flags_extra_found = append(flags_extra_found, flag)
|
||||
}
|
||||
} else if label, ok := flag.(*fic.FlagLabel); ok {
|
||||
found := false
|
||||
|
||||
for _, flag_remote := range flags_remote {
|
||||
if label_remote, ok := flag_remote.(*fic.FlagLabel); ok && (label.Label == label_remote.Label || label.Order == label_remote.Order) {
|
||||
found = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if !found {
|
||||
flags_extra_found = append(flags_extra_found, flag)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if len(flags_not_found) > 0 || len(flags_extra_found) > 0 {
|
||||
diffs = append(diffs, syncDiff{
|
||||
Field: "flags",
|
||||
Link: fmt.Sprintf("exercices/%d/flags", exercice.Id),
|
||||
Before: flags_extra_found,
|
||||
After: flags_not_found,
|
||||
})
|
||||
}
|
||||
|
||||
// Compare hints
|
||||
hints, err := exercice.GetHints()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Unable to GetHints: %w", err)
|
||||
}
|
||||
|
||||
hints_remote, err := sync.GetRemoteExerciceHints(thid, exid)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Unable to GetRemoteHints: %w", err)
|
||||
}
|
||||
|
||||
for i, hint_remote := range hints_remote {
|
||||
hint_remote.Hint.TreatHintContent()
|
||||
|
||||
for _, field := range reflect.VisibleFields(reflect.TypeOf(*hint_remote.Hint)) {
|
||||
if !field.IsExported() || field.Name == "Id" || field.Name == "IdExercice" {
|
||||
continue
|
||||
}
|
||||
if len(hints) <= i {
|
||||
diffs = append(diffs, syncDiff{
|
||||
Field: fmt.Sprintf("hints[%d].%s", i, field.Name),
|
||||
Link: fmt.Sprintf("exercices/%d", exercice.Id),
|
||||
Before: nil,
|
||||
After: reflect.ValueOf(*hint_remote.Hint).FieldByName(field.Name).Interface(),
|
||||
})
|
||||
} else if !reflect.ValueOf(*hint_remote.Hint).FieldByName(field.Name).Equal(reflect.ValueOf(*hints[i]).FieldByName(field.Name)) {
|
||||
diffs = append(diffs, syncDiff{
|
||||
Field: fmt.Sprintf("hints[%d].%s", i, field.Name),
|
||||
Link: fmt.Sprintf("exercices/%d", exercice.Id),
|
||||
Before: reflect.ValueOf(*hints[i]).FieldByName(field.Name).Interface(),
|
||||
After: reflect.ValueOf(*hint_remote.Hint).FieldByName(field.Name).Interface(),
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return diffs, err
|
||||
}
|
||||
|
||||
func APIDiffExerciceWithRemote(c *gin.Context) {
|
||||
theme := c.MustGet("theme").(*fic.Theme)
|
||||
exercice := c.MustGet("exercice").(*fic.Exercice)
|
||||
|
||||
diffs, err := diffExerciceWithRemote(exercice, theme)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"errmsg": err.Error()})
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, diffs)
|
||||
}
|
||||
|
|
|
@ -79,12 +79,14 @@ func declareSyncRoutes(router *gin.RouterGroup) {
|
|||
c.JSON(http.StatusOK, r)
|
||||
})
|
||||
|
||||
apiSyncRoutes.POST("/local-diff", APIDiffDBWithRemote)
|
||||
|
||||
apiSyncDeepRoutes := apiSyncRoutes.Group("/deep/:thid")
|
||||
apiSyncDeepRoutes.Use(ThemeHandler)
|
||||
// Special route to handle standalone exercices
|
||||
apiSyncRoutes.POST("/deep/0", func(c *gin.Context) {
|
||||
var st []string
|
||||
for _, se := range multierr.Errors(sync.SyncThemeDeep(sync.GlobalImporter, &fic.Theme{Path: sync.StandaloneExercicesDirectory}, 0, 250, nil)) {
|
||||
for _, se := range multierr.Errors(sync.SyncThemeDeep(sync.GlobalImporter, &fic.StandaloneExercicesTheme, 0, 250, nil)) {
|
||||
st = append(st, se.Error())
|
||||
}
|
||||
sync.EditDeepReport(&sync.SyncReport{Exercices: st}, false)
|
||||
|
@ -378,3 +380,32 @@ func autoSync(c *gin.Context) {
|
|||
|
||||
c.JSON(http.StatusOK, st)
|
||||
}
|
||||
|
||||
func diffDBWithRemote() (map[string][]syncDiff, error) {
|
||||
diffs := map[string][]syncDiff{}
|
||||
|
||||
themes, err := fic.GetThemesExtended()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Compare inner themes
|
||||
for _, theme := range themes {
|
||||
diffs[theme.Name], err = diffThemeWithRemote(theme)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Unable to diffThemeWithRemote: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
return diffs, err
|
||||
}
|
||||
|
||||
func APIDiffDBWithRemote(c *gin.Context) {
|
||||
diffs, err := diffDBWithRemote()
|
||||
if err != nil {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"errmsg": err.Error()})
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, diffs)
|
||||
}
|
||||
|
|
|
@ -5,7 +5,9 @@ import (
|
|||
"log"
|
||||
"net/http"
|
||||
"path"
|
||||
"reflect"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"srs.epita.fr/fic-server/admin/sync"
|
||||
"srs.epita.fr/fic-server/libfic"
|
||||
|
@ -48,6 +50,8 @@ func declareThemesRoutes(router *gin.RouterGroup) {
|
|||
apiThemesRoutes.PUT("", updateTheme)
|
||||
apiThemesRoutes.DELETE("", deleteTheme)
|
||||
|
||||
apiThemesRoutes.POST("/diff-sync", APIDiffThemeWithRemote)
|
||||
|
||||
apiThemesRoutes.GET("/exercices_stats.json", getThemedExercicesStats)
|
||||
|
||||
declareExercicesRoutes(apiThemesRoutes)
|
||||
|
@ -71,7 +75,7 @@ func ThemeHandler(c *gin.Context) {
|
|||
}
|
||||
|
||||
if thid == 0 {
|
||||
c.Set("theme", &fic.Theme{Name: "Exercices indépendants", Path: sync.StandaloneExercicesDirectory})
|
||||
c.Set("theme", &fic.StandaloneExercicesTheme)
|
||||
} else {
|
||||
theme, err := fic.GetTheme(thid)
|
||||
if err != nil {
|
||||
|
@ -132,7 +136,7 @@ func listThemes(c *gin.Context) {
|
|||
}
|
||||
|
||||
if has, _ := fic.HasStandaloneExercice(); has {
|
||||
themes = append([]*fic.Theme{&fic.Theme{Name: "Exercices indépendants", Path: sync.StandaloneExercicesDirectory}}, themes...)
|
||||
themes = append([]*fic.Theme{&fic.StandaloneExercicesTheme}, themes...)
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, themes)
|
||||
|
@ -263,3 +267,110 @@ func getThemedExercicesStats(c *gin.Context) {
|
|||
}
|
||||
c.JSON(http.StatusOK, ret)
|
||||
}
|
||||
|
||||
func diffThemeWithRemote(theme *fic.Theme) ([]syncDiff, error) {
|
||||
var diffs []syncDiff
|
||||
|
||||
// Compare theme attributes
|
||||
theme_remote, err := sync.GetRemoteTheme(theme.Path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for _, field := range reflect.VisibleFields(reflect.TypeOf(*theme)) {
|
||||
if ((field.Name == "Image") && path.Base(reflect.ValueOf(*theme_remote).FieldByName(field.Name).String()) != path.Base(reflect.ValueOf(*theme).FieldByName(field.Name).String())) || (field.Name != "Image" && !reflect.ValueOf(*theme_remote).FieldByName(field.Name).Equal(reflect.ValueOf(*theme).FieldByName(field.Name))) {
|
||||
if !field.IsExported() || field.Name == "Id" || field.Name == "IdTheme" || field.Name == "IssueKind" || field.Name == "BackgroundColor" {
|
||||
continue
|
||||
}
|
||||
|
||||
diffs = append(diffs, syncDiff{
|
||||
Field: field.Name,
|
||||
Link: fmt.Sprintf("themes/%d", theme.Id),
|
||||
Before: reflect.ValueOf(*theme).FieldByName(field.Name).Interface(),
|
||||
After: reflect.ValueOf(*theme_remote).FieldByName(field.Name).Interface(),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// Compare exercices list
|
||||
exercices, err := theme.GetExercices()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Unable to GetExercices: %w", err)
|
||||
}
|
||||
|
||||
exercices_remote, err := sync.ListRemoteExercices(theme.Path)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Unable to ListRemoteExercices: %w", err)
|
||||
}
|
||||
|
||||
var not_found []string
|
||||
var extra_found []string
|
||||
|
||||
for _, exercice_remote := range exercices_remote {
|
||||
found := false
|
||||
for _, exercice := range exercices {
|
||||
if exercice.Path[strings.Index(exercice.Path, "/")+1:] == exercice_remote {
|
||||
found = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if !found {
|
||||
not_found = append(not_found, exercice_remote)
|
||||
}
|
||||
}
|
||||
|
||||
for _, exercice := range exercices {
|
||||
found := false
|
||||
for _, exercice_remote := range exercices_remote {
|
||||
if exercice.Path[strings.Index(exercice.Path, "/")+1:] == exercice_remote {
|
||||
found = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if !found {
|
||||
extra_found = append(extra_found, exercice.Path[strings.Index(exercice.Path, "/")+1:])
|
||||
}
|
||||
}
|
||||
|
||||
if len(not_found) > 0 || len(extra_found) > 0 {
|
||||
diffs = append(diffs, syncDiff{
|
||||
Field: "theme.Exercices",
|
||||
Link: fmt.Sprintf("themes/%d", theme.Id),
|
||||
Before: strings.Join(extra_found, ", "),
|
||||
After: strings.Join(not_found, ", "),
|
||||
})
|
||||
}
|
||||
|
||||
// Compare inner exercices
|
||||
for i, exercice := range exercices {
|
||||
exdiffs, err := diffExerciceWithRemote(exercice, theme)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Unable to diffExerciceWithRemote: %w", err)
|
||||
}
|
||||
|
||||
for _, exdiff := range exdiffs {
|
||||
if theme.Id == 0 {
|
||||
exdiff.Field = fmt.Sprintf("exercices[%d].%s", exercice.Id, exdiff.Field)
|
||||
} else {
|
||||
exdiff.Field = fmt.Sprintf("exercices[%d].%s", i, exdiff.Field)
|
||||
}
|
||||
diffs = append(diffs, exdiff)
|
||||
}
|
||||
}
|
||||
|
||||
return diffs, err
|
||||
}
|
||||
|
||||
func APIDiffThemeWithRemote(c *gin.Context) {
|
||||
theme := c.MustGet("theme").(*fic.Theme)
|
||||
|
||||
diffs, err := diffThemeWithRemote(theme)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"errmsg": err.Error()})
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, diffs)
|
||||
}
|
||||
|
|
Reference in a new issue