Extract background color to continue image
This commit is contained in:
parent
35d07c1aa4
commit
26c282138e
|
@ -677,7 +677,7 @@ func createExercice(c *gin.Context) {
|
|||
}
|
||||
}
|
||||
|
||||
exercice, err := theme.AddExercice(ue.Title, ue.Authors, ue.Image, ue.WIP, ue.URLId, ue.Path, ue.Statement, ue.Overview, ue.Headline, depend, ue.Gain, ue.VideoURI, ue.Resolution, ue.SeeAlso, ue.Finished)
|
||||
exercice, err := theme.AddExercice(ue.Title, ue.Authors, ue.Image, ue.BackgroundColor, ue.WIP, ue.URLId, ue.Path, ue.Statement, ue.Overview, ue.Headline, depend, ue.Gain, ue.VideoURI, ue.Resolution, ue.SeeAlso, ue.Finished)
|
||||
if err != nil {
|
||||
log.Println("Unable to createExercice:", err.Error())
|
||||
c.AbortWithStatusJSON(http.StatusInternalServerError, gin.H{"errmsg": "An error occurs during exercice creation."})
|
||||
|
|
|
@ -1715,7 +1715,7 @@ angular.module("FICApp")
|
|||
})
|
||||
.controller("ThemeController", function($scope, Theme, $routeParams, $location, $rootScope, $http) {
|
||||
$scope.theme = Theme.get({ themeId: $routeParams.themeId });
|
||||
$scope.fields = ["name", "urlid", "locked", "authors", "headline", "intro", "image", "partner_txt", "partner_href", "partner_img"];
|
||||
$scope.fields = ["name", "urlid", "locked", "authors", "headline", "intro", "image", "background_color", "partner_txt", "partner_href", "partner_img"];
|
||||
|
||||
$scope.saveTheme = function() {
|
||||
if (this.theme.id) {
|
||||
|
@ -1893,7 +1893,7 @@ angular.module("FICApp")
|
|||
}
|
||||
});
|
||||
$scope.exercices = Exercice.query();
|
||||
$scope.fields = ["title", "urlid", "authors", "disabled", "statement", "headline", "overview", "finished", "depend", "gain", "coefficient", "videoURI", "image", "resolution", "issue", "issuekind", "wip"];
|
||||
$scope.fields = ["title", "urlid", "authors", "disabled", "statement", "headline", "overview", "finished", "depend", "gain", "coefficient", "videoURI", "image", "background_color", "resolution", "issue", "issuekind", "wip"];
|
||||
|
||||
$scope.inSync = false;
|
||||
$scope.syncExo = function() {
|
||||
|
|
|
@ -21,7 +21,7 @@
|
|||
<div class="form-group row" ng-repeat="field in fields">
|
||||
<label for="{{ field }}" class="col-sm-1 col-form-label-sm">{{ field | capitalize }}</label>
|
||||
<div class="col-sm-11">
|
||||
<input type="text" class="form-control form-control-sm" id="{{ field }}" ng-model="exercice[field]" ng-if="field != 'statement' && field != 'issue' && field != 'issuekind' && field != 'overview' && field != 'resolution' && field != 'finished' && field != 'depend' && field != 'gain' && field != 'coefficient' && field != 'wip' && field != 'disabled'">
|
||||
<input type="text" class="form-control form-control-sm" id="{{ field }}" ng-model="exercice[field]" ng-if="field != 'statement' && field != 'issue' && field != 'issuekind' && field != 'overview' && field != 'resolution' && field != 'finished' && field != 'depend' && field != 'gain' && field != 'coefficient' && field != 'wip' && field != 'disabled' && field != 'background_color'">
|
||||
<input type="checkbox" id="{{ field }}" ng-model="exercice[field]" ng-if="field == 'wip' || field == 'disabled'">
|
||||
<input type="text" class="form-control form-control-sm" id="{{ field }}" ng-model="exercice[field]" ng-if="field == 'gain'" integer>
|
||||
<input type="text" class="form-control form-control-sm" id="{{ field }}" ng-model="exercice[field]" ng-if="field == 'coefficient'" float>
|
||||
|
@ -30,6 +30,7 @@
|
|||
<option value="">Aucune</option>
|
||||
</select>
|
||||
<select class="form-control form-control-sm" id="{{field}}" ng-model="exercice[field]" ng-options="v for v in ['primary', 'secondary', 'success', 'danger', 'warning', 'info', 'light', 'dark']" ng-if="field == 'issuekind'"></select>
|
||||
<input type="color" class="form-control form-control-sm" id="{{ field }}" ng-model="exercice[field]" ng-if="field == 'background_color'" color>
|
||||
</div>
|
||||
</div>
|
||||
<div class="text-right" ng-show="exercice.id">
|
||||
|
|
|
@ -12,8 +12,9 @@
|
|||
<div ng-class="{'form-group': field != 'locked', 'form-check': field == 'locked'}" ng-repeat="field in fields">
|
||||
<input type="checkbox" class="form-check-input" id="{{ field }}" ng-model="theme[field]" ng-if="field == 'locked'">
|
||||
<label for="{{ field }}">{{ field | capitalize }}</label>
|
||||
<input type="text" class="form-control form-control-sm" id="{{ field }}" ng-model="theme[field]" ng-if="field != 'intro' && field != 'locked'">
|
||||
<input type="text" class="form-control form-control-sm" id="{{ field }}" ng-model="theme[field]" ng-if="field != 'intro' && field != 'locked' && field != 'background_color'">
|
||||
<textarea class="form-control form-control-sm" id="{{ field }}" ng-model="theme[field]" ng-if="field == 'intro'"></textarea>
|
||||
<input type="color" class="form-control form-control-sm" id="{{ field }}" ng-model="theme[field]" ng-if="field == 'background_color'" color>
|
||||
</div>
|
||||
<div class="text-right" ng-show="theme.id">
|
||||
<button type="submit" class="btn btn-success"><span class="glyphicon glyphicon-save" aria-hidden="true"></span> Save</button>
|
||||
|
|
|
@ -397,6 +397,8 @@ func SyncExercice(i Importer, theme *fic.Theme, epath string, dmap *map[int64]*f
|
|||
|
||||
e.Image = strings.TrimPrefix(filePath, fic.FilesDir)
|
||||
|
||||
e.BackgroundColor, _ = getBackgroundColor(filePath)
|
||||
|
||||
// If the theme has no image yet, use the first exercice's image found
|
||||
theme.Image = e.Image
|
||||
_, err := theme.Update()
|
||||
|
|
|
@ -13,6 +13,7 @@ import (
|
|||
"strings"
|
||||
"unicode"
|
||||
|
||||
"github.com/cenkalti/dominantcolor"
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/yuin/goldmark"
|
||||
"go.uber.org/multierr"
|
||||
|
@ -86,6 +87,49 @@ func resizePicture(importedPath string, rect image.Rectangle) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
type SubImager interface {
|
||||
SubImage(r image.Rectangle) image.Image
|
||||
}
|
||||
|
||||
// getBackgroundColor retrieves the most dominant color in the bottom of the image.
|
||||
func getBackgroundColor(importedPath string) (uint32, error) {
|
||||
fl, err := os.Open(strings.TrimSuffix(importedPath, ".jpg") + ".thumb.jpg")
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
src, _, err := image.Decode(fl)
|
||||
if err != nil {
|
||||
fl.Close()
|
||||
return 0, err
|
||||
}
|
||||
|
||||
bounds := src.Bounds()
|
||||
|
||||
// Test if the right and left corner have the same color
|
||||
bottomLeft := src.(SubImager).SubImage(image.Rect(0, bounds.Dy()-10, 40, bounds.Dy()))
|
||||
bottomRight := src.(SubImager).SubImage(image.Rect(bounds.Dx()-40, bounds.Dy()-10, bounds.Dx(), bounds.Dy()))
|
||||
|
||||
colorLeft := dominantcolor.Find(bottomLeft)
|
||||
colorRight := dominantcolor.Find(bottomRight)
|
||||
if uint32(colorLeft.R>>5)<<16+uint32(colorLeft.G>>5)<<8+uint32(colorLeft.B>>5) == uint32(colorRight.R>>5)<<16+uint32(colorRight.G>>5)<<8+uint32(colorRight.B>>5) {
|
||||
return uint32(colorLeft.R)<<16 + uint32(colorLeft.G)<<8 + uint32(colorLeft.B), nil
|
||||
}
|
||||
|
||||
// Only keep the darkest color of the bottom of the image
|
||||
bottomFull := src.(SubImager).SubImage(image.Rect(0, bounds.Dy()-5, bounds.Dx(), bounds.Dy()))
|
||||
colors := dominantcolor.FindN(bottomFull, 4)
|
||||
|
||||
color := colors[0]
|
||||
for _, c := range colors {
|
||||
if uint32(color.R<<2)+uint32(color.G<<2)+uint32(color.B<<2) > uint32(c.R<<2)+uint32(c.G<<2)+uint32(c.B<<2) {
|
||||
color = c
|
||||
}
|
||||
}
|
||||
|
||||
return uint32(color.R)<<16 + uint32(color.G)<<8 + uint32(color.B), nil
|
||||
}
|
||||
|
||||
// getAuthors parses the AUTHORS file.
|
||||
func getAuthors(i Importer, tname string) ([]string, error) {
|
||||
if authors, err := GetFileContent(i, path.Join(tname, "AUTHORS.txt")); err != nil {
|
||||
|
@ -258,6 +302,7 @@ func SyncThemes(i Importer) (exceptions map[string]*CheckExceptions, errs error)
|
|||
}
|
||||
|
||||
btheme.Image = strings.TrimPrefix(filePath, fic.FilesDir)
|
||||
btheme.BackgroundColor, _ = getBackgroundColor(filePath)
|
||||
return nil, nil
|
||||
}); err != nil {
|
||||
errs = multierr.Append(errs, NewThemeError(btheme, fmt.Errorf("unable to import heading image: %w", err)))
|
||||
|
|
|
@ -22,6 +22,9 @@
|
|||
import { settings } from '$lib/stores/settings.js';
|
||||
import { themesStore } from '$lib/stores/themes.js';
|
||||
|
||||
// Override theme color
|
||||
document.body.style.backgroundColor = "";
|
||||
|
||||
let items = [];
|
||||
$: {
|
||||
const tmpitems = [];
|
||||
|
|
|
@ -12,7 +12,21 @@
|
|||
|
||||
let heading_image = "";
|
||||
let current_authors = "";
|
||||
let background_color = "#ffffff";
|
||||
let color_brightness = 0;
|
||||
$: color_brightness = parseInt(background_color[1], 16) + parseInt(background_color[3], 16) + parseInt(background_color[5], 16);
|
||||
$: if ($current_theme) {
|
||||
if ($current_exercice && $current_exercice.background_color) {
|
||||
background_color = $current_exercice.background_color;
|
||||
document.body.style.backgroundColor = $current_exercice.background_color;
|
||||
} else if ($current_theme.background_color) {
|
||||
background_color = $current_theme.background_color;
|
||||
document.body.style.backgroundColor = $current_theme.background_color;
|
||||
} else {
|
||||
background_color = "#ffffff";
|
||||
document.body.style.backgroundColor = "";
|
||||
}
|
||||
|
||||
if ($current_exercice && $current_exercice.image) {
|
||||
heading_image = $current_exercice.image;
|
||||
} else {
|
||||
|
@ -48,13 +62,21 @@
|
|||
</Container>
|
||||
{:else}
|
||||
<div style="background-image: url({heading_image})" class="page-header">
|
||||
<Container class="text-primary">
|
||||
<h1 class="display-2">
|
||||
{#if $current_theme.urlid == "_" && $current_exercice}
|
||||
<a href="{$current_theme.urlid}">{$current_exercice.title}</a>
|
||||
{:else}
|
||||
<a href="{$current_theme.urlid}">{$current_theme.name}</a>
|
||||
{/if}
|
||||
<Container class="text-primary py-4">
|
||||
<h1
|
||||
class="display-2"
|
||||
style:text-shadow={color_brightness < 24 ? "0 0 15px rgba(255,255,255,0.95), 0 0 5px rgb(255,255,255)" : "0 0 15px rgba(0,0,0,0.95), 0 0 5px rgb(0,0,0)"}
|
||||
>
|
||||
<a
|
||||
href="{$current_theme.urlid}"
|
||||
style:color={background_color}
|
||||
>
|
||||
{#if $current_theme.urlid == "_" && $current_exercice}
|
||||
{$current_exercice.title}
|
||||
{:else}
|
||||
{$current_theme.name}
|
||||
{/if}
|
||||
</a>
|
||||
</h1>
|
||||
<h2>
|
||||
{#if current_authors}
|
||||
|
@ -64,29 +86,21 @@
|
|||
{/if}
|
||||
</h2>
|
||||
</Container>
|
||||
{#if heading_image}
|
||||
<div class="headerfade"></div>
|
||||
{:else}
|
||||
<div style="height: 3rem;"></div>
|
||||
{/if}
|
||||
<Container class="pb-4">
|
||||
<slot></slot>
|
||||
</Container>
|
||||
</div>
|
||||
<Container>
|
||||
<slot></slot>
|
||||
</Container>
|
||||
{/if}
|
||||
|
||||
<style>
|
||||
.page-header {
|
||||
background-size: cover;
|
||||
background-position: center;
|
||||
margin-bottom: -15rem;
|
||||
}
|
||||
.page-header h1 {
|
||||
text-shadow: 0 0 15px rgba(255,255,255,0.95), 0 0 5px rgb(255,255,255)
|
||||
background-size: 100% auto;
|
||||
background-position: top center;
|
||||
background-repeat: no-repeat;
|
||||
}
|
||||
.page-header h1, .page-header h1 a {
|
||||
color: black;
|
||||
text-decoration: none;
|
||||
filter: invert(100%) hue-rotate(45deg) brightness(100%);
|
||||
}
|
||||
.page-header h2 {
|
||||
font-size: 100%;
|
||||
|
@ -99,16 +113,9 @@
|
|||
text-decoration: underline;
|
||||
}
|
||||
.page-header h1 {
|
||||
padding-top: 4rem;
|
||||
text-align: center;
|
||||
}
|
||||
.page-header h2 {
|
||||
padding-bottom: 14rem;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.page-header .headerfade {
|
||||
background: linear-gradient(transparent 0%, rgb(233,236,239) 100%);
|
||||
height: 3rem;
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -37,7 +37,7 @@
|
|||
/>
|
||||
</Masonry>
|
||||
{:else}
|
||||
<Card class="bg-dark niceborder text-indent mt-2 mb-4">
|
||||
<Card class="bg-dark niceborder text-indent mt-2" style="--bs-bg-opacity: .9;">
|
||||
|
||||
<Row>
|
||||
<Col lg={6} xl={7}>
|
||||
|
|
|
@ -51,8 +51,8 @@
|
|||
</script>
|
||||
|
||||
{#if $current_exercice}
|
||||
<Card class="niceborder text-indent my-3">
|
||||
<CardBody class="bg-dark">
|
||||
<Card class="niceborder text-indent my-3 bg-primary" style="--bs-bg-opacity: .9;">
|
||||
<CardBody class="bg-dark" style="--bs-bg-opacity: .5;">
|
||||
{#if $current_theme.locked}
|
||||
<div style="position: absolute; z-index: 0; top: 0; bottom: 0; left: 0; right: 0;" class="d-flex justify-content-center align-items-center">
|
||||
<div style="transform: rotate(-25deg)">
|
||||
|
@ -91,7 +91,7 @@
|
|||
<CardBody>
|
||||
<Row>
|
||||
<Col>
|
||||
<Row class="level" cols={{xs:2, md:3, xl:4}}>
|
||||
<Row class="level text-light" cols={{xs:2, md:3, xl:4}}>
|
||||
<Col>
|
||||
<div class="level-item">
|
||||
{#if $settings.discountedFactor > 0 && $my && $my.exercices[$current_exercice.id]}
|
||||
|
|
|
@ -17,6 +17,9 @@
|
|||
|
||||
import { my } from '$lib/stores/my.js';
|
||||
import { settings } from '$lib/stores/settings.js';
|
||||
|
||||
// Override theme color
|
||||
document.body.style.backgroundColor = "";
|
||||
</script>
|
||||
|
||||
<Container class="my-3">
|
||||
|
|
|
@ -17,6 +17,9 @@
|
|||
|
||||
import FormIssue from '$lib/components/FormIssue.svelte';
|
||||
|
||||
// Override theme color
|
||||
document.body.style.backgroundColor = "";
|
||||
|
||||
export let data;
|
||||
let issue = {};
|
||||
|
||||
|
|
|
@ -17,6 +17,9 @@
|
|||
import CardTheme from '$lib/components/CardTheme.svelte';
|
||||
|
||||
let search = "";
|
||||
|
||||
// Override theme color
|
||||
document.body.style.backgroundColor = "";
|
||||
</script>
|
||||
|
||||
<Container fluid class="my-3">
|
||||
|
|
|
@ -85,6 +85,9 @@
|
|||
message = "Une erreur est survenue lors de l'inscription de l'équipe. Veuillez réessayer dans quelques instants.";
|
||||
}
|
||||
}
|
||||
|
||||
// Override theme color
|
||||
document.body.style.backgroundColor = "";
|
||||
</script>
|
||||
|
||||
<Container class="my-3">
|
||||
|
|
|
@ -8,6 +8,9 @@
|
|||
|
||||
import { challengeInfo } from '$lib/stores/challengeinfo.js';
|
||||
import { settings } from '$lib/stores/settings.js';
|
||||
|
||||
// Override theme color
|
||||
document.body.style.backgroundColor = "";
|
||||
</script>
|
||||
|
||||
<Container class="my-3">
|
||||
|
|
|
@ -11,6 +11,9 @@
|
|||
|
||||
import { themesStore } from '$lib/stores/themes.js';
|
||||
|
||||
// Override theme color
|
||||
document.body.style.backgroundColor = "";
|
||||
|
||||
tick().then(() => {
|
||||
WordCloud(
|
||||
document.getElementById('wordcloud'),
|
||||
|
|
|
@ -33,6 +33,9 @@
|
|||
|
||||
exercices = tmp_exercices;
|
||||
}
|
||||
|
||||
// Override theme color
|
||||
document.body.style.backgroundColor = "";
|
||||
</script>
|
||||
|
||||
<Container class="mt-3">
|
||||
|
|
2
go.mod
2
go.mod
|
@ -31,9 +31,11 @@ require (
|
|||
github.com/asticode/go-astits v1.8.0 // indirect
|
||||
github.com/aws/aws-sdk-go v1.38.20 // indirect
|
||||
github.com/bytedance/sonic v1.9.1 // indirect
|
||||
github.com/cenkalti/dominantcolor v1.0.2 // indirect
|
||||
github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 // indirect
|
||||
github.com/cloudflare/circl v1.3.3 // indirect
|
||||
github.com/cyphar/filepath-securejoin v0.2.4 // indirect
|
||||
github.com/disintegration/imaging v1.6.2 // indirect
|
||||
github.com/emirpasic/gods v1.18.1 // indirect
|
||||
github.com/fsnotify/fsnotify v1.6.0 // indirect
|
||||
github.com/gabriel-vasile/mimetype v1.4.2 // indirect
|
||||
|
|
3
go.sum
3
go.sum
|
@ -65,6 +65,8 @@ github.com/bytedance/sonic v1.8.0 h1:ea0Xadu+sHlu7x5O3gKhRpQ1IKiMrSiHttPF0ybECuA
|
|||
github.com/bytedance/sonic v1.8.0/go.mod h1:i736AoUSYt75HyZLoJW9ERYxcy6eaN6h4BZXU064P/U=
|
||||
github.com/bytedance/sonic v1.9.1 h1:6iJ6NqdoxCDr6mbY8h18oSO+cShGSMRGCEo7F2h0x8s=
|
||||
github.com/bytedance/sonic v1.9.1/go.mod h1:i736AoUSYt75HyZLoJW9ERYxcy6eaN6h4BZXU064P/U=
|
||||
github.com/cenkalti/dominantcolor v1.0.2 h1:nP1qLG2sD4vu+mGjvEcp3zMaiT7OvcRDtp+wE0YEtfg=
|
||||
github.com/cenkalti/dominantcolor v1.0.2/go.mod h1:HvN7ziRLPAes3UkUrLDDRADCPTFsKUzZx5ZAQx8KECc=
|
||||
github.com/chenzhuoyu/base64x v0.0.0-20211019084208-fb5309c8db06/go.mod h1:DH46F32mSOjUmXrMHnKwZdA8wcEefY7UVqBKYGjpdQY=
|
||||
github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 h1:qSGYFH7+jGhDF8vLC+iwCD4WpbV1EBDSzWkJODFLams=
|
||||
github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311/go.mod h1:b583jCggY9gE99b6G5LEC39OIiVsWj+R97kbl5odCEk=
|
||||
|
@ -78,6 +80,7 @@ github.com/cyphar/filepath-securejoin v0.2.4/go.mod h1:aPGpWjXOXUn2NCNjFvBE6aRxG
|
|||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/disintegration/imaging v1.6.2 h1:w1LecBlG2Lnp8B3jk5zSuNqd7b4DXhcjwek1ei82L+c=
|
||||
github.com/disintegration/imaging v1.6.2/go.mod h1:44/5580QXChDfwIclfc/PCwrr44amcmDAg8hxG0Ewe4=
|
||||
github.com/emirpasic/gods v1.12.0 h1:QAUIPSaCu4G+POclxeqb3F+WPpdKqFGlw36+yOzGlrg=
|
||||
github.com/emirpasic/gods v1.12.0/go.mod h1:YfzfFFoVP/catgzJb4IKIqXjX78Ha8FMSDh3ymbK86o=
|
||||
|
|
|
@ -94,6 +94,7 @@ CREATE TABLE IF NOT EXISTS themes(
|
|||
headline TEXT NOT NULL,
|
||||
intro TEXT NOT NULL,
|
||||
image VARCHAR(255) NOT NULL,
|
||||
background_color INTEGER UNSIGNED NOT NULL,
|
||||
authors TEXT NOT NULL,
|
||||
partner_img VARCHAR(255) NOT NULL,
|
||||
partner_href VARCHAR(255) NOT NULL,
|
||||
|
@ -106,7 +107,7 @@ CREATE TABLE IF NOT EXISTS themes(
|
|||
CREATE TABLE IF NOT EXISTS teams(
|
||||
id_team INTEGER NOT NULL PRIMARY KEY AUTO_INCREMENT,
|
||||
name VARCHAR(255) NOT NULL,
|
||||
color INTEGER NOT NULL,
|
||||
color INTEGER UNSIGNED NOT NULL,
|
||||
active BOOLEAN NOT NULL DEFAULT 1,
|
||||
external_id TEXT NOT NULL,
|
||||
password VARCHAR(255) NULL
|
||||
|
@ -144,6 +145,7 @@ CREATE TABLE IF NOT EXISTS exercices(
|
|||
title VARCHAR(255) NOT NULL,
|
||||
authors TEXT NOT NULL,
|
||||
image VARCHAR(255) NOT NULL,
|
||||
background_color INTEGER UNSIGNED NOT NULL,
|
||||
disabled BOOLEAN NOT NULL DEFAULT 0,
|
||||
headline TEXT NOT NULL,
|
||||
url_id VARCHAR(255) NOT NULL,
|
||||
|
@ -564,7 +566,7 @@ func DBRecreateDiscountedView() (err error) {
|
|||
return
|
||||
}
|
||||
|
||||
_, err = db.Exec("CREATE OR REPLACE VIEW exercices_discounted AS SELECT E.id_exercice, E.id_theme, E.title, E.authors, E.image, E.disabled, E.headline, E.url_id, E.path, E.statement, E.overview, E.issue, E.issue_kind, E.depend, E.gain - " + fmt.Sprintf("%f", DiscountedFactor) + " * E.gain * (COUNT(*) - 1) AS gain, E.coefficient_cur, E.finished, E.video_uri, E.resolution, E.seealso FROM exercices E LEFT OUTER JOIN exercice_solved S ON S.id_exercice = E.id_exercice GROUP BY E.id_exercice;")
|
||||
_, err = db.Exec("CREATE OR REPLACE VIEW exercices_discounted AS SELECT E.id_exercice, E.id_theme, E.title, E.authors, E.image, E.background_color, E.disabled, E.headline, E.url_id, E.path, E.statement, E.overview, E.issue, E.issue_kind, E.depend, E.gain - " + fmt.Sprintf("%f", DiscountedFactor) + " * E.gain * (COUNT(*) - 1) AS gain, E.coefficient_cur, E.finished, E.video_uri, E.resolution, E.seealso FROM exercices E LEFT OUTER JOIN exercice_solved S ON S.id_exercice = E.id_exercice GROUP BY E.id_exercice;")
|
||||
return
|
||||
}
|
||||
|
||||
|
|
|
@ -21,12 +21,13 @@ var ExerciceCurrentCoefficient = 1.0
|
|||
|
||||
// Exercice represents a challenge inside a Theme.
|
||||
type Exercice struct {
|
||||
Id int64 `json:"id"`
|
||||
IdTheme *int64 `json:"id_theme"`
|
||||
Language string `json:"lang,omitempty"`
|
||||
Title string `json:"title"`
|
||||
Authors string `json:"authors"`
|
||||
Image string `json:"image"`
|
||||
Id int64 `json:"id"`
|
||||
IdTheme *int64 `json:"id_theme"`
|
||||
Language string `json:"lang,omitempty"`
|
||||
Title string `json:"title"`
|
||||
Authors string `json:"authors"`
|
||||
Image string `json:"image"`
|
||||
BackgroundColor uint32 `json:"background_color,omitempty"`
|
||||
// Disabled indicates if the exercice is available to players now or not
|
||||
Disabled bool `json:"disabled"`
|
||||
// WIP indicates if the exercice is in development or not
|
||||
|
@ -75,7 +76,7 @@ func (e *Exercice) AnalyzeTitle() {
|
|||
func getExercice(table, condition string, args ...interface{}) (*Exercice, error) {
|
||||
var e Exercice
|
||||
var tmpgain float64
|
||||
if err := DBQueryRow("SELECT id_exercice, id_theme, title, authors, image, disabled, url_id, path, statement, overview, headline, issue, issue_kind, depend, gain, coefficient_cur, video_uri, resolution, seealso, finished FROM "+table+" "+condition, args...).Scan(&e.Id, &e.IdTheme, &e.Title, &e.Authors, &e.Image, &e.Disabled, &e.URLId, &e.Path, &e.Statement, &e.Overview, &e.Headline, &e.Issue, &e.IssueKind, &e.Depend, &tmpgain, &e.Coefficient, &e.VideoURI, &e.Resolution, &e.SeeAlso, &e.Finished); err != nil {
|
||||
if err := DBQueryRow("SELECT id_exercice, id_theme, title, authors, image, background_color, disabled, url_id, path, statement, overview, headline, issue, issue_kind, depend, gain, coefficient_cur, video_uri, resolution, seealso, finished FROM "+table+" "+condition, args...).Scan(&e.Id, &e.IdTheme, &e.Title, &e.Authors, &e.Image, &e.BackgroundColor, &e.Disabled, &e.URLId, &e.Path, &e.Statement, &e.Overview, &e.Headline, &e.Issue, &e.IssueKind, &e.Depend, &tmpgain, &e.Coefficient, &e.VideoURI, &e.Resolution, &e.SeeAlso, &e.Finished); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
e.Gain = int64(math.Trunc(tmpgain))
|
||||
|
@ -142,7 +143,7 @@ func GetDiscountedExercice(id int64) (*Exercice, error) {
|
|||
|
||||
// getExercices returns the list of all challenges present in the database.
|
||||
func getExercices(table string) ([]*Exercice, error) {
|
||||
if rows, err := DBQuery("SELECT id_exercice, id_theme, title, authors, image, disabled, url_id, path, statement, overview, headline, issue, issue_kind, depend, gain, coefficient_cur, video_uri, resolution, seealso, finished FROM " + table + " ORDER BY path ASC"); err != nil {
|
||||
if rows, err := DBQuery("SELECT id_exercice, id_theme, title, authors, image, background_color, disabled, url_id, path, statement, overview, headline, issue, issue_kind, depend, gain, coefficient_cur, video_uri, resolution, seealso, finished FROM " + table + " ORDER BY path ASC"); err != nil {
|
||||
return nil, err
|
||||
} else {
|
||||
defer rows.Close()
|
||||
|
@ -151,7 +152,7 @@ func getExercices(table string) ([]*Exercice, error) {
|
|||
for rows.Next() {
|
||||
e := &Exercice{}
|
||||
var tmpgain float64
|
||||
if err := rows.Scan(&e.Id, &e.IdTheme, &e.Title, &e.Authors, &e.Image, &e.Disabled, &e.URLId, &e.Path, &e.Statement, &e.Overview, &e.Headline, &e.Issue, &e.IssueKind, &e.Depend, &tmpgain, &e.Coefficient, &e.VideoURI, &e.Resolution, &e.SeeAlso, &e.Finished); err != nil {
|
||||
if err := rows.Scan(&e.Id, &e.IdTheme, &e.Title, &e.Authors, &e.Image, &e.BackgroundColor, &e.Disabled, &e.URLId, &e.Path, &e.Statement, &e.Overview, &e.Headline, &e.Issue, &e.IssueKind, &e.Depend, &tmpgain, &e.Coefficient, &e.VideoURI, &e.Resolution, &e.SeeAlso, &e.Finished); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
e.Gain = int64(math.Trunc(tmpgain))
|
||||
|
@ -180,11 +181,11 @@ func GetDiscountedExercices() ([]*Exercice, error) {
|
|||
|
||||
// GetExercices returns the list of all challenges in the Theme.
|
||||
func (t *Theme) GetExercices() ([]*Exercice, error) {
|
||||
query := "SELECT id_exercice, id_theme, title, authors, image, disabled, url_id, path, statement, overview, headline, issue, issue_kind, depend, gain, coefficient_cur, video_uri, resolution, seealso, finished FROM exercices WHERE id_theme IS NULL ORDER BY path ASC"
|
||||
query := "SELECT id_exercice, id_theme, title, authors, image, background_color, disabled, url_id, path, statement, overview, headline, issue, issue_kind, depend, gain, coefficient_cur, video_uri, resolution, seealso, finished FROM exercices WHERE id_theme IS NULL ORDER BY path ASC"
|
||||
args := []interface{}{}
|
||||
|
||||
if t.GetId() != nil {
|
||||
query = "SELECT id_exercice, id_theme, title, authors, image, disabled, url_id, path, statement, overview, headline, issue, issue_kind, depend, gain, coefficient_cur, video_uri, resolution, seealso, finished FROM exercices WHERE id_theme = ? ORDER BY path ASC"
|
||||
query = "SELECT id_exercice, id_theme, title, authors, image, background_color, disabled, url_id, path, statement, overview, headline, issue, issue_kind, depend, gain, coefficient_cur, video_uri, resolution, seealso, finished FROM exercices WHERE id_theme = ? ORDER BY path ASC"
|
||||
args = append(args, t.GetId())
|
||||
}
|
||||
|
||||
|
@ -196,7 +197,7 @@ func (t *Theme) GetExercices() ([]*Exercice, error) {
|
|||
exos := []*Exercice{}
|
||||
for rows.Next() {
|
||||
e := &Exercice{}
|
||||
if err := rows.Scan(&e.Id, &e.IdTheme, &e.Title, &e.Authors, &e.Image, &e.Disabled, &e.URLId, &e.Path, &e.Statement, &e.Overview, &e.Headline, &e.Issue, &e.IssueKind, &e.Depend, &e.Gain, &e.Coefficient, &e.VideoURI, &e.Resolution, &e.SeeAlso, &e.Finished); err != nil {
|
||||
if err := rows.Scan(&e.Id, &e.IdTheme, &e.Title, &e.Authors, &e.Image, &e.BackgroundColor, &e.Disabled, &e.URLId, &e.Path, &e.Statement, &e.Overview, &e.Headline, &e.Issue, &e.IssueKind, &e.Depend, &e.Gain, &e.Coefficient, &e.VideoURI, &e.Resolution, &e.SeeAlso, &e.Finished); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
e.AnalyzeTitle()
|
||||
|
@ -259,7 +260,7 @@ func (t *Theme) addExercice(e *Exercice) (err error) {
|
|||
if e.WIP {
|
||||
wip = "%"
|
||||
}
|
||||
if res, err := DBExec("INSERT INTO exercices (id_theme, title, authors, image, disabled, url_id, path, statement, overview, finished, headline, issue, depend, gain, video_uri, resolution, seealso, issue_kind, coefficient_cur) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, "+ik+", "+cc+")", t.GetId(), wip+e.Title, e.Authors, e.Image, e.Disabled, e.URLId, e.Path, e.Statement, e.Overview, e.Finished, e.Headline, e.Issue, e.Depend, e.Gain, e.VideoURI, e.Resolution, e.SeeAlso); err != nil {
|
||||
if res, err := DBExec("INSERT INTO exercices (id_theme, title, authors, image, background_color, disabled, url_id, path, statement, overview, finished, headline, issue, depend, gain, video_uri, resolution, seealso, issue_kind, coefficient_cur) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, "+ik+", "+cc+")", t.GetId(), wip+e.Title, e.Authors, e.Image, e.BackgroundColor, e.Disabled, e.URLId, e.Path, e.Statement, e.Overview, e.Finished, e.Headline, e.Issue, e.Depend, e.Gain, e.VideoURI, e.Resolution, e.SeeAlso); err != nil {
|
||||
return err
|
||||
} else if eid, err := res.LastInsertId(); err != nil {
|
||||
return err
|
||||
|
@ -271,29 +272,30 @@ func (t *Theme) addExercice(e *Exercice) (err error) {
|
|||
}
|
||||
|
||||
// AddExercice creates and fills a new struct Exercice and registers it into the database.
|
||||
func (t *Theme) AddExercice(title string, authors string, image string, wip bool, urlId string, path string, statement string, overview string, headline string, depend *Exercice, gain int64, videoURI string, resolution string, seealso string, finished string) (e *Exercice, err error) {
|
||||
func (t *Theme) AddExercice(title string, authors string, image string, backgroundcolor uint32, wip bool, urlId string, path string, statement string, overview string, headline string, depend *Exercice, gain int64, videoURI string, resolution string, seealso string, finished string) (e *Exercice, err error) {
|
||||
var dpd *int64 = nil
|
||||
if depend != nil {
|
||||
dpd = &depend.Id
|
||||
}
|
||||
|
||||
e = &Exercice{
|
||||
Title: title,
|
||||
Authors: authors,
|
||||
Image: image,
|
||||
Disabled: false,
|
||||
WIP: wip,
|
||||
URLId: urlId,
|
||||
Path: path,
|
||||
Statement: statement,
|
||||
Overview: overview,
|
||||
Headline: headline,
|
||||
Depend: dpd,
|
||||
Finished: finished,
|
||||
Gain: gain,
|
||||
VideoURI: videoURI,
|
||||
Resolution: resolution,
|
||||
SeeAlso: seealso,
|
||||
Title: title,
|
||||
Authors: authors,
|
||||
Image: image,
|
||||
BackgroundColor: backgroundcolor,
|
||||
Disabled: false,
|
||||
WIP: wip,
|
||||
URLId: urlId,
|
||||
Path: path,
|
||||
Statement: statement,
|
||||
Overview: overview,
|
||||
Headline: headline,
|
||||
Depend: dpd,
|
||||
Finished: finished,
|
||||
Gain: gain,
|
||||
VideoURI: videoURI,
|
||||
Resolution: resolution,
|
||||
SeeAlso: seealso,
|
||||
}
|
||||
|
||||
err = t.addExercice(e)
|
||||
|
@ -308,7 +310,7 @@ func (e *Exercice) Update() (int64, error) {
|
|||
wip = "%"
|
||||
}
|
||||
|
||||
if res, err := DBExec("UPDATE exercices SET title = ?, authors = ?, image = ?, disabled = ?, url_id = ?, path = ?, statement = ?, overview = ?, headline = ?, issue = ?, issue_kind = ?, depend = ?, gain = ?, coefficient_cur = ?, video_uri = ?, resolution = ?, seealso = ?, finished = ? WHERE id_exercice = ?", wip+e.Title, e.Authors, e.Image, e.Disabled, e.URLId, e.Path, e.Statement, e.Overview, e.Headline, e.Issue, e.IssueKind, e.Depend, e.Gain, e.Coefficient, e.VideoURI, e.Resolution, e.SeeAlso, e.Finished, e.Id); err != nil {
|
||||
if res, err := DBExec("UPDATE exercices SET title = ?, authors = ?, image = ?, background_color = ?, disabled = ?, url_id = ?, path = ?, statement = ?, overview = ?, headline = ?, issue = ?, issue_kind = ?, depend = ?, gain = ?, coefficient_cur = ?, video_uri = ?, resolution = ?, seealso = ?, finished = ? WHERE id_exercice = ?", wip+e.Title, e.Authors, e.Image, e.BackgroundColor, e.Disabled, e.URLId, e.Path, e.Statement, e.Overview, e.Headline, e.Issue, e.IssueKind, e.Depend, e.Gain, e.Coefficient, e.VideoURI, e.Resolution, e.SeeAlso, e.Finished, e.Id); err != nil {
|
||||
return 0, err
|
||||
} else if nb, err := res.RowsAffected(); err != nil {
|
||||
return 0, err
|
||||
|
|
|
@ -4,19 +4,20 @@ import ()
|
|||
|
||||
// Theme represents a group of challenges, to display to players
|
||||
type Theme struct {
|
||||
Id int64 `json:"id"`
|
||||
Language string `json:"lang,omitempty"`
|
||||
Name string `json:"name"`
|
||||
Locked bool `json:"locked"`
|
||||
URLId string `json:"urlid"`
|
||||
Path string `json:"path"`
|
||||
Authors string `json:"authors,omitempty"`
|
||||
Intro string `json:"intro,omitempty"`
|
||||
Headline string `json:"headline,omitempty"`
|
||||
Image string `json:"image,omitempty"`
|
||||
PartnerImage string `json:"partner_img,omitempty"`
|
||||
PartnerLink string `json:"partner_href,omitempty"`
|
||||
PartnerText string `json:"partner_txt,omitempty"`
|
||||
Id int64 `json:"id"`
|
||||
Language string `json:"lang,omitempty"`
|
||||
Name string `json:"name"`
|
||||
Locked bool `json:"locked"`
|
||||
URLId string `json:"urlid"`
|
||||
Path string `json:"path"`
|
||||
Authors string `json:"authors,omitempty"`
|
||||
Intro string `json:"intro,omitempty"`
|
||||
Headline string `json:"headline,omitempty"`
|
||||
Image string `json:"image,omitempty"`
|
||||
BackgroundColor uint32 `json:"background_color,omitempty"`
|
||||
PartnerImage string `json:"partner_img,omitempty"`
|
||||
PartnerLink string `json:"partner_href,omitempty"`
|
||||
PartnerText string `json:"partner_txt,omitempty"`
|
||||
}
|
||||
|
||||
func (t *Theme) GetId() *int64 {
|
||||
|
@ -29,12 +30,12 @@ func (t *Theme) GetId() *int64 {
|
|||
|
||||
// CmpTheme returns true if given Themes are identicals.
|
||||
func CmpTheme(t1 *Theme, t2 *Theme) bool {
|
||||
return t1 != nil && t2 != nil && !(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 || t1.PartnerImage != t2.PartnerImage || t1.PartnerLink != t2.PartnerLink || t1.PartnerText != t2.PartnerText)
|
||||
return t1 != nil && t2 != nil && !(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 || t1.BackgroundColor != t2.BackgroundColor || t1.PartnerImage != t2.PartnerImage || t1.PartnerLink != t2.PartnerLink || t1.PartnerText != t2.PartnerText)
|
||||
}
|
||||
|
||||
// GetThemes returns a list of registered Themes from the database.
|
||||
func GetThemes() ([]*Theme, error) {
|
||||
if rows, err := DBQuery("SELECT id_theme, name, locked, url_id, path, authors, intro, headline, image, partner_img, partner_href, partner_text FROM themes"); err != nil {
|
||||
if rows, err := DBQuery("SELECT id_theme, name, locked, url_id, path, authors, intro, headline, image, background_color, partner_img, partner_href, partner_text FROM themes"); err != nil {
|
||||
return nil, err
|
||||
} else {
|
||||
defer rows.Close()
|
||||
|
@ -42,7 +43,7 @@ func GetThemes() ([]*Theme, error) {
|
|||
var themes []*Theme
|
||||
for rows.Next() {
|
||||
t := &Theme{}
|
||||
if err := rows.Scan(&t.Id, &t.Name, &t.Locked, &t.URLId, &t.Path, &t.Authors, &t.Intro, &t.Headline, &t.Image, &t.PartnerImage, &t.PartnerLink, &t.PartnerText); err != nil {
|
||||
if err := rows.Scan(&t.Id, &t.Name, &t.Locked, &t.URLId, &t.Path, &t.Authors, &t.Intro, &t.Headline, &t.Image, &t.BackgroundColor, &t.PartnerImage, &t.PartnerLink, &t.PartnerText); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
themes = append(themes, t)
|
||||
|
@ -58,7 +59,7 @@ func GetThemes() ([]*Theme, error) {
|
|||
// GetTheme retrieves a Theme from its identifier.
|
||||
func GetTheme(id int64) (*Theme, error) {
|
||||
t := &Theme{}
|
||||
if err := DBQueryRow("SELECT id_theme, name, locked, url_id, path, authors, intro, headline, image, partner_img, partner_href, partner_text FROM themes WHERE id_theme=?", id).Scan(&t.Id, &t.Name, &t.Locked, &t.URLId, &t.Path, &t.Authors, &t.Intro, &t.Headline, &t.Image, &t.PartnerImage, &t.PartnerLink, &t.PartnerText); err != nil {
|
||||
if err := DBQueryRow("SELECT id_theme, name, locked, url_id, path, authors, intro, headline, image, background_color, partner_img, partner_href, partner_text FROM themes WHERE id_theme=?", id).Scan(&t.Id, &t.Name, &t.Locked, &t.URLId, &t.Path, &t.Authors, &t.Intro, &t.Headline, &t.Image, &t.BackgroundColor, &t.PartnerImage, &t.PartnerLink, &t.PartnerText); err != nil {
|
||||
return t, err
|
||||
}
|
||||
|
||||
|
@ -68,7 +69,7 @@ func GetTheme(id int64) (*Theme, error) {
|
|||
// GetTheme retrieves a Theme from an given Exercice.
|
||||
func (e *Exercice) GetTheme() (*Theme, error) {
|
||||
t := &Theme{}
|
||||
if err := DBQueryRow("SELECT id_theme, name, locked, url_id, path, authors, intro, headline, image, partner_img, partner_href, partner_text FROM themes WHERE id_theme=?", e.IdTheme).Scan(&t.Id, &t.Name, &t.Locked, &t.URLId, &t.Path, &t.Authors, &t.Intro, &t.Headline, &t.Image, &t.PartnerImage, &t.PartnerLink, &t.PartnerText); err != nil {
|
||||
if err := DBQueryRow("SELECT id_theme, name, locked, url_id, path, authors, intro, headline, image, background_color, partner_img, partner_href, partner_text FROM themes WHERE id_theme=?", e.IdTheme).Scan(&t.Id, &t.Name, &t.Locked, &t.URLId, &t.Path, &t.Authors, &t.Intro, &t.Headline, &t.Image, &t.BackgroundColor, &t.PartnerImage, &t.PartnerLink, &t.PartnerText); err != nil {
|
||||
return t, err
|
||||
}
|
||||
|
||||
|
@ -78,7 +79,7 @@ func (e *Exercice) GetTheme() (*Theme, error) {
|
|||
// GetThemeByName retrieves a Theme from its title
|
||||
func GetThemeByName(name string) (*Theme, error) {
|
||||
t := &Theme{}
|
||||
if err := DBQueryRow("SELECT id_theme, name, locked, url_id, path, authors, intro, headline, image, partner_img, partner_text FROM themes WHERE name=?", name).Scan(&t.Id, &t.Name, &t.Locked, &t.URLId, &t.Path, &t.Authors, &t.Intro, &t.Headline, &t.Image, &t.PartnerImage, &t.PartnerText); err != nil {
|
||||
if err := DBQueryRow("SELECT id_theme, name, locked, url_id, path, authors, intro, headline, image, background_color, partner_img, partner_text FROM themes WHERE name=?", name).Scan(&t.Id, &t.Name, &t.Locked, &t.URLId, &t.Path, &t.Authors, &t.Intro, &t.Headline, &t.Image, &t.BackgroundColor, &t.PartnerImage, &t.PartnerText); err != nil {
|
||||
return t, err
|
||||
}
|
||||
|
||||
|
@ -88,14 +89,14 @@ func GetThemeByName(name string) (*Theme, error) {
|
|||
// GetThemeByPath retrieves a Theme from its dirname
|
||||
func GetThemeByPath(dirname string) (*Theme, error) {
|
||||
t := &Theme{}
|
||||
err := DBQueryRow("SELECT id_theme, name, locked, url_id, path, authors, intro, headline, image, partner_img, partner_href, partner_text FROM themes WHERE path=?", dirname).Scan(&t.Id, &t.Name, &t.Locked, &t.URLId, &t.Path, &t.Authors, &t.Intro, &t.Headline, &t.Image, &t.PartnerImage, &t.PartnerLink, &t.PartnerText)
|
||||
err := DBQueryRow("SELECT id_theme, name, locked, url_id, path, authors, intro, headline, image, background_color, partner_img, partner_href, partner_text FROM themes WHERE path=?", dirname).Scan(&t.Id, &t.Name, &t.Locked, &t.URLId, &t.Path, &t.Authors, &t.Intro, &t.Headline, &t.Image, &t.BackgroundColor, &t.PartnerImage, &t.PartnerLink, &t.PartnerText)
|
||||
|
||||
return t, err
|
||||
}
|
||||
|
||||
// CreateTheme creates and fills a new struct Theme and registers it into the database.
|
||||
func CreateTheme(theme *Theme) (*Theme, error) {
|
||||
if res, err := DBExec("INSERT INTO themes (name, locked, url_id, authors, path, intro, headline, image, partner_img, partner_href, partner_text) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", theme.Name, theme.Locked, theme.URLId, theme.Authors, theme.Path, theme.Intro, theme.Headline, theme.Image, theme.PartnerImage, theme.PartnerLink, theme.PartnerText); err != nil {
|
||||
if res, err := DBExec("INSERT INTO themes (name, locked, url_id, authors, path, intro, headline, image, background_color, partner_img, partner_href, partner_text) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", theme.Name, theme.Locked, theme.URLId, theme.Authors, theme.Path, theme.Intro, theme.Headline, theme.Image, theme.BackgroundColor, theme.PartnerImage, theme.PartnerLink, theme.PartnerText); err != nil {
|
||||
return nil, err
|
||||
} else if theme.Id, err = res.LastInsertId(); err != nil {
|
||||
return nil, err
|
||||
|
@ -116,7 +117,7 @@ func (t *Theme) FixURLId() bool {
|
|||
|
||||
// Update applies modifications back to the database.
|
||||
func (t *Theme) Update() (int64, error) {
|
||||
if res, err := DBExec("UPDATE themes SET name = ?, locked = ?, url_id = ?, authors = ?, path = ?, intro = ?, headline = ?, image = ?, partner_img = ?, partner_href = ?, partner_text = ? WHERE id_theme = ?", t.Name, t.Locked, t.URLId, t.Authors, t.Path, t.Intro, t.Headline, t.Image, t.PartnerImage, t.PartnerLink, t.PartnerText, t.Id); err != nil {
|
||||
if res, err := DBExec("UPDATE themes SET name = ?, locked = ?, url_id = ?, authors = ?, path = ?, intro = ?, headline = ?, image = ?, background_color = ?, partner_img = ?, partner_href = ?, partner_text = ? WHERE id_theme = ?", t.Name, t.Locked, t.URLId, t.Authors, t.Path, t.Intro, t.Headline, t.Image, t.BackgroundColor, t.PartnerImage, t.PartnerLink, t.PartnerText, t.Id); err != nil {
|
||||
return 0, err
|
||||
} else if nb, err := res.RowsAffected(); err != nil {
|
||||
return 0, err
|
||||
|
|
|
@ -10,32 +10,34 @@ var GlobalScoreCoefficient float64 = 1
|
|||
|
||||
// exportedExercice is a structure representing a challenge, as exposed to players.
|
||||
type exportedExercice struct {
|
||||
Id int64 `json:"id"`
|
||||
Title string `json:"title"`
|
||||
Authors string `json:"authors,omitempty"`
|
||||
Headline string `json:"headline,omitempty"`
|
||||
Image string `json:"image,omitempty"`
|
||||
URLId string `json:"urlid"`
|
||||
Tags []string `json:"tags"`
|
||||
Gain int64 `json:"gain"`
|
||||
Coeff float64 `json:"curcoeff"`
|
||||
Solved int64 `json:"solved"`
|
||||
Tried int64 `json:"tried"`
|
||||
Id int64 `json:"id"`
|
||||
Title string `json:"title"`
|
||||
Authors string `json:"authors,omitempty"`
|
||||
Headline string `json:"headline,omitempty"`
|
||||
Image string `json:"image,omitempty"`
|
||||
BackgroundColor string `json:"background_color,omitempty"`
|
||||
URLId string `json:"urlid"`
|
||||
Tags []string `json:"tags"`
|
||||
Gain int64 `json:"gain"`
|
||||
Coeff float64 `json:"curcoeff"`
|
||||
Solved int64 `json:"solved"`
|
||||
Tried int64 `json:"tried"`
|
||||
}
|
||||
|
||||
// exportedTheme is a structure representing a Theme, as exposed to players.
|
||||
type exportedTheme struct {
|
||||
Name string `json:"name,omitempty"`
|
||||
URLId string `json:"urlid"`
|
||||
Locked bool `json:"locked,omitempty"`
|
||||
Authors string `json:"authors,omitempty"`
|
||||
Headline string `json:"headline,omitempty"`
|
||||
Intro string `json:"intro,omitempty"`
|
||||
Image string `json:"image,omitempty"`
|
||||
PartnerImage string `json:"partner_img,omitempty"`
|
||||
PartnerLink string `json:"partner_href,omitempty"`
|
||||
PartnerText string `json:"partner_txt,omitempty"`
|
||||
Exercices []exportedExercice `json:"exercices"`
|
||||
Name string `json:"name,omitempty"`
|
||||
URLId string `json:"urlid"`
|
||||
Locked bool `json:"locked,omitempty"`
|
||||
Authors string `json:"authors,omitempty"`
|
||||
Headline string `json:"headline,omitempty"`
|
||||
Intro string `json:"intro,omitempty"`
|
||||
Image string `json:"image,omitempty"`
|
||||
BackgroundColor string `json:"background_color,omitempty"`
|
||||
PartnerImage string `json:"partner_img,omitempty"`
|
||||
PartnerLink string `json:"partner_href,omitempty"`
|
||||
PartnerText string `json:"partner_txt,omitempty"`
|
||||
Exercices []exportedExercice `json:"exercices"`
|
||||
}
|
||||
|
||||
// Exportedthemes exports themes from the database, to be displayed to players.
|
||||
|
@ -69,6 +71,10 @@ func ExportThemes() (interface{}, error) {
|
|||
if len(exercice.Image) > 0 {
|
||||
exoimgpath = path.Join(FilesDir, exercice.Image)
|
||||
}
|
||||
exobackgroundcolor := ""
|
||||
if exercice.BackgroundColor > 0 || len(exercice.Image) > 0 {
|
||||
exobackgroundcolor = fmt.Sprintf("#%06X", exercice.BackgroundColor)
|
||||
}
|
||||
|
||||
tags, _ := exercice.GetTags()
|
||||
exos = append(exos, exportedExercice{
|
||||
|
@ -77,6 +83,7 @@ func ExportThemes() (interface{}, error) {
|
|||
exercice.Authors,
|
||||
exercice.Headline,
|
||||
exoimgpath,
|
||||
exobackgroundcolor,
|
||||
exercice.URLId,
|
||||
tags,
|
||||
int64(float64(exercice.Gain) * GlobalScoreCoefficient),
|
||||
|
@ -92,6 +99,11 @@ func ExportThemes() (interface{}, error) {
|
|||
imgpath = path.Join(FilesDir, theme.Image)
|
||||
}
|
||||
|
||||
thmbackgroundcolor := ""
|
||||
if theme.BackgroundColor > 0 || len(theme.Image) > 0 {
|
||||
thmbackgroundcolor = fmt.Sprintf("#%06X", theme.BackgroundColor)
|
||||
}
|
||||
|
||||
partnerImgpath := ""
|
||||
if len(theme.PartnerImage) > 0 {
|
||||
partnerImgpath = path.Join(FilesDir, theme.PartnerImage)
|
||||
|
@ -105,6 +117,7 @@ func ExportThemes() (interface{}, error) {
|
|||
theme.Headline,
|
||||
strings.Replace(theme.Intro, "$FILES$", FilesDir, -1),
|
||||
imgpath,
|
||||
thmbackgroundcolor,
|
||||
partnerImgpath,
|
||||
theme.PartnerLink,
|
||||
theme.PartnerText,
|
||||
|
|
Loading…
Reference in New Issue