admin: Check all theme/exercice attribute are in sync with repo
This commit is contained in:
parent
5e262b75a3
commit
74f388a2b9
18 changed files with 813 additions and 137 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)
|
||||
}
|
||||