Implement and display headlines in interface

This commit is contained in:
nemunaire 2018-12-02 11:43:24 +01:00
parent abd7fc6bef
commit 8c95782eff
13 changed files with 85 additions and 58 deletions

View file

@ -144,6 +144,10 @@ func partUpdateExercice(exercice fic.Exercice, body []byte) (interface{}, error)
exercice.Statement = ue.Statement exercice.Statement = ue.Statement
} }
if len(ue.Headline) > 0 {
exercice.Headline = ue.Headline
}
if len(ue.Overview) > 0 { if len(ue.Overview) > 0 {
exercice.Overview = ue.Overview exercice.Overview = ue.Overview
} }
@ -199,7 +203,7 @@ func createExercice(theme fic.Theme, body []byte) (interface{}, error) {
} }
} }
return theme.AddExercice(ue.Title, ue.URLId, ue.Path, ue.Statement, ue.Overview, depend, ue.Gain, ue.VideoURI) return theme.AddExercice(ue.Title, ue.URLId, ue.Path, ue.Statement, ue.Overview, ue.Headline, depend, ue.Gain, ue.VideoURI)
} }
type uploadedHint struct { type uploadedHint struct {

View file

@ -146,15 +146,8 @@ func showThemedExercice(theme fic.Theme, exercice fic.Exercice, body []byte) (in
return exercice, nil return exercice, nil
} }
type uploadedTheme struct {
Name string
URLId string
Authors string
Intro string
}
func createTheme(_ httprouter.Params, body []byte) (interface{}, error) { func createTheme(_ httprouter.Params, body []byte) (interface{}, error) {
var ut uploadedTheme var ut fic.Theme
if err := json.Unmarshal(body, &ut); err != nil { if err := json.Unmarshal(body, &ut); err != nil {
return nil, err return nil, err
} }
@ -163,7 +156,7 @@ func createTheme(_ httprouter.Params, body []byte) (interface{}, error) {
return nil, errors.New("Theme's name not filled") return nil, errors.New("Theme's name not filled")
} }
return fic.CreateTheme(ut.Name, ut.URLId, "", ut.Authors, ut.Intro, "") return fic.CreateTheme(ut.Name, ut.URLId, "", ut.Authors, ut.Intro, ut.Headline, ut.Image)
} }
func updateTheme(theme fic.Theme, body []byte) (interface{}, error) { func updateTheme(theme fic.Theme, body []byte) (interface{}, error) {

View file

@ -929,7 +929,7 @@ angular.module("FICApp")
}) })
.controller("ThemeController", function($scope, Theme, $routeParams, $location, $rootScope, $http) { .controller("ThemeController", function($scope, Theme, $routeParams, $location, $rootScope, $http) {
$scope.theme = Theme.get({ themeId: $routeParams.themeId }); $scope.theme = Theme.get({ themeId: $routeParams.themeId });
$scope.fields = ["name", "urlid", "authors", "intro", "image"]; $scope.fields = ["name", "urlid", "authors", "headline", "intro", "image"];
$scope.saveTheme = function() { $scope.saveTheme = function() {
if (this.theme.id) { if (this.theme.id) {
@ -1044,7 +1044,7 @@ angular.module("FICApp")
$scope.exercice = Exercice.get({ exerciceId: $routeParams.exerciceId }); $scope.exercice = Exercice.get({ exerciceId: $routeParams.exerciceId });
} }
$scope.exercices = Exercice.query(); $scope.exercices = Exercice.query();
$scope.fields = ["title", "urlid", "statement", "overview", "depend", "gain", "coefficient", "videoURI", "issue", "issuekind"]; $scope.fields = ["title", "urlid", "statement", "headline", "overview", "depend", "gain", "coefficient", "videoURI", "issue", "issuekind"];
$scope.showTags = false; $scope.showTags = false;
$scope.toggleTags = function(val) { $scope.toggleTags = function(val) {

View file

@ -59,6 +59,11 @@ func SyncExercices(i Importer, theme fic.Theme) []string {
if err != nil { if err != nil {
errs = append(errs, fmt.Sprintf("%q: overview.txt: %s", edir, err)) errs = append(errs, fmt.Sprintf("%q: overview.txt: %s", edir, err))
} }
ovrvw := strings.Split(overview, "\n")
headline := ovrvw[0]
if len(ovrvw) > 1 {
overview = strings.Join(ovrvw[1:], "\n")
}
statement, err := getFileContent(i, path.Join(theme.Path, edir, "statement.txt")) statement, err := getFileContent(i, path.Join(theme.Path, edir, "statement.txt"))
if err != nil { if err != nil {
@ -111,18 +116,20 @@ func SyncExercices(i Importer, theme fic.Theme) []string {
// Markdown pre-formating // Markdown pre-formating
statement = string(blackfriday.Run([]byte(statement))) statement = string(blackfriday.Run([]byte(statement)))
overview = string(blackfriday.Run([]byte(overview))) overview = string(blackfriday.Run([]byte(overview)))
headline = string(blackfriday.Run([]byte(headline)))
e, err := theme.GetExerciceByTitle(ename) e, err := theme.GetExerciceByTitle(ename)
if err != nil { if err != nil {
if e, err = theme.AddExercice(ename, fic.ToURLid(ename), path.Join(theme.Path, edir), statement, overview, depend, gain, videoURI); err != nil { if e, err = theme.AddExercice(ename, fic.ToURLid(ename), path.Join(theme.Path, edir), statement, overview, headline, depend, gain, videoURI); err != nil {
errs = append(errs, fmt.Sprintf("%q: error on exercice add: %s", edir, err)) errs = append(errs, fmt.Sprintf("%q: error on exercice add: %s", edir, err))
continue continue
} }
} else if e.Title != ename || e.URLId == "" || e.Statement != statement || e.Overview != overview || e.Gain != gain || e.VideoURI != videoURI { } else if e.Title != ename || e.URLId == "" || e.Statement != statement || e.Overview != overview || e.Headline != headline || e.Gain != gain || e.VideoURI != videoURI {
e.Title = ename e.Title = ename
e.URLId = fic.ToURLid(ename) e.URLId = fic.ToURLid(ename)
e.Statement = statement e.Statement = statement
e.Overview = overview e.Overview = overview
e.Headline = headline
e.Gain = gain e.Gain = gain
e.VideoURI = videoURI e.VideoURI = videoURI
if _, err := e.Update(); err != nil { if _, err := e.Update(); err != nil {

View file

@ -62,6 +62,7 @@ func SyncThemes(i Importer) []string {
for _, tdir := range themes { for _, tdir := range themes {
var authors []string var authors []string
var intro string var intro string
var headline string
var image string var image string
var theme fic.Theme var theme fic.Theme
var tname string var tname string
@ -78,10 +79,19 @@ func SyncThemes(i Importer) []string {
continue continue
} else if intro, err = getFileContent(i, path.Join(tdir, "overview.txt")); err != nil { } 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)) errs = append(errs, fmt.Sprintf("%q: unable to get theme's overview: %s", tname, err))
} else if theme, err = fic.GetThemeByName(tname); err != nil { } else {
if _, err := fic.CreateTheme(tname, fic.ToURLid(tname), tdir, strings.Join(authors, ", "), intro, image); err != nil { // Split headline from intro
errs = append(errs, fmt.Sprintf("%q: an error occurs during add: %s", tdir, err)) ovrvw := strings.Split(intro, "\n")
continue 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
}
} }
} }
@ -90,6 +100,7 @@ func SyncThemes(i Importer) []string {
// Format overview (markdown) // Format overview (markdown)
intro = string(blackfriday.Run([]byte(intro))) intro = string(blackfriday.Run([]byte(intro)))
headline = string(blackfriday.Run([]byte(headline)))
if i.exists(path.Join(tdir, "heading.jpg")) { if i.exists(path.Join(tdir, "heading.jpg")) {
image = path.Join(tdir, "heading.jpg") image = path.Join(tdir, "heading.jpg")
@ -108,10 +119,11 @@ func SyncThemes(i Importer) []string {
} }
} }
if theme.Name != tname || theme.Authors != authors_str || theme.Intro != intro || theme.Image != image { if theme.Name != tname || theme.Authors != authors_str || theme.Headline != headline || theme.Intro != intro || theme.Image != image {
theme.Name = tname theme.Name = tname
theme.Authors = authors_str theme.Authors = authors_str
theme.Intro = intro theme.Intro = intro
theme.Headline = headline
theme.Image = image theme.Image = image
theme.Path = tdir theme.Path = tdir
if _, err := theme.Update(); err != nil { if _, err := theme.Update(); err != nil {

View file

@ -20,7 +20,8 @@
Vous n'avez pas encore accès à cet exercice. Vous n'avez pas encore accès à cet exercice.
</div> </div>
<div class="jumbotron niceborder text-indent mt-3" ng-if="!(my.exercices[current_exercice])"> <div class="jumbotron niceborder text-indent mt-3" ng-if="!(my.exercices[current_exercice])">
<p class="lead text-justify" ng-bind-html="themes[current_theme].intro"></p> <p class="lead text-justify" ng-bind-html="themes[current_theme].headline"></p>
<p class="text-justify" ng-bind-html="themes[current_theme].intro"></p>
</div> </div>
<div class="jumbotron niceborder text-indent mt-3" ng-if="(my.exercices[current_exercice])"> <div class="jumbotron niceborder text-indent mt-3" ng-if="(my.exercices[current_exercice])">
<h3 class="display-4">{{ themes[current_theme].exercices[current_exercice].title }}</h3> <h3 class="display-4">{{ themes[current_theme].exercices[current_exercice].title }}</h3>

View file

@ -22,7 +22,7 @@
<a ng-href="/{{ theme.urlid }}">{{ theme.name }}</a> <a ng-href="/{{ theme.urlid }}">{{ theme.name }}</a>
<a ng-href="/tags/{{tag}}" class="badge badge-pill badge-secondary ml-1 float-right">#tag</a> <a ng-href="/tags/{{tag}}" class="badge badge-pill badge-secondary ml-1 float-right">#tag</a>
</h5> </h5>
<p style="clear: both" class="card-text text-justify">Sunt omnis est quibusdam aperiam quos minima numquam. Omnis eos corrupti corrupti quia ut.</p> <p style="clear: both" class="card-text text-justify" ng-bind-html="theme.headline"></p>
</div> </div>
</div> </div>
</div> </div>

View file

@ -6,7 +6,7 @@
<a ng-href="/{{ex.theme.urlid}}/{{ex.exercice.urlid}}">{{ex.exercice.title}}</a> <a ng-href="/{{ex.theme.urlid}}/{{ex.exercice.urlid}}">{{ex.exercice.title}}</a>
<a ng-href="/tags/{{tag}}" class="badge badge-pill badge-secondary mr-2 float-right" ng-repeat="tag in themes[ex.tid].exercices[ex.eid].tags">#{{ tag }}</a> <a ng-href="/tags/{{tag}}" class="badge badge-pill badge-secondary mr-2 float-right" ng-repeat="tag in themes[ex.tid].exercices[ex.eid].tags">#{{ tag }}</a>
</h6> </h6>
<p style="clear: both" class="card-text text-justify">Sunt omnis est quibusdam aperiam quos minima numquam. Omnis eos corrupti corrupti quia ut.</p> <p style="clear: both" class="card-text text-justify" ng-bind-html="ex.exercice.headline"></p>
</div> </div>
</div> </div>
</div> </div>

View file

@ -1,5 +1,6 @@
<div class="jumbotron niceborder text-indent mt-2 mb-4"> <div class="jumbotron niceborder text-indent mt-2 mb-4">
<p class="lead text-justify" ng-bind-html="themes[current_theme].intro"></p> <p class="lead text-justify" ng-bind-html="themes[current_theme].headline"></p>
<p class="text-justify" ng-bind-html="themes[current_theme].intro"></p>
</div> </div>
<div class="card-group mb-5"> <div class="card-group mb-5">
@ -17,6 +18,6 @@
<span class="glyphicon glyphicon-ok" aria-hidden="true" ng-if="(my.team_id && my.exercices[k].solved)"></span> <span class="glyphicon glyphicon-ok" aria-hidden="true" ng-if="(my.team_id && my.exercices[k].solved)"></span>
<span class="glyphicon glyphicon-gift" aria-hidden="true" ng-if="themes[current_theme].exercices[k].curcoeff > 1.0" title="Un bonus est actuellement appliqué lors de la résolution de ce défi"></span> <span class="glyphicon glyphicon-gift" aria-hidden="true" ng-if="themes[current_theme].exercices[k].curcoeff > 1.0" title="Un bonus est actuellement appliqué lors de la résolution de ce défi"></span>
</h5> </h5>
<p style="clear: both" class="card-text text-justify">Sunt omnis est quibusdam aperiam quos minima numquam.</p> <p style="clear: both" class="card-text text-justify" ng-bind-html="exercice.headline"></p>
</div> </div>
</div> </div>

View file

@ -72,6 +72,7 @@ CREATE TABLE IF NOT EXISTS themes(
name VARCHAR(255) NOT NULL, name VARCHAR(255) NOT NULL,
url_id VARCHAR(191) NOT NULL UNIQUE, url_id VARCHAR(191) NOT NULL UNIQUE,
path VARCHAR(191) NOT NULL UNIQUE, path VARCHAR(191) NOT NULL UNIQUE,
headline TEXT NOT NULL,
intro TEXT NOT NULL, intro TEXT NOT NULL,
image VARCHAR(255) NOT NULL, image VARCHAR(255) NOT NULL,
authors TEXT NOT NULL authors TEXT NOT NULL
@ -116,6 +117,7 @@ CREATE TABLE IF NOT EXISTS exercices(
id_exercice INTEGER NOT NULL PRIMARY KEY AUTO_INCREMENT, id_exercice INTEGER NOT NULL PRIMARY KEY AUTO_INCREMENT,
id_theme INTEGER NOT NULL, id_theme INTEGER NOT NULL,
title VARCHAR(255) NOT NULL, title VARCHAR(255) NOT NULL,
headline TEXT NOT NULL,
url_id VARCHAR(255) NOT NULL, url_id VARCHAR(255) NOT NULL,
path VARCHAR(191) NOT NULL UNIQUE, path VARCHAR(191) NOT NULL UNIQUE,
statement TEXT NOT NULL, statement TEXT NOT NULL,

View file

@ -26,6 +26,8 @@ type Exercice struct {
Statement string `json:"statement"` Statement string `json:"statement"`
// Overview is the challenge description shown to public // Overview is the challenge description shown to public
Overview string `json:"overview"` Overview string `json:"overview"`
// Headline is the challenge headline to fill in small part
Headline string `json:"headline"`
// Issue is an optional text describing an issue with the exercice // Issue is an optional text describing an issue with the exercice
Issue string `json:"issue"` Issue string `json:"issue"`
// IssueKind is the criticity level of the previous issue // IssueKind is the criticity level of the previous issue
@ -45,7 +47,7 @@ type Exercice struct {
// GetExercice retrieves the challenge with the given id. // GetExercice retrieves the challenge with the given id.
func GetExercice(id int64) (Exercice, error) { func GetExercice(id int64) (Exercice, error) {
var e Exercice var e Exercice
if err := DBQueryRow("SELECT id_exercice, title, url_id, path, statement, overview, issue, issue_kind, depend, gain, coefficient_cur, video_uri FROM exercices WHERE id_exercice = ?", id).Scan(&e.Id, &e.Title, &e.URLId, &e.Path, &e.Statement, &e.Overview, &e.Issue, &e.IssueKind, &e.Depend, &e.Gain, &e.Coefficient, &e.VideoURI); err != nil { if err := DBQueryRow("SELECT id_exercice, title, url_id, path, statement, overview, headline, issue, issue_kind, depend, gain, coefficient_cur, video_uri FROM exercices WHERE id_exercice = ?", id).Scan(&e.Id, &e.Title, &e.URLId, &e.Path, &e.Statement, &e.Overview, &e.Headline, &e.Issue, &e.IssueKind, &e.Depend, &e.Gain, &e.Coefficient, &e.VideoURI); err != nil {
return Exercice{}, err return Exercice{}, err
} }
@ -55,7 +57,7 @@ func GetExercice(id int64) (Exercice, error) {
// GetExercice retrieves the challenge with the given id. // GetExercice retrieves the challenge with the given id.
func (t Theme) GetExercice(id int) (Exercice, error) { func (t Theme) GetExercice(id int) (Exercice, error) {
var e Exercice var e Exercice
if err := DBQueryRow("SELECT id_exercice, title, url_id, path, statement, overview, issue, issue_kind, depend, gain, coefficient_cur, video_uri FROM exercices WHERE id_theme = ? AND id_exercice = ?", t.Id, id).Scan(&e.Id, &e.Title, &e.URLId, &e.Path, &e.Statement, &e.Overview, &e.Issue, &e.IssueKind, &e.Depend, &e.Gain, &e.Coefficient, &e.VideoURI); err != nil { if err := DBQueryRow("SELECT id_exercice, title, url_id, path, statement, overview, headline, issue, issue_kind, depend, gain, coefficient_cur, video_uri FROM exercices WHERE id_theme = ? AND id_exercice = ?", t.Id, id).Scan(&e.Id, &e.Title, &e.URLId, &e.Path, &e.Statement, &e.Overview, &e.Headline, &e.Issue, &e.IssueKind, &e.Depend, &e.Gain, &e.Coefficient, &e.VideoURI); err != nil {
return Exercice{}, err return Exercice{}, err
} }
@ -65,7 +67,7 @@ func (t Theme) GetExercice(id int) (Exercice, error) {
// GetExerciceByTitle retrieves the challenge with the given title. // GetExerciceByTitle retrieves the challenge with the given title.
func (t Theme) GetExerciceByTitle(title string) (Exercice, error) { func (t Theme) GetExerciceByTitle(title string) (Exercice, error) {
var e Exercice var e Exercice
if err := DBQueryRow("SELECT id_exercice, title, url_id, path, statement, overview, issue, issue_kind, depend, gain, coefficient_cur, video_uri FROM exercices WHERE id_theme = ? AND title = ?", t.Id, title).Scan(&e.Id, &e.Title, &t.URLId, &e.Path, &e.Statement, &e.Overview, &e.Issue, &e.IssueKind, &e.Depend, &e.Gain, &e.Coefficient, &e.VideoURI); err != nil { if err := DBQueryRow("SELECT id_exercice, title, url_id, path, statement, overview, headline, issue, issue_kind, depend, gain, coefficient_cur, video_uri FROM exercices WHERE id_theme = ? AND title = ?", t.Id, title).Scan(&e.Id, &e.Title, &t.URLId, &e.Path, &e.Statement, &e.Overview, &e.Headline, &e.Issue, &e.IssueKind, &e.Depend, &e.Gain, &e.Coefficient, &e.VideoURI); err != nil {
return Exercice{}, err return Exercice{}, err
} }
@ -74,7 +76,7 @@ func (t Theme) GetExerciceByTitle(title string) (Exercice, error) {
// GetExercices returns the list of all challenges present in the database. // GetExercices returns the list of all challenges present in the database.
func GetExercices() ([]Exercice, error) { func GetExercices() ([]Exercice, error) {
if rows, err := DBQuery("SELECT id_exercice, title, url_id, path, statement, overview, issue, issue_kind, depend, gain, coefficient_cur, video_uri FROM exercices"); err != nil { if rows, err := DBQuery("SELECT id_exercice, title, url_id, path, statement, overview, headline, issue, issue_kind, depend, gain, coefficient_cur, video_uri FROM exercices"); err != nil {
return nil, err return nil, err
} else { } else {
defer rows.Close() defer rows.Close()
@ -82,7 +84,7 @@ func GetExercices() ([]Exercice, error) {
var exos = make([]Exercice, 0) var exos = make([]Exercice, 0)
for rows.Next() { for rows.Next() {
var e Exercice var e Exercice
if err := rows.Scan(&e.Id, &e.Title, &e.URLId, &e.Path, &e.Statement, &e.Overview, &e.Issue, &e.IssueKind, &e.Depend, &e.Gain, &e.Coefficient, &e.VideoURI); err != nil { if err := rows.Scan(&e.Id, &e.Title, &e.URLId, &e.Path, &e.Statement, &e.Overview, &e.Headline, &e.Issue, &e.IssueKind, &e.Depend, &e.Gain, &e.Coefficient, &e.VideoURI); err != nil {
return nil, err return nil, err
} }
exos = append(exos, e) exos = append(exos, e)
@ -97,7 +99,7 @@ func GetExercices() ([]Exercice, error) {
// GetExercices returns the list of all challenges in the Theme. // GetExercices returns the list of all challenges in the Theme.
func (t Theme) GetExercices() ([]Exercice, error) { func (t Theme) GetExercices() ([]Exercice, error) {
if rows, err := DBQuery("SELECT id_exercice, title, url_id, path, statement, overview, issue, issue_kind, depend, gain, coefficient_cur, video_uri FROM exercices WHERE id_theme = ?", t.Id); err != nil { if rows, err := DBQuery("SELECT id_exercice, title, url_id, path, statement, overview, headline, issue, issue_kind, depend, gain, coefficient_cur, video_uri FROM exercices WHERE id_theme = ?", t.Id); err != nil {
return nil, err return nil, err
} else { } else {
defer rows.Close() defer rows.Close()
@ -105,7 +107,7 @@ func (t Theme) GetExercices() ([]Exercice, error) {
var exos = make([]Exercice, 0) var exos = make([]Exercice, 0)
for rows.Next() { for rows.Next() {
var e Exercice var e Exercice
if err := rows.Scan(&e.Id, &e.Title, &e.URLId, &e.Path, &e.Statement, &e.Overview, &e.Issue, &e.IssueKind, &e.Depend, &e.Gain, &e.Coefficient, &e.VideoURI); err != nil { if err := rows.Scan(&e.Id, &e.Title, &e.URLId, &e.Path, &e.Statement, &e.Overview, &e.Headline, &e.Issue, &e.IssueKind, &e.Depend, &e.Gain, &e.Coefficient, &e.VideoURI); err != nil {
return nil, err return nil, err
} }
exos = append(exos, e) exos = append(exos, e)
@ -119,29 +121,29 @@ func (t Theme) GetExercices() ([]Exercice, error) {
} }
// AddExercice creates and fills a new struct Exercice and registers it into the database. // AddExercice creates and fills a new struct Exercice and registers it into the database.
func (t Theme) AddExercice(title string, urlId string, path string, statement string, overview string, depend *Exercice, gain int64, videoURI string) (Exercice, error) { func (t Theme) AddExercice(title string, urlId string, path string, statement string, overview string, headline string, depend *Exercice, gain int64, videoURI string) (Exercice, error) {
var dpd interface{} var dpd interface{}
if depend == nil { if depend == nil {
dpd = nil dpd = nil
} else { } else {
dpd = depend.Id dpd = depend.Id
} }
if res, err := DBExec("INSERT INTO exercices (id_theme, title, url_id, path, statement, overview, issue, depend, gain, video_uri) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", t.Id, title, urlId, path, statement, overview, "", dpd, gain, videoURI); err != nil { if res, err := DBExec("INSERT INTO exercices (id_theme, title, url_id, path, statement, overview, headline, issue, depend, gain, video_uri) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", t.Id, title, urlId, path, statement, overview, headline, "", dpd, gain, videoURI); err != nil {
return Exercice{}, err return Exercice{}, err
} else if eid, err := res.LastInsertId(); err != nil { } else if eid, err := res.LastInsertId(); err != nil {
return Exercice{}, err return Exercice{}, err
} else { } else {
if depend == nil { if depend == nil {
return Exercice{eid, title, urlId, path, statement, overview, "", "info", nil, gain, 1.0, videoURI}, nil return Exercice{eid, title, urlId, path, statement, overview, headline, "", "info", nil, gain, 1.0, videoURI}, nil
} else { } else {
return Exercice{eid, title, urlId, path, statement, overview, "", "info", &depend.Id, gain, 1.0, videoURI}, nil return Exercice{eid, title, urlId, path, statement, overview, headline, "", "info", &depend.Id, gain, 1.0, videoURI}, nil
} }
} }
} }
// Update applies modifications back to the database. // Update applies modifications back to the database.
func (e Exercice) Update() (int64, error) { func (e Exercice) Update() (int64, error) {
if res, err := DBExec("UPDATE exercices SET title = ?, url_id = ?, path = ?, statement = ?, overview = ?, issue = ?, issue_kind = ?, depend = ?, gain = ?, coefficient_cur = ?, video_uri = ? WHERE id_exercice = ?", e.Title, e.URLId, e.Path, e.Statement, e.Overview, e.Issue, e.IssueKind, e.Depend, e.Gain, e.Coefficient, e.VideoURI, e.Id); err != nil { if res, err := DBExec("UPDATE exercices SET title = ?, url_id = ?, path = ?, statement = ?, overview = ?, headline = ?, issue = ?, issue_kind = ?, depend = ?, gain = ?, coefficient_cur = ?, video_uri = ? WHERE id_exercice = ?", e.Title, e.URLId, e.Path, e.Statement, e.Overview, e.Headline, e.Issue, e.IssueKind, e.Depend, e.Gain, e.Coefficient, e.VideoURI, e.Id); err != nil {
return 0, err return 0, err
} else if nb, err := res.RowsAffected(); err != nil { } else if nb, err := res.RowsAffected(); err != nil {
return 0, err return 0, err

View file

@ -4,18 +4,19 @@ import ()
// Theme represents a group of challenges, to display to players // Theme represents a group of challenges, to display to players
type Theme struct { type Theme struct {
Id int64 `json:"id"` Id int64 `json:"id"`
Name string `json:"name"` Name string `json:"name"`
URLId string `json:"urlid"` URLId string `json:"urlid"`
Path string `json:"path"` Path string `json:"path"`
Authors string `json:"authors,omitempty"` Authors string `json:"authors,omitempty"`
Intro string `json:"intro,omitempty"` Intro string `json:"intro,omitempty"`
Image string `json:"image,omitempty"` Headline string `json:"headline,omitempty"`
Image string `json:"image,omitempty"`
} }
// GetThemes returns a list of registered Themes from the database. // GetThemes returns a list of registered Themes from the database.
func GetThemes() ([]Theme, error) { func GetThemes() ([]Theme, error) {
if rows, err := DBQuery("SELECT id_theme, name, url_id, path, authors, intro, image FROM themes"); err != nil { if rows, err := DBQuery("SELECT id_theme, name, url_id, path, authors, intro, headline, image FROM themes"); err != nil {
return nil, err return nil, err
} else { } else {
defer rows.Close() defer rows.Close()
@ -23,7 +24,7 @@ func GetThemes() ([]Theme, error) {
var themes = make([]Theme, 0) var themes = make([]Theme, 0)
for rows.Next() { for rows.Next() {
var t Theme var t Theme
if err := rows.Scan(&t.Id, &t.Name, &t.URLId, &t.Path, &t.Authors, &t.Intro, &t.Image); err != nil { if err := rows.Scan(&t.Id, &t.Name, &t.URLId, &t.Path, &t.Authors, &t.Intro, &t.Headline, &t.Image); err != nil {
return nil, err return nil, err
} }
themes = append(themes, t) themes = append(themes, t)
@ -39,7 +40,7 @@ func GetThemes() ([]Theme, error) {
// GetTheme retrieves a Theme from its identifier. // GetTheme retrieves a Theme from its identifier.
func GetTheme(id int64) (Theme, error) { func GetTheme(id int64) (Theme, error) {
var t Theme var t Theme
if err := DBQueryRow("SELECT id_theme, name, url_id, path, authors, intro, image FROM themes WHERE id_theme=?", id).Scan(&t.Id, &t.Name, &t.URLId, &t.Path, &t.Authors, &t.Intro, &t.Image); err != nil { if err := DBQueryRow("SELECT id_theme, name, url_id, path, authors, intro, headline, image FROM themes WHERE id_theme=?", id).Scan(&t.Id, &t.Name, &t.URLId, &t.Path, &t.Authors, &t.Intro, &t.Headline, &t.Image); err != nil {
return t, err return t, err
} }
@ -49,7 +50,7 @@ func GetTheme(id int64) (Theme, error) {
// GetThemeByName retrieves a Theme from its title // GetThemeByName retrieves a Theme from its title
func GetThemeByName(name string) (Theme, error) { func GetThemeByName(name string) (Theme, error) {
var t Theme var t Theme
if err := DBQueryRow("SELECT id_theme, name, url_id, path, authors, intro, image FROM themes WHERE name=?", name).Scan(&t.Id, &t.Name, &t.URLId, &t.Path, &t.Authors, &t.Intro, &t.Image); err != nil { if err := DBQueryRow("SELECT id_theme, name, url_id, path, authors, intro, headline, image FROM themes WHERE name=?", name).Scan(&t.Id, &t.Name, &t.URLId, &t.Path, &t.Authors, &t.Intro, &t.Headline, &t.Image); err != nil {
return t, err return t, err
} }
@ -57,13 +58,13 @@ func GetThemeByName(name string) (Theme, error) {
} }
// CreateTheme creates and fills a new struct Theme and registers it into the database. // 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, image string) (Theme, error) { 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, image) VALUES (?, ?, ?, ?, ?, ?)", name, url_id, authors, path, intro, image); err != nil { 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 {
return Theme{}, err return Theme{}, err
} else if tid, err := res.LastInsertId(); err != nil { } else if tid, err := res.LastInsertId(); err != nil {
return Theme{}, err return Theme{}, err
} else { } else {
return Theme{tid, name, url_id, path, authors, intro, image}, nil return Theme{tid, name, url_id, path, authors, intro, headline, image}, nil
} }
} }
@ -79,7 +80,7 @@ func (t *Theme) FixURLId() bool {
// Update applies modifications back to the database. // Update applies modifications back to the database.
func (t Theme) Update() (int64, error) { func (t Theme) Update() (int64, error) {
if res, err := DBExec("UPDATE themes SET name = ?, url_id = ?, authors = ?, path = ?, intro = ?, image = ? WHERE id_theme = ?", t.Name, t.URLId, t.Authors, t.Path, t.Intro, t.Image, t.Id); err != nil { if res, err := DBExec("UPDATE themes SET name = ?, url_id = ?, authors = ?, path = ?, intro = ?, headline = ?, image = ? WHERE id_theme = ?", t.Name, t.URLId, t.Authors, t.Path, t.Intro, t.Headline, t.Image, t.Id); err != nil {
return 0, err return 0, err
} else if nb, err := res.RowsAffected(); err != nil { } else if nb, err := res.RowsAffected(); err != nil {
return 0, err return 0, err

View file

@ -7,13 +7,14 @@ import (
// exportedExercice is a structure representing a challenge, as exposed to players. // exportedExercice is a structure representing a challenge, as exposed to players.
type exportedExercice struct { type exportedExercice struct {
Title string `json:"title"` Title string `json:"title"`
URLId string `json:"urlid"` Headline string `json:"headline,omitempty"`
Tags []string `json:"tags"` URLId string `json:"urlid"`
Gain int64 `json:"gain"` Tags []string `json:"tags"`
Coeff float64 `json:"curcoeff"` Gain int64 `json:"gain"`
Solved int64 `json:"solved"` Coeff float64 `json:"curcoeff"`
Tried int64 `json:"tried"` Solved int64 `json:"solved"`
Tried int64 `json:"tried"`
} }
// exportedTheme is a structure representing a Theme, as exposed to players. // exportedTheme is a structure representing a Theme, as exposed to players.
@ -21,6 +22,7 @@ type exportedTheme struct {
Name string `json:"name"` Name string `json:"name"`
URLId string `json:"urlid"` URLId string `json:"urlid"`
Authors string `json:"authors"` Authors string `json:"authors"`
Headline string `json:"headline,omitempty"`
Intro string `json:"intro"` Intro string `json:"intro"`
Image string `json:"image,omitempty"` Image string `json:"image,omitempty"`
Exercices map[string]exportedExercice `json:"exercices"` Exercices map[string]exportedExercice `json:"exercices"`
@ -41,6 +43,7 @@ func ExportThemes() (interface{}, error) {
tags, _ := exercice.GetTags() tags, _ := exercice.GetTags()
exos[fmt.Sprintf("%d", exercice.Id)] = exportedExercice{ exos[fmt.Sprintf("%d", exercice.Id)] = exportedExercice{
exercice.Title, exercice.Title,
exercice.Headline,
exercice.URLId, exercice.URLId,
tags, tags,
exercice.Gain, exercice.Gain,
@ -59,6 +62,7 @@ func ExportThemes() (interface{}, error) {
theme.Name, theme.Name,
theme.URLId, theme.URLId,
theme.Authors, theme.Authors,
theme.Headline,
theme.Intro, theme.Intro,
imgpath, imgpath,
exos, exos,