New option to disallow team creation: join only

This commit is contained in:
nemunaire 2020-05-16 03:51:36 +02:00
parent 5d3ef96f3f
commit 64b9e9a251
6 changed files with 53 additions and 30 deletions

View file

@ -178,6 +178,7 @@ func main() {
WChoiceCurCoefficient: 1, WChoiceCurCoefficient: 1,
AllowRegistration: false, AllowRegistration: false,
CanJoinTeam: false, CanJoinTeam: false,
DenyTeamCreation: false,
DenyNameChange: false, DenyNameChange: false,
AcceptNewIssue: true, AcceptNewIssue: true,
EnableResolutionRoute: false, EnableResolutionRoute: false,

View file

@ -129,6 +129,13 @@
</label> </label>
</div> </div>
<div class="form-check">
<label class="custom-control custom-checkbox">
<input class="custom-control-input" type="checkbox" ng-model="config.denyTeamCreation" ng-disabled="!config.allowRegistration && !config.canJoinTeam">
<span class="custom-control-label">Interdire la création de nouvelles équipes</span>
</label>
</div>
<div class="form-check"> <div class="form-check">
<label class="custom-control custom-checkbox"> <label class="custom-control custom-checkbox">
<input class="custom-control-input" type="checkbox" ng-model="config.denyNameChange"> <input class="custom-control-input" type="checkbox" ng-model="config.denyNameChange">

View file

@ -70,6 +70,7 @@ var skipInitialGeneration = false
func reloadSettings(config settings.FICSettings) { func reloadSettings(config settings.FICSettings) {
allowRegistration = config.AllowRegistration allowRegistration = config.AllowRegistration
canJoinTeam = config.CanJoinTeam canJoinTeam = config.CanJoinTeam
denyTeamCreation = config.DenyTeamCreation
fic.HintCoefficient = config.HintCurCoefficient fic.HintCoefficient = config.HintCurCoefficient
fic.WChoiceCoefficient = config.WChoiceCurCoefficient fic.WChoiceCoefficient = config.WChoiceCurCoefficient
fic.ExerciceCurrentCoefficient = config.ExerciceCurCoefficient fic.ExerciceCurrentCoefficient = config.ExerciceCurCoefficient

View file

@ -18,6 +18,7 @@ import (
var ( var (
allowRegistration = false allowRegistration = false
canJoinTeam = false canJoinTeam = false
denyTeamCreation = false
) )
type uTeamRegistration struct { type uTeamRegistration struct {
@ -78,6 +79,8 @@ func treatRegistration(pathname string, team_id string) {
log.Printf("%s [WRN] %s\n", id, err) log.Printf("%s [WRN] %s\n", id, err)
} }
} }
} else if denyTeamCreation {
log.Printf("%s [ERR] Registration received, whereas team creation denied. Skipped.\n", id)
} else if validTeamName(nTeam.TeamName) { } else if validTeamName(nTeam.TeamName) {
if team, err := fic.CreateTeam(nTeam.TeamName, uint32(rand.Int31n(16581376))); err != nil { if team, err := fic.CreateTeam(nTeam.TeamName, uint32(rand.Int31n(16581376))); err != nil {
log.Printf("%s [ERR] Unable to register new team %s: %s\n", id, nTeam.TeamName, err) log.Printf("%s [ERR] Unable to register new team %s: %s\n", id, nTeam.TeamName, err)

View file

@ -9,9 +9,9 @@
</div> </div>
</div> </div>
<div class="jumbotron niceborder" style="text-indent: 1em" ng-if="settings.allowRegistration"> <div class="jumbotron niceborder" style="text-indent: 1em" ng-if="settings.allowRegistration && !settings.denyTeamCreation">
<p> <p>
<strong>Félicitations&nbsp;! vous êtes maintenant authentifié auprès de <strong>Félicitations&nbsp;! vous êtes maintenant authentifié&middot;e auprès de
notre serveur&nbsp;!</strong> notre serveur&nbsp;!</strong>
</p> </p>
<p> <p>
@ -76,9 +76,18 @@
</div> </div>
<div class="jumbotron niceborder" style="text-indent: 1em" ng-if="settings.canJoinTeam"> <div class="jumbotron niceborder" style="text-indent: 1em" ng-if="settings.canJoinTeam">
<p> <p ng-if="settings.denyTeamCreation">
<strong>Félicitations&nbsp;! vous êtes maintenant authentifié&middot;e auprès de
notre serveur&nbsp;!</strong>
</p>
<p ng-if="!settings.denyTeamCreation">
Si votre équipe est déjà créée, rejoignez-là&nbsp;! Si votre équipe est déjà créée, rejoignez-là&nbsp;!
</p> </p>
<p ng-if="settings.denyTeamCreation">
Vous n'êtes pas encore enregistré&middot;e sur notre serveur. Afin de
pouvoir participer au challenge, nous vous remercions de bien vouloir
rejoindre votre équipe&nbsp;:
</p>
<form ng-submit="jsubmit()"> <form ng-submit="jsubmit()">
<div class="row"> <div class="row">

View file

@ -8,8 +8,8 @@ import (
"os" "os"
"os/signal" "os/signal"
"path" "path"
"time"
"syscall" "syscall"
"time"
"gopkg.in/fsnotify.v1" "gopkg.in/fsnotify.v1"
) )
@ -23,52 +23,54 @@ var SettingsDir string = "./SETTINGS"
// FICSettings represents the settings panel. // FICSettings represents the settings panel.
type FICSettings struct { type FICSettings struct {
// Title is the displayed name of the challenge. // Title is the displayed name of the challenge.
Title string `json:"title"` Title string `json:"title"`
// Authors is the group name of people making the challenge. // Authors is the group name of people making the challenge.
Authors string `json:"authors"` Authors string `json:"authors"`
// VideoLink is the link to explaination videos when the challenge is over. // VideoLink is the link to explaination videos when the challenge is over.
VideosLink string `json:"videoslink"` VideosLink string `json:"videoslink"`
// Start is the departure time (expected or effective). // Start is the departure time (expected or effective).
Start time.Time `json:"start"` Start time.Time `json:"start"`
// End is the expected end time. // End is the expected end time.
End time.Time `json:"end"` End time.Time `json:"end"`
// Generation is a value used to regenerate static files. // Generation is a value used to regenerate static files.
Generation time.Time `json:"generation"` Generation time.Time `json:"generation"`
// ActivateTime is the time when the current file should be proceed. // ActivateTime is the time when the current file should be proceed.
ActivateTime time.Time `json:"activateTime"` ActivateTime time.Time `json:"activateTime"`
// FirstBlood is the coefficient applied to each first team who solve a challenge. // FirstBlood is the coefficient applied to each first team who solve a challenge.
FirstBlood float64 `json:"firstBlood"` FirstBlood float64 `json:"firstBlood"`
// SubmissionCostBase is a complex number representing the cost of each attempts. // SubmissionCostBase is a complex number representing the cost of each attempts.
SubmissionCostBase float64 `json:"submissionCostBase"` SubmissionCostBase float64 `json:"submissionCostBase"`
// ExerciceCurrentCoefficient is the current coefficient applied globaly to exercices. // ExerciceCurrentCoefficient is the current coefficient applied globaly to exercices.
ExerciceCurCoefficient float64 `json:"exerciceCurrentCoefficient"` ExerciceCurCoefficient float64 `json:"exerciceCurrentCoefficient"`
// HintCurrentCoefficient is the current coefficient applied to hint discovery. // HintCurrentCoefficient is the current coefficient applied to hint discovery.
HintCurCoefficient float64 `json:"hintCurrentCoefficient"` HintCurCoefficient float64 `json:"hintCurrentCoefficient"`
// WChoiceCurCoefficient is the current coefficient applied to wanted choices. // WChoiceCurCoefficient is the current coefficient applied to wanted choices.
WChoiceCurCoefficient float64 `json:"wchoiceCurrentCoefficient"` WChoiceCurCoefficient float64 `json:"wchoiceCurrentCoefficient"`
// AllowRegistration permits unregistered Team to register themselves. // AllowRegistration permits unregistered Team to register themselves.
AllowRegistration bool `json:"allowRegistration"` AllowRegistration bool `json:"allowRegistration"`
// CanJoinTeam permits unregistered account to join an already existing team. // CanJoinTeam permits unregistered account to join an already existing team.
CanJoinTeam bool `json:"canJoinTeam"` CanJoinTeam bool `json:"canJoinTeam"`
// DenyTeamCreation forces unregistered account to join a team, it's not possible to create a new team.
DenyTeamCreation bool `json:"denyTeamCreation"`
// DenyNameChange disallow Team to change their name. // DenyNameChange disallow Team to change their name.
DenyNameChange bool `json:"denyNameChange"` DenyNameChange bool `json:"denyNameChange"`
// AcceptNewIssue enables the reporting system. // AcceptNewIssue enables the reporting system.
AcceptNewIssue bool `json:"acceptNewIssue"` AcceptNewIssue bool `json:"acceptNewIssue"`
// EnableResolutionRoute activates the route displaying resolution movies. // EnableResolutionRoute activates the route displaying resolution movies.
EnableResolutionRoute bool `json:"enableResolutionRoute"` EnableResolutionRoute bool `json:"enableResolutionRoute"`
// PartialValidation validates each correct given answers, don't expect Team to give all correct answer in a try. // PartialValidation validates each correct given answers, don't expect Team to give all correct answer in a try.
PartialValidation bool `json:"partialValidation"` PartialValidation bool `json:"partialValidation"`
// UnlockedChallengeDepth don't show (or permit to solve) to team challenges they are not unlocked through dependancies. // UnlockedChallengeDepth don't show (or permit to solve) to team challenges they are not unlocked through dependancies.
UnlockedChallengeDepth int `json:"unlockedChallengeDepth"` UnlockedChallengeDepth int `json:"unlockedChallengeDepth"`
// SubmissionUniqueness don't count multiple times identical tries. // SubmissionUniqueness don't count multiple times identical tries.
SubmissionUniqueness bool `json:"submissionUniqueness"` SubmissionUniqueness bool `json:"submissionUniqueness"`
// DisplayAllFlags doesn't respect the predefined constraint existing between flags. // DisplayAllFlags doesn't respect the predefined constraint existing between flags.
DisplayAllFlags bool `json:"displayAllFlags"` DisplayAllFlags bool `json:"displayAllFlags"`
// EventKindness will ask browsers to delay notification interval. // EventKindness will ask browsers to delay notification interval.
EventKindness bool `json:"eventKindness"` EventKindness bool `json:"eventKindness"`
} }
// ExistsSettings checks if the settings file can by found at the given path. // ExistsSettings checks if the settings file can by found at the given path.
@ -125,7 +127,7 @@ func ForceRegeneration() error {
// Giving the location and a callback, this function will first call your reload function // Giving the location and a callback, this function will first call your reload function
// before returning (if the file can be parsed); then it starts watching modifications made to // before returning (if the file can be parsed); then it starts watching modifications made to
// this file. Your callback is then run each time the file is modified. // this file. Your callback is then run each time the file is modified.
func LoadAndWatchSettings(settingsPath string, reload func (FICSettings)) { func LoadAndWatchSettings(settingsPath string, reload func(FICSettings)) {
// First load of configuration if it exists // First load of configuration if it exists
if _, err := os.Stat(settingsPath); !os.IsNotExist(err) { if _, err := os.Stat(settingsPath); !os.IsNotExist(err) {
if config, err := ReadSettings(settingsPath); err != nil { if config, err := ReadSettings(settingsPath); err != nil {
@ -138,7 +140,7 @@ func LoadAndWatchSettings(settingsPath string, reload func (FICSettings)) {
// Register SIGHUP // Register SIGHUP
c := make(chan os.Signal, 1) c := make(chan os.Signal, 1)
signal.Notify(c, syscall.SIGHUP) signal.Notify(c, syscall.SIGHUP)
go func(){ go func() {
for range c { for range c {
log.Println("SIGHUP received, reloading settings...") log.Println("SIGHUP received, reloading settings...")
go tryReload(settingsPath, reload) go tryReload(settingsPath, reload)
@ -158,7 +160,7 @@ func LoadAndWatchSettings(settingsPath string, reload func (FICSettings)) {
for { for {
select { select {
case ev := <-watcher.Events: case ev := <-watcher.Events:
if path.Base(ev.Name) == SettingsFile && ev.Op & (fsnotify.Write | fsnotify.Create) != 0 { if path.Base(ev.Name) == SettingsFile && ev.Op&(fsnotify.Write|fsnotify.Create) != 0 {
log.Println("Settings file changes, reloading it!") log.Println("Settings file changes, reloading it!")
go tryReload(settingsPath, reload) go tryReload(settingsPath, reload)
} }
@ -170,7 +172,7 @@ func LoadAndWatchSettings(settingsPath string, reload func (FICSettings)) {
} }
} }
func tryReload(settingsPath string, reload func (FICSettings)) { func tryReload(settingsPath string, reload func(FICSettings)) {
if config, err := ReadSettings(settingsPath); err != nil { if config, err := ReadSettings(settingsPath); err != nil {
log.Println("ERROR: Unable to read challenge settings:", err) log.Println("ERROR: Unable to read challenge settings:", err)
} else if time.Until(config.ActivateTime) > 0 { } else if time.Until(config.ActivateTime) > 0 {