mirror of https://github.com/dirtbags/moth.git
parent
077dc261e4
commit
79799bf1c2
|
@ -10,6 +10,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||
- Reworked the built-in theme
|
||||
- [moth.mjs](theme/moth.mjs) is now the standard MOTH library for ECMAScript
|
||||
- Devel mode no longer accepts an empty team ID
|
||||
- messages.html moved into theme
|
||||
- Exported state now includes "Enabled" boolean
|
||||
|
||||
## [v4.4.9] - 2022-05-12
|
||||
### Changed
|
||||
|
|
|
@ -45,7 +45,7 @@ func TestHttpd(t *testing.T) {
|
|||
|
||||
if r := hs.TestRequest("/state", nil); r.Result().StatusCode != 200 {
|
||||
t.Error(r.Result())
|
||||
} else if r.Body.String() != `{"Config":{"Devel":false},"Messages":"messages.html","TeamNames":{},"PointsLog":[],"Puzzles":{}}` {
|
||||
} else if r.Body.String() != `{"Config":{"Devel":false},"TeamNames":{},"PointsLog":[],"Puzzles":{}}` {
|
||||
t.Error("Unexpected state", r.Body.String())
|
||||
}
|
||||
|
||||
|
@ -71,7 +71,7 @@ func TestHttpd(t *testing.T) {
|
|||
|
||||
if r := hs.TestRequest("/state", nil); r.Result().StatusCode != 200 {
|
||||
t.Error(r.Result())
|
||||
} else if r.Body.String() != `{"Config":{"Devel":false},"Messages":"messages.html","TeamNames":{"self":"GoTeam"},"PointsLog":[],"Puzzles":{"pategory":[1]}}` {
|
||||
} else if r.Body.String() != `{"Config":{"Devel":false},"TeamNames":{"self":"GoTeam"},"PointsLog":[],"Puzzles":{"pategory":[1]}}` {
|
||||
t.Error("Unexpected state", r.Body.String())
|
||||
}
|
||||
|
||||
|
|
|
@ -30,7 +30,7 @@ type Configuration struct {
|
|||
// StateExport is given to clients requesting the current state.
|
||||
type StateExport struct {
|
||||
Config Configuration
|
||||
Messages string
|
||||
Enabled bool
|
||||
TeamNames map[string]string
|
||||
PointsLog award.List
|
||||
Puzzles map[string][]int
|
||||
|
@ -53,7 +53,7 @@ type ThemeProvider interface {
|
|||
|
||||
// StateProvider defines what's required to provide MOTH state.
|
||||
type StateProvider interface {
|
||||
Messages() string
|
||||
Enabled() bool
|
||||
PointsLog() award.List
|
||||
TeamName(teamID string) (string, error)
|
||||
SetTeamName(teamID, teamName string) error
|
||||
|
@ -194,7 +194,7 @@ func (mh *MothRequestHandler) exportStateIfRegistered(forceRegistered bool) *Sta
|
|||
teamName, err := mh.State.TeamName(mh.teamID)
|
||||
registered := forceRegistered || mh.Config.Devel || (err == nil)
|
||||
|
||||
export.Messages = mh.State.Messages()
|
||||
export.Enabled = mh.State.Enabled()
|
||||
export.TeamNames = make(map[string]string)
|
||||
|
||||
// Anonymize team IDs in points log, and write out team names
|
||||
|
|
|
@ -22,7 +22,6 @@ func NewTestServer() TestServer {
|
|||
|
||||
state := NewTestState()
|
||||
afero.WriteFile(state, "teamids.txt", []byte("teamID\n"), 0644)
|
||||
afero.WriteFile(state, "messages.html", []byte("messages.html"), 0644)
|
||||
state.refresh()
|
||||
|
||||
theme := NewTestTheme()
|
||||
|
@ -101,9 +100,6 @@ func TestProdServer(t *testing.T) {
|
|||
if len(es.Puzzles) != 1 {
|
||||
t.Error("Puzzle categories wrong length", len(es.Puzzles))
|
||||
}
|
||||
if es.Messages != "messages.html" {
|
||||
t.Error("Messages has wrong contents")
|
||||
}
|
||||
if len(es.PointsLog) != 0 {
|
||||
t.Error("Points log not empty")
|
||||
}
|
||||
|
|
|
@ -37,7 +37,7 @@ type State struct {
|
|||
afero.Fs
|
||||
|
||||
// Enabled tracks whether the current State system is processing updates
|
||||
Enabled bool
|
||||
enabled bool
|
||||
|
||||
enabledWhy string
|
||||
refreshNow chan bool
|
||||
|
@ -49,7 +49,6 @@ type State struct {
|
|||
teamNamesLastChange time.Time
|
||||
teamNames map[string]string
|
||||
pointsLog award.List
|
||||
messages string
|
||||
lock sync.RWMutex
|
||||
}
|
||||
|
||||
|
@ -57,7 +56,7 @@ type State struct {
|
|||
func NewState(fs afero.Fs) *State {
|
||||
s := &State{
|
||||
Fs: fs,
|
||||
Enabled: true,
|
||||
enabled: true,
|
||||
refreshNow: make(chan bool, 5),
|
||||
eventStream: make(chan []string, 80),
|
||||
|
||||
|
@ -117,11 +116,11 @@ func (s *State) updateEnabled() {
|
|||
}
|
||||
}
|
||||
|
||||
if (nextEnabled != s.Enabled) || (why != s.enabledWhy) {
|
||||
s.Enabled = nextEnabled
|
||||
if (nextEnabled != s.enabled) || (why != s.enabledWhy) {
|
||||
s.enabled = nextEnabled
|
||||
s.enabledWhy = why
|
||||
log.Printf("Setting enabled=%v: %s", s.Enabled, s.enabledWhy)
|
||||
if s.Enabled {
|
||||
log.Printf("Setting enabled=%v: %s", s.enabled, s.enabledWhy)
|
||||
if s.enabled {
|
||||
s.LogEvent("enabled", "", "", 0, s.enabledWhy)
|
||||
} else {
|
||||
s.LogEvent("disabled", "", "", 0, s.enabledWhy)
|
||||
|
@ -193,11 +192,9 @@ func (s *State) PointsLog() award.List {
|
|||
return ret
|
||||
}
|
||||
|
||||
// Messages retrieves the current messages.
|
||||
func (s *State) Messages() string {
|
||||
s.lock.RLock() // It's not clear to me that this actually needs to happen
|
||||
defer s.lock.RUnlock()
|
||||
return s.messages
|
||||
// Enabled returns true if the server is in "enabled" state
|
||||
func (s *State) Enabled() bool {
|
||||
return s.enabled
|
||||
}
|
||||
|
||||
// AwardPoints gives points to teamID in category.
|
||||
|
@ -313,7 +310,6 @@ func (s *State) maybeInitialize() {
|
|||
s.Remove("hours.txt")
|
||||
s.Remove("points.log")
|
||||
s.Remove("events.csv")
|
||||
s.Remove("messages.html")
|
||||
s.Remove("mothd.log")
|
||||
s.RemoveAll("points.tmp")
|
||||
s.RemoveAll("points.new")
|
||||
|
@ -369,11 +365,6 @@ func (s *State) maybeInitialize() {
|
|||
f.Close()
|
||||
}
|
||||
|
||||
if f, err := s.Create("messages.html"); err == nil {
|
||||
fmt.Fprintln(f, "<!-- messages.html: put client broadcast messages here. -->")
|
||||
f.Close()
|
||||
}
|
||||
|
||||
if f, err := s.Create("points.log"); err == nil {
|
||||
f.Close()
|
||||
}
|
||||
|
@ -465,16 +456,12 @@ func (s *State) updateCaches() {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
if bMessages, err := afero.ReadFile(s, "messages.html"); err == nil {
|
||||
s.messages = string(bMessages)
|
||||
}
|
||||
}
|
||||
|
||||
func (s *State) refresh() {
|
||||
s.maybeInitialize()
|
||||
s.updateEnabled()
|
||||
if s.Enabled {
|
||||
if s.enabled {
|
||||
s.collectPoints()
|
||||
}
|
||||
s.updateCaches()
|
||||
|
|
|
@ -185,7 +185,7 @@ func TestStateDisabled(t *testing.T) {
|
|||
s := NewTestState()
|
||||
s.refresh()
|
||||
|
||||
if !s.Enabled {
|
||||
if !s.Enabled() {
|
||||
t.Error("Brand new state is disabled")
|
||||
}
|
||||
|
||||
|
@ -195,35 +195,35 @@ func TestStateDisabled(t *testing.T) {
|
|||
}
|
||||
defer hoursFile.Close()
|
||||
s.refresh()
|
||||
if !s.Enabled {
|
||||
if !s.Enabled() {
|
||||
t.Error("Empty hours.txt not enabled")
|
||||
}
|
||||
|
||||
fmt.Fprintln(hoursFile, "- 1970-01-01T01:01:01Z")
|
||||
hoursFile.Sync()
|
||||
s.refresh()
|
||||
if s.Enabled {
|
||||
if s.Enabled() {
|
||||
t.Error("1970-01-01")
|
||||
}
|
||||
|
||||
fmt.Fprintln(hoursFile, "+ 1970-01-02 01:01:01+05:00")
|
||||
hoursFile.Sync()
|
||||
s.refresh()
|
||||
if !s.Enabled {
|
||||
if !s.Enabled() {
|
||||
t.Error("1970-01-02")
|
||||
}
|
||||
|
||||
fmt.Fprintln(hoursFile, "-")
|
||||
hoursFile.Sync()
|
||||
s.refresh()
|
||||
if s.Enabled {
|
||||
if s.Enabled() {
|
||||
t.Error("bare -")
|
||||
}
|
||||
|
||||
fmt.Fprintln(hoursFile, "+")
|
||||
hoursFile.Sync()
|
||||
s.refresh()
|
||||
if !s.Enabled {
|
||||
if !s.Enabled() {
|
||||
t.Error("bare +")
|
||||
}
|
||||
|
||||
|
@ -231,21 +231,21 @@ func TestStateDisabled(t *testing.T) {
|
|||
fmt.Fprintln(hoursFile, "# Comment")
|
||||
hoursFile.Sync()
|
||||
s.refresh()
|
||||
if !s.Enabled {
|
||||
if !s.Enabled() {
|
||||
t.Error("Comment")
|
||||
}
|
||||
|
||||
fmt.Fprintln(hoursFile, "intentional parse error")
|
||||
hoursFile.Sync()
|
||||
s.refresh()
|
||||
if !s.Enabled {
|
||||
if !s.Enabled() {
|
||||
t.Error("intentional parse error")
|
||||
}
|
||||
|
||||
fmt.Fprintln(hoursFile, "- 1980-01-01T01:01:01Z")
|
||||
hoursFile.Sync()
|
||||
s.refresh()
|
||||
if s.Enabled {
|
||||
if s.Enabled() {
|
||||
t.Error("1980-01-01")
|
||||
}
|
||||
|
||||
|
@ -253,13 +253,13 @@ func TestStateDisabled(t *testing.T) {
|
|||
t.Error(err)
|
||||
}
|
||||
s.refresh()
|
||||
if !s.Enabled {
|
||||
if !s.Enabled() {
|
||||
t.Error("Removing `hours.txt` disabled event")
|
||||
}
|
||||
|
||||
s.Remove("initialized")
|
||||
s.refresh()
|
||||
if !s.Enabled {
|
||||
if !s.Enabled() {
|
||||
t.Error("Re-initializing didn't start event")
|
||||
}
|
||||
}
|
||||
|
|
|
@ -53,7 +53,6 @@ Returns the current Moth event state as a JSON object.
|
|||
"Config": {
|
||||
"Devel": false // true means this is a development server
|
||||
},
|
||||
"Messages: "HTML to be rendered as broadcast messages",
|
||||
"TeamNames": {
|
||||
"self": "Requesting team name", // Only if regestered team id is a provided
|
||||
"0": "Team 1 Name",
|
||||
|
@ -91,7 +90,6 @@ Content-Type: application/json
|
|||
|
||||
{"Config":
|
||||
{"Devel":false},
|
||||
"Messages":"<p>Welcome to the event!</p><p>Event ends at 19:00!</p>",
|
||||
"TeamNames":{
|
||||
"0":"Mike and Jack",
|
||||
"12":"Team 2",
|
||||
|
|
|
@ -167,9 +167,7 @@ class App {
|
|||
}
|
||||
|
||||
function init() {
|
||||
window.app = {
|
||||
server: new App()
|
||||
}
|
||||
window.app = new App()
|
||||
}
|
||||
|
||||
common.WhenDOMLoaded(init)
|
||||
|
|
|
@ -367,10 +367,8 @@ class State {
|
|||
Devel: obj.Config.Devel,
|
||||
}
|
||||
|
||||
/** Global messages, in HTML
|
||||
* @type {string}
|
||||
*/
|
||||
this.Messages = obj.Messages
|
||||
/** True if the server is in enabled state */
|
||||
this.Enabled = obj.Enabled
|
||||
|
||||
/** Map from Team ID to Team Name
|
||||
* @type {Object.<string,string>}
|
||||
|
|
Loading…
Reference in New Issue