Skip to content

Commit

Permalink
Revamp team joining
Browse files Browse the repository at this point in the history
  • Loading branch information
diamondburned committed Mar 12, 2024
1 parent 53166cb commit d03d2b9
Show file tree
Hide file tree
Showing 4 changed files with 147 additions and 47 deletions.
3 changes: 2 additions & 1 deletion server/auth.go
Original file line number Diff line number Diff line change
Expand Up @@ -116,10 +116,11 @@ func generateInviteCode() string {
const letters = "abcdefghijklmnopqrstuvwxyz0123456789"
const word = 4
const count = 4
const length = word*count + count - 1

r := rand.New(rand.NewSource(time.Now().UnixNano()))
var b strings.Builder
b.Grow(word*count + count - 1)
b.Grow(length)

for i := 0; i < count; i++ {
if i != 0 {
Expand Down
62 changes: 44 additions & 18 deletions server/frontend/pages/join.html
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@ <h2>Team Creation</h2>
{{ if .TeamName }}
<p>
<strong>
You are already on a team <mark data-tooltip="Team name">{{ .TeamName }}</mark> as
You are already on a team
<mark data-tooltip="Team name">{{ .TeamName }}</mark> as
<mark data-tooltip="Username">{{ .Username }}</mark>.
</strong>
You can change teams by entering a new team code or creating a new team.
Expand Down Expand Up @@ -51,24 +52,49 @@ <h2>Team Creation</h2>
{{ end }}
/>

<input
maxlength="32"
minlength="2"
type="text"
name="team_name"
placeholder="Team Name or Team Code"
pattern="[a-zA-Z-_ ]{2,32}"
title="Team name must be of length [2, 32] consisting of letters and spaces only!"
value="{{ .FillingTeamName }}"
autocomplete="off"
required
/>
<div class="team-grid">
<div class="left">
<input
maxlength="32"
minlength="2"
type="text"
name="team_name"
placeholder="Team Name"
pattern="[a-zA-Z-_ ]{2,32}"
title="Team name must be of length [2, 32] consisting of letters and spaces only!"
value="{{ .FillingTeamName }}"
autocomplete="on"
required
/>

{{ if .TeamName }}
<button type="submit" id="submit-team" class="seecondary">Rename</button>
{{ else }}
<button type="submit" id="submit-team">Create</button>
{{ end }}
</div>

<div class="separator">
<p>or</p>
</div>

{{ if .TeamName }}
<button type="submit" class="secondary" id="submit-team">Change</button>
{{ else }}
<button type="submit" id="submit-team">Join</button>
{{ end }}
<div class="right">
<input
maxlength="19"
minlength="19"
type="text"
name="team_code"
placeholder="Team Code"
pattern="[a-z0-9]{4}-[a-z0-9]{4}-[a-z0-9]{4}-[a-z0-9]{4}"
title="Team code must be in the format xxxx-xxxx-xxxx-xxxx!"
value="{{ .FillingTeamCode }}"
autocomplete="off"
required
/>

<button type="submit" id="submit-team" class="secondary">Join</button>
</div>
</div>
</form>

<footer>
Expand Down
55 changes: 55 additions & 0 deletions server/frontend/styles/_join.scss
Original file line number Diff line number Diff line change
@@ -1,4 +1,59 @@
#join {
.team-grid {
display: grid;
grid-template-columns: 1fr auto 1fr;

.left,
.right {
button {
margin-bottom: 0;
}
}

.separator {
margin: 0 calc(var(--spacing) / 2);
background-color: var(--card-background-color);

display: flex;
flex-direction: column;
align-items: center;
gap: var(--spacing);

&::before,
&::after {
content: "";
border-left: 2px solid var(--muted-color);
border-radius: 1px;
height: 100%;
width: 0;
}

p {
margin: 0;
margin-top: -0.25em;
line-height: 0;
}
}

@media (max-width: 480px) {
grid-template-columns: 1fr;
grid-gap: var(--spacing);

.separator {
margin: calc(var(--spacing) / 2) 0;
flex-direction: row;

&::before,
&::after {
border-top: 2px solid var(--muted-color);
border-left: none;
width: 100%;
height: 0;
}
}
}
}

footer {
ul,
li {
Expand Down
74 changes: 46 additions & 28 deletions server/r_join.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ type joinPageData struct {
OpenRegistrationTime time.Time
FillingUsername string
FillingTeamName string
FillingTeamCode string
Error string
}

Expand All @@ -39,6 +40,7 @@ func (s *Server) joinPage(w http.ResponseWriter, r *http.Request) {
var (
reUsername = regexp.MustCompile(`^[a-zA-Z0-9-_ ]{2,32}$`)
reTeamName = regexp.MustCompile(`^[a-zA-Z0-9-_ ]{2,32}$`)
reTeamCode = regexp.MustCompile(`^[a-z0-9]{4}-[a-z0-9]{4}-[a-z0-9]{4}-[a-z0-9]{4}$`)
)

func (s *Server) join(w http.ResponseWriter, r *http.Request) {
Expand All @@ -63,6 +65,7 @@ func (s *Server) join(w http.ResponseWriter, r *http.Request) {
var data struct {
Username string `schema:"username"`
TeamName string `schema:"team_name"`
TeamCode string `schema:"team_code"`
}
if err := unmarshalForm(r, &data); err != nil {
writeError(err)
Expand All @@ -71,27 +74,45 @@ func (s *Server) join(w http.ResponseWriter, r *http.Request) {

pageData.FillingUsername = data.Username
pageData.FillingTeamName = data.TeamName
pageData.FillingTeamCode = data.TeamCode

if data.Username != "" || !isAuthenticated {
if data.TeamName != "" && data.TeamCode != "" {
writeError(fmt.Errorf("cannot provide both team name and team code"))
return
}

if isAuthenticated {
// If no username is provided, default to the current username.
if data.Username == "" {
data.Username = u.Username
}

// If neither team name nor team code is provided, assume the user
// remains on their current team.
if data.TeamName == "" && data.TeamCode == "" {
data.TeamName = u.TeamName
}
} else {
if !reUsername.MatchString(data.Username) {
writeError(fmt.Errorf("invalid username"))
return
}
}

if data.TeamName != "" || !isAuthenticated {
if !reTeamName.MatchString(data.TeamName) {
writeError(fmt.Errorf("invalid team name"))
return
// If neither team name nor team code is provided, default to the
// username.
if data.TeamName == "" && data.TeamCode == "" {
data.TeamName = data.Username
}
}

if isAuthenticated {
data.Username = u.Username
if data.TeamName != "" && !reTeamName.MatchString(data.TeamName) {
writeError(fmt.Errorf("invalid team name"))
return
}

if data.TeamName == "" && isAuthenticated {
data.TeamName = u.TeamName
if data.TeamCode != "" && !reTeamCode.MatchString(data.TeamCode) {
writeError(fmt.Errorf("invalid team code"))
return
}

err := s.database.Tx(func(q *db.Queries) error {
Expand All @@ -116,35 +137,32 @@ func (s *Server) join(w http.ResponseWriter, r *http.Request) {
}
}

team, err := q.FindTeamWithInviteCode(ctx, data.TeamName)
if err == nil {
_, err := q.JoinTeam(ctx, db.JoinTeamParams{
TeamName: team.TeamName,
Username: data.Username,
var isLeader bool
if data.TeamCode != "" {
t, err := q.FindTeamWithInviteCode(ctx, data.TeamCode)
if err != nil {
return fmt.Errorf("failed to find team: %w", err)
}
data.TeamName = t.TeamName
} else {
_, err := q.CreateTeam(ctx, db.CreateTeamParams{
TeamName: data.TeamName,
InviteCode: generateInviteCode(),
})
if err != nil {
return fmt.Errorf("failed to join team: %w", err)
return fmt.Errorf("failed to create team: %w", err)
}
return nil
isLeader = true
}

_, err = q.CreateTeam(ctx, db.CreateTeamParams{
TeamName: data.TeamName,
InviteCode: generateInviteCode(),
})
if err != nil {
return fmt.Errorf("failed to create team: %w", err)
}

_, err = q.JoinTeam(ctx, db.JoinTeamParams{
_, err := q.JoinTeam(ctx, db.JoinTeamParams{
TeamName: data.TeamName,
Username: data.Username,
IsLeader: true,
IsLeader: isLeader,
})
if err != nil {
return fmt.Errorf("failed to join team: %w", err)
}

return nil
})
if err != nil {
Expand Down

0 comments on commit d03d2b9

Please sign in to comment.