func AddMember(c common.WSContext) error { var state GameState c.Data().Overwrite(&state) return c.Transact(func(c common.WSContext) error { game := Game{Id: state.Game.Id} if err := c.DB().Get(&game); err != nil { return fmt.Errorf("Game not found") } if game.State != common.GameStateCreated { return fmt.Errorf("%+v already started") } variant, found := common.VariantMap[game.Variant] if !found { return fmt.Errorf("Unknown variant %v", game.Variant) } if alreadyMember, err := game.Member(c.DB(), c.Principal()); err != nil { return err } else if alreadyMember != nil { return fmt.Errorf("%+v is already member of %v", alreadyMember, game.Id) } me := &user.User{Id: kol.Id(c.Principal())} if err := c.DB().Get(me); err != nil { return err } if game.Disallows(me) { return fmt.Errorf("Is not allowed to join this game due to game settings") } already, err := game.Members(c.DB()) if err != nil { return err } if disallows, err := already.Disallows(c.DB(), me); err != nil { return err } else if disallows { return fmt.Errorf("Is not allowed to join this game due to blacklistings") } if len(already) < len(variant.Nations) { member := Member{ GameId: state.Game.Id, UserId: kol.Id(c.Principal()), PreferredNations: state.Members[0].PreferredNations, } if err := c.DB().Set(&member); err != nil { return err } if len(already) == len(variant.Nations)-1 { if err := game.start(c.Diet()); err != nil { return err } c.Infof("Started %v", game.Id) } } return nil }) }
func Openid(c *common.HTTPContext) (err error) { redirect, email, ok, err := gopenid.VerifyAuth(c.Req()) if err != nil { return } if ok { email = strings.ToLower(email) c.Session().Values[common.SessionEmail] = email u := &User{Id: kol.Id(email)} err = c.DB().Get(u) if err == kol.NotFound { err = nil u.Email = email u.Ranking = 1 } if err == nil { u.Language = common.GetLanguage(c.Req()) u.DiplicityHost = c.Req().Host u.LastLoginAt = time.Now() err = c.DB().Set(u) } } else { delete(c.Session().Values, common.SessionEmail) } c.Close() c.Resp().Header().Set("Location", redirect.String()) c.Resp().WriteHeader(302) fmt.Fprintln(c.Resp(), redirect.String()) return }
func Set(d *kol.DB, at time.Duration) (err error) { epoch := &Epoch{ Id: kol.Id(epochKey), At: at, } err = d.Set(epoch) return }
func (self *cli) createUser(email string) (err error) { _, err = self.post("/admin/users", map[string]interface{}{ "Email": email, "Id": kol.Id(email), "DiplicityHost": fmt.Sprintf("%v:%v", self.host, self.port), }) return }
func subscribeOthers(c common.WSContext, filter kol.QFilter, preLimiter func(source Games) (result Games), postLimiter func(source GameStates) (result GameStates)) error { if c.Principal() == "" { return websocket.JSON.Send(c.Conn(), gosubs.Message{ Type: gosubs.FetchType, Object: &gosubs.Object{ URI: c.Match()[0], }, }) } s := c.Pack().New(c.Match()[0]) s.Query = s.DB().Query().Where(filter) s.Call = func(i interface{}, op string) error { games := i.([]*Game) if preLimiter != nil { games = ([]*Game)(preLimiter(Games(games))) } states := GameStates{} isMember := false me := &user.User{Id: kol.Id(c.Principal())} if err := c.DB().Get(me); err != nil { return err } for _, game := range games { if !game.Disallows(me) { members, err := game.Members(c.DB()) if err != nil { return err } if disallows, err := members.Disallows(c.DB(), me); err != nil { return err } else if !disallows { isMember = members.Contains(c.Principal()) if !isMember { state, err := game.ToState(c.DB(), members, nil) if err != nil { return err } states = append(states, state) } } } } if op == gosubs.FetchType || len(states) > 0 { if postLimiter != nil { states = postLimiter(states) } return s.Send(states, op) } return nil } return s.Subscribe(&Game{}) }
func OAuth2Callback(clientId, clientSecret string) func(c *common.HTTPContext) (err error) { return func(c *common.HTTPContext) (err error) { state := c.Req().FormValue("state") nonceLock.Lock() defer nonceLock.Unlock() if _, found := nonces[state]; !found { err = fmt.Errorf("state not found") return } delete(nonces, state) scheme := "http" if c.Req().TLS != nil { scheme = "https" } redirectUrl, err := url.Parse(fmt.Sprintf("%v://%v/oauth2callback", scheme, c.Req().Host)) if err != nil { return } email, ok, err := goauth2.VerifyEmail(clientId, clientSecret, c.Req().FormValue("code"), redirectUrl) if err != nil { return } if ok { email = strings.ToLower(email) c.Session().Values[common.SessionEmail] = email u := &User{Id: kol.Id(email)} err = c.DB().Get(u) if err == kol.NotFound { err = nil u.Email = email u.Ranking = 1 } if err == nil { u.Language = common.GetLanguage(c.Req()) u.DiplicityHost = c.Req().Host u.LastLoginAt = time.Now() err = c.DB().Set(u) } } else { delete(c.Session().Values, common.SessionEmail) } c.Close() c.Resp().Header().Set("Location", "/") c.Resp().WriteHeader(302) fmt.Fprintln(c.Resp(), "/") return } }
func Get(d *kol.DB) (result time.Duration, err error) { epoch := &Epoch{ Id: kol.Id(epochKey), } if err = d.Get(epoch); err != nil { if err == kol.NotFound { err = nil } else { return } } result = epoch.At + time.Now().Sub(time.Unix(0, atomic.LoadInt64(&deltaPoint))) return }
func (self Members) ToStates(d *kol.DB, g *Game, email string, isAdmin bool) (result []MemberState, err error) { result = make([]MemberState, len(self)) isMember := false for _, member := range self { if member.UserId.Equals(kol.Id(email)) { isMember = true break } } for index, member := range self { var state *MemberState if state, err = member.ToState(d, g, email, isMember, isAdmin); err != nil { return } result[index] = *state } return }
func Create(c common.WSContext) error { var state GameState c.Data().Overwrite(&state) game := &Game{ Variant: state.Game.Variant, EndYear: state.Game.EndYear, Private: state.Game.Private, SecretEmail: state.Game.SecretEmail, SecretNickname: state.Game.SecretNickname, SecretNation: state.Game.SecretNation, Deadlines: state.Game.Deadlines, ChatFlags: state.Game.ChatFlags, AllocationMethod: state.Game.AllocationMethod, NonCommitConsequences: state.Game.NonCommitConsequences, NMRConsequences: state.Game.NMRConsequences, Ranking: state.Game.Ranking, } if _, found := common.VariantMap[game.Variant]; !found { return fmt.Errorf("Unknown variant for %+v", game) } if _, found := common.AllocationMethodMap[game.AllocationMethod]; !found { return fmt.Errorf("Unknown allocation method for %+v", game) } member := &Member{ UserId: kol.Id(c.Principal()), PreferredNations: state.Members[0].PreferredNations, } return c.Transact(func(c common.WSContext) error { if err := c.DB().Set(game); err != nil { return err } member.GameId = game.Id return c.DB().Set(member) }) }
func SubscribeMine(c common.WSContext) error { if c.Principal() == "" { return websocket.JSON.Send(c.Conn(), gosubs.Message{ Type: gosubs.FetchType, Object: &gosubs.Object{ URI: c.Match()[0], }, }) } s := c.Pack().New(c.Match()[0]) s.Query = s.DB().Query().Where(kol.Equals{"UserId", kol.Id(c.Principal())}) s.Call = func(i interface{}, op string) (err error) { members := i.([]*Member) var ep time.Duration ep, err = epoch.Get(c.DB()) if err != nil { return } states := GameStates{} for _, member := range members { if op == gosubs.DeleteType { states = append(states, GameState{ Game: &Game{Id: member.GameId}, Members: []MemberState{MemberState{Member: member}}, }) } else { game := &Game{Id: member.GameId} if err = s.DB().Get(game); err != nil { return } var gameMembers Members if gameMembers, err = game.Members(c.DB()); err != nil { return } var state GameState if state, err = game.ToState(c.DB(), gameMembers, member); err != nil { return } states = append(states, state) } } if op == gosubs.FetchType || len(states) > 0 { states = states.SortAndLimit(func(a, b GameState) bool { urgencyA := time.Hour * 24 * 365 urgencyB := time.Hour * 24 * 365 switch a.State { case common.GameStateStarted: _, phase, err := a.Game.Phase(c.DB(), 0) if err == nil { urgencyA = phase.Deadline - ep } case common.GameStateCreated: urgencyA -= 1 } switch b.State { case common.GameStateStarted: _, phase, err := b.Game.Phase(c.DB(), 0) if err == nil { urgencyB = phase.Deadline - ep } case common.GameStateCreated: urgencyB -= 1 } if urgencyA != urgencyB { return urgencyA < urgencyB } return a.CreatedAt.Before(b.CreatedAt) }, 1024*16) return s.Send(states, op) } return nil } return s.Subscribe(&Member{}) }
func DeleteMember(c common.WSContext) error { return c.Transact(func(c common.WSContext) error { decodedId, err := kol.DecodeId(c.Match()[1]) if err != nil { return err } game := &Game{Id: decodedId} if err := c.DB().Get(game); err != nil { return fmt.Errorf("Game not found: %v", err) } if game.State != common.GameStateCreated { return fmt.Errorf("%+v already started", game) } member := Member{} if _, err := c.DB().Query().Where(kol.And{kol.Equals{"GameId", decodedId}, kol.Equals{"UserId", kol.Id(c.Principal())}}).First(&member); err != nil { return err } if err := c.DB().Del(&member); err != nil { return err } left, err := game.Members(c.DB()) if err != nil { return err } if len(left) == 0 { if err := c.DB().Del(game); err != nil { return err } } return nil }) }
func (self *Game) Member(d *kol.DB, email string) (result *Member, err error) { var member Member var found bool if found, err = d.Query().Where(kol.And{kol.Equals{"GameId", self.Id}, kol.Equals{"UserId", kol.Id(email)}}).First(&member); found && err == nil { result = &member } return }