diff --git a/admin/api/theme.go b/admin/api/theme.go index e7803963..1fbcdd65 100644 --- a/admin/api/theme.go +++ b/admin/api/theme.go @@ -164,7 +164,7 @@ func createTheme(_ httprouter.Params, body []byte) (interface{}, error) { return nil, errors.New("Theme's name not filled") } - return fic.CreateTheme(ut.Name, ut.URLId, "", ut.Authors, ut.Intro, ut.Headline, ut.Image) + return fic.CreateTheme(ut) } func updateTheme(theme fic.Theme, body []byte) (interface{}, error) { diff --git a/admin/sync/themes.go b/admin/sync/themes.go index c511cdd0..2da28f89 100644 --- a/admin/sync/themes.go +++ b/admin/sync/themes.go @@ -8,13 +8,13 @@ import ( "strings" "unicode" - "srs.epita.fr/fic-server/libfic" "github.com/julienschmidt/httprouter" "gopkg.in/russross/blackfriday.v2" + "srs.epita.fr/fic-server/libfic" ) -// getThemes returns all theme directories in the base directory. -func getThemes(i Importer) ([]string, error) { +// GetThemes returns all theme directories in the base directory. +func GetThemes(i Importer) ([]string, error) { var themes []string if dirs, err := i.listDir("/"); err != nil { @@ -50,11 +50,71 @@ func getAuthors(i Importer, tname string) ([]string, error) { } } +// BuildTheme creates a Theme from a given importer. +func BuildTheme(i Importer, tdir string) (th *fic.Theme, errs []string) { + th = &fic.Theme{} + + th.Path = tdir + + // Extract theme's label + if f := strings.Index(tdir, "-"); f >= 0 { + th.Name = fixnbsp(tdir[f+1:]) + } else { + th.Name = fixnbsp(tdir) + } + th.URLId = fic.ToURLid(th.Name) + + if authors, err := getAuthors(i, tdir); err != nil { + errs = append(errs, fmt.Sprintf("%q: unable to get AUTHORS.txt: %s", th.Name, err)) + return nil, errs + } else { + // Format authors + th.Authors = strings.Join(authors, ", ") + } + + if intro, err := getFileContent(i, path.Join(tdir, "overview.txt")); err != nil { + errs = append(errs, fmt.Sprintf("%q: unable to get theme's overview: %s", th.Name, err)) + } else { + // Split headline from intro + ovrvw := strings.Split(fixnbsp(intro), "\n") + th.Headline = ovrvw[0] + if len(ovrvw) > 1 { + intro = strings.Join(ovrvw[1:], "\n") + } + + // Format overview (markdown) + th.Intro, err = ProcessMarkdown(i, intro, tdir) + if err != nil { + errs = append(errs, fmt.Sprintf("%q: overview.txt: an error occurs during markdown formating: %s", tdir, err)) + } + th.Headline = string(blackfriday.Run([]byte(th.Headline))) + } + + if i.exists(path.Join(tdir, "heading.jpg")) { + th.Image = path.Join(tdir, "heading.jpg") + } else if i.exists(path.Join(tdir, "heading.png")) { + th.Image = path.Join(tdir, "heading.png") + } + + if len(th.Image) > 0 { + if _, err := i.importFile(th.Image, + func(filePath string, origin string) (interface{}, error) { + th.Image = strings.TrimPrefix(filePath, fic.FilesDir) + return nil, nil + }); err != nil { + errs = append(errs, fmt.Sprintf("%q: unable to import heading image: %s", tdir, err)) + return nil, errs + } + } + + return +} + // SyncThemes imports new or updates existing themes. func SyncThemes(i Importer) []string { var errs []string - if themes, err := getThemes(i); err != nil { + if themes, err := GetThemes(i); err != nil { errs = append(errs, err.Error()) } else { rand.Shuffle(len(themes), func(i, j int) { @@ -62,76 +122,24 @@ func SyncThemes(i Importer) []string { }) for _, tdir := range themes { - var authors []string - var intro string - var headline string - var image string - var theme fic.Theme - var tname string + btheme, berrs := BuildTheme(i, tdir) + errs = append(errs, berrs...) - // Extract theme's label - if f := strings.Index(tdir, "-"); f >= 0 { - tname = fixnbsp(tdir[f+1:]) - } else { - tname = fixnbsp(tdir) - } - - if authors, err = getAuthors(i, tdir); err != nil { - errs = append(errs, fmt.Sprintf("%q: unable to get AUTHORS: %s", tname, err)) + if btheme == nil { continue - } else if intro, err = getFileContent(i, path.Join(tdir, "overview.txt")); err != nil { - errs = append(errs, fmt.Sprintf("%q: unable to get theme's overview: %s", tname, err)) - } else { - // Split headline from intro - ovrvw := strings.Split(fixnbsp(intro), "\n") - headline = ovrvw[0] - if len(ovrvw) > 1 { - intro = strings.Join(ovrvw[1:], "\n") - } + } - if theme, err = fic.GetThemeByName(tname); err != nil { - if _, err := fic.CreateTheme(tname, fic.ToURLid(tname), tdir, strings.Join(authors, ", "), intro, headline, image); err != nil { - errs = append(errs, fmt.Sprintf("%q: an error occurs during add: %s", tdir, err)) - continue - } + var theme fic.Theme + if theme, err = fic.GetThemeByName(btheme.Name); err != nil { + if _, err := fic.CreateTheme(*btheme); err != nil { + errs = append(errs, fmt.Sprintf("%q: an error occurs during add: %s", tdir, err)) + continue } } - // Format authors - authors_str := strings.Join(authors, ", ") - - // Format overview (markdown) - intro, err = ProcessMarkdown(i, intro, tdir) - if err != nil { - errs = append(errs, fmt.Sprintf("%q: overview.txt: an error occurs during markdown formating: %s", tdir, err)) - } - headline = string(blackfriday.Run([]byte(headline))) - - if i.exists(path.Join(tdir, "heading.jpg")) { - image = path.Join(tdir, "heading.jpg") - } else if i.exists(path.Join(tdir, "heading.png")) { - image = path.Join(tdir, "heading.png") - } - - if len(image) > 0 { - if _, err := i.importFile(image, - func(filePath string, origin string) (interface{}, error) { - image = strings.TrimPrefix(filePath, fic.FilesDir) - return nil, nil - }); err != nil { - errs = append(errs, fmt.Sprintf("%q: unable to import heading image: %s", tdir, err)) - continue - } - } - - if theme.Name != tname || theme.Authors != authors_str || theme.Headline != headline || theme.Intro != intro || theme.Image != image { - theme.Name = tname - theme.Authors = authors_str - theme.Intro = intro - theme.Headline = headline - theme.Image = image - theme.Path = tdir - if _, err := theme.Update(); err != nil { + if !fic.CmpTheme(theme, *btheme) { + btheme.Id = theme.Id + if _, err := btheme.Update(); err != nil { errs = append(errs, fmt.Sprintf("%q: an error occurs during update: %s", tdir, err)) continue } @@ -144,7 +152,7 @@ func SyncThemes(i Importer) []string { // ApiListRemoteThemes is an accessor letting foreign packages to access remote themes list. func ApiListRemoteThemes(_ httprouter.Params, _ []byte) (interface{}, error) { - return getThemes(GlobalImporter) + return GetThemes(GlobalImporter) } // ApiListRemoteTheme is an accessor letting foreign packages to access remote main theme attributes. diff --git a/libfic/theme.go b/libfic/theme.go index c578bc85..3f89cc75 100644 --- a/libfic/theme.go +++ b/libfic/theme.go @@ -14,6 +14,11 @@ type Theme struct { Image string `json:"image,omitempty"` } +// CmpTheme returns true if given Themes are identicals. +func CmpTheme(t1 Theme, t2 Theme) bool { + return !(t1.Name != t2.Name || t1.URLId != t2.URLId || t1.Path != t2.Path || t1.Authors != t2.Authors || t1.Intro != t2.Intro || t1.Headline != t2.Headline || t1.Image != t2.Image) +} + // GetThemes returns a list of registered Themes from the database. func GetThemes() ([]Theme, error) { if rows, err := DBQuery("SELECT id_theme, name, url_id, path, authors, intro, headline, image FROM themes"); err != nil { @@ -58,13 +63,13 @@ func GetThemeByName(name string) (Theme, error) { } // CreateTheme creates and fills a new struct Theme and registers it into the database. -func CreateTheme(name string, url_id string, path string, authors string, intro string, headline string, image string) (Theme, error) { - if res, err := DBExec("INSERT INTO themes (name, url_id, authors, path, intro, headline, image) VALUES (?, ?, ?, ?, ?, ?, ?)", name, url_id, authors, path, intro, headline, image); err != nil { +func CreateTheme(theme Theme) (Theme, error) { + if res, err := DBExec("INSERT INTO themes (name, url_id, authors, path, intro, headline, image) VALUES (?, ?, ?, ?, ?, ?, ?)", theme.Name, theme.URLId, theme.Authors, theme.Path, theme.Intro, theme.Headline, theme.Image); err != nil { return Theme{}, err - } else if tid, err := res.LastInsertId(); err != nil { + } else if theme.Id, err = res.LastInsertId(); err != nil { return Theme{}, err } else { - return Theme{tid, name, url_id, path, authors, intro, headline, image}, nil + return theme, nil } }