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
|
@ -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