Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Remove the need to annually update speaker-mod feature #855

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion index.html
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta http-equiv="Content-Type" content="text/html" charset="utf-8" />
<link rel="icon" type="image/x-icon" href="favicon.png">
<title>Roguelike Celebration 2024</title>
<title>Roguelike Celebration</title>

<link rel="stylesheet" type="text/css" href="style/style.css" />
<script src="src/index.tsx" type="module"></script>
Expand Down
4 changes: 2 additions & 2 deletions server/src/database.ts
Original file line number Diff line number Diff line change
Expand Up @@ -75,12 +75,12 @@ interface Database {

setModStatus(userId: string, isMod: boolean)

setSpeakerStatus(userId: string, isSpeaker: boolean)
setSpeakerStatus(userId: string, year: string, isSpeaker: boolean)

banUser(user: User, isBanned: boolean)

modList(): Promise<string[]>
speakerList(): Promise<string[]>
speakerListForYear(year: string): Promise<string[]>

// -----------------------------------------------------------------
// SETTINGS DATA
Expand Down
41 changes: 21 additions & 20 deletions server/src/endpoints/toggleSpeakerStatus.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
import { AuthenticatedEndpointFunction, LogFn } from '../endpoint'
import { awardUserBadge, isSpeaker, minimizeUser, User } from '../user'
import { awardUserBadge, isSpeaker, isSpeakerForYear, minimizeUser, User } from '../user'
import { DB } from '../database'
import { UnlockableBadgeMap } from '../badges'

const toggleSpeakerStatus: AuthenticatedEndpointFunction = async (user: User, inputs: any, log: LogFn) => {
const userIdToToggle: string = inputs.userId
const isForPastYear = inputs.year !== '2024'
const year: string = inputs.year
const thisYear: string = `${(new Date()).getFullYear()}`
const isForPastYear = year !== thisYear

if (!userIdToToggle) {
return {
Expand All @@ -18,27 +20,26 @@ const toggleSpeakerStatus: AuthenticatedEndpointFunction = async (user: User, in

let toggledUser: User

/* toggle past speaker */
if (isForPastYear) {
const pastSpeakerBadge = UnlockableBadgeMap['🎙️']
// Set their database status (which will give them the special badge if current year)
if (await isSpeakerForYear(userIdToToggle, year)) {
log(`[MOD] Setting user ${userIdToToggle} to speaker=false for ${year}`)
toggledUser = await DB.setSpeakerStatus(userIdToToggle, year, false)
} else {
log(`[MOD] Setting user ${userIdToToggle} to speaker=true for ${year}`)
toggledUser = await DB.setSpeakerStatus(userIdToToggle, year, true)
}

const profile = await DB.getUser(userIdToToggle)
// Assign them the 'past speaker' badge
// (We don't currently have per-year speakers, that would be a reasonable improvement)
const pastSpeakerBadge = UnlockableBadgeMap['🎙️']

if (profile.unlockedBadges.includes(pastSpeakerBadge)) {
const remainingUnlockedBadges = profile.unlockedBadges.filter(badge => badge !== pastSpeakerBadge)
toggledUser = await DB.setPartialUserProfile(userIdToToggle, { unlockedBadges: remainingUnlockedBadges })
} else {
toggledUser = await awardUserBadge(userIdToToggle, pastSpeakerBadge)
}
/* toggle current speaker */
const profile = await DB.getUser(userIdToToggle)

if (profile.unlockedBadges.includes(pastSpeakerBadge)) {
const remainingUnlockedBadges = profile.unlockedBadges.filter(badge => badge !== pastSpeakerBadge)
toggledUser = await DB.setPartialUserProfile(userIdToToggle, { unlockedBadges: remainingUnlockedBadges })
} else {
if (await isSpeaker(userIdToToggle)) {
log(`[MOD] Setting user ${userIdToToggle} to speaker=false`)
toggledUser = await DB.setSpeakerStatus(userIdToToggle, false)
} else {
log(`[MOD] Setting user ${userIdToToggle} to speaker=true`)
toggledUser = await DB.setSpeakerStatus(userIdToToggle, true)
}
toggledUser = await awardUserBadge(userIdToToggle, pastSpeakerBadge)
}

return {
Expand Down
37 changes: 23 additions & 14 deletions server/src/redis.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,8 @@ interface RedisInternal extends Database {
addMod (userId: string)
removeMod (userId: string)

addSpeaker (userId: string)
removeSpeaker (userId: string)
addSpeakerForYear (userId: string, year: string)
removeSpeakerForYear (userId: string, year: string)
}

const Redis: RedisInternal = {
Expand Down Expand Up @@ -213,8 +213,8 @@ const Redis: RedisInternal = {
return await getSet(modListKey) || []
},

async speakerList (): Promise<string[]> {
return await getSet(speakerListKey) || []
async speakerListForYear (year: string): Promise<string[]> {
return await getSet(speakerListKey(year)) || []
},

async setModStatus (userId: string, isMod: boolean) {
Expand All @@ -236,24 +236,30 @@ const Redis: RedisInternal = {
await removeFromSet(modListKey, userId)
},

async setSpeakerStatus (userId: string, isSpeaker: boolean) {
async setSpeakerStatus (userId: string, year: string, isSpeaker: boolean) {
const profile = await Redis.getUser(userId)
if (!profile.speakerYears) profile.speakerYears = []

if (isSpeaker) {
await Redis.addSpeaker(userId)
await Redis.addSpeakerForYear(userId, year)
if (!profile.speakerYears.includes(year)) {
profile.speakerYears.push(year)
}
} else {
await Redis.removeSpeaker(userId)
await Redis.removeSpeakerForYear(userId, year)
profile.speakerYears = profile.speakerYears.filter(y => y !== year)
}
const profile = await Redis.getUser(userId)
profile.isSpeaker = isSpeaker

await Redis.setUserProfile(userId, profile)
return profile
},

async addSpeaker (userId: string) {
await addToSet(speakerListKey, userId)
async addSpeakerForYear (userId: string, year: string) {
await addToSet(speakerListKey(year), userId)
},

async removeSpeaker (userId: string) {
await removeFromSet(speakerListKey, userId)
async removeSpeakerForYear (userId: string, year: string) {
await removeFromSet(speakerListKey(year), userId)
},

// Server settings
Expand Down Expand Up @@ -403,14 +409,17 @@ const Redis: RedisInternal = {
const activeUsersKey = 'activeUsersList'

const modListKey = 'mods'
const speakerListKey = 'speakers'

const serverSettingsKey = 'serverSettings'

const allUserIdsKey = 'allUserIds'

const roomIdsKey = 'roomIds'

function speakerListKey (year: string): string {
return `speakers_${year}`
}

function roomDataKey (roomId: string): string {
return `room_${roomId}`
}
Expand Down
13 changes: 9 additions & 4 deletions server/src/user.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ export interface MinimalUser {
username: string;
pronouns?: string;
isMod?: boolean;
isSpeaker?: boolean // TODO: Currently never set
speakerYears?: string[]
isBanned?: boolean;
// From https://www.w3schools.com/colors/colors_names.asp
nameColor?: string;
Expand Down Expand Up @@ -57,11 +57,16 @@ export async function isMod (userId: string) {
return modList.includes(userId)
}

export async function isSpeaker (userId: string) {
const speakerList = await DB.speakerList()
export async function isSpeakerForYear (userId: string, year: string) {
const speakerList = await DB.speakerListForYear(year)
return speakerList.includes(userId)
}

export async function isSpeaker (userId: string) {
const thisYear: string = `${(new Date()).getFullYear()}`
return await isSpeakerForYear(userId, thisYear)
}

export async function updateModStatus (userId: string) {
const userIsMod = await isMod(userId)

Expand Down Expand Up @@ -214,7 +219,7 @@ export function minimizeUser (user: User | PublicUser): MinimalUser {
item: user.item,
polymorph: user.polymorph,
isMod: user.isMod,
isSpeaker: user.isSpeaker,
speakerYears: user.speakerYears,
fontReward: user.fontReward,
equippedBadges: user.equippedBadges,
pronouns: user.pronouns
Expand Down
4 changes: 3 additions & 1 deletion src/components/GoHomeView.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
import React from 'react'

export default function GoHomeView () {
const thisYear: string = `${(new Date()).getFullYear()}`

return (
<div id='go-home'>
<h1>A magical force repels you from the entrance</h1>
<p>Roguelike Celebration is currently closed! Check the <a href="https://roguelike.club/event2024.html" target="_blank" rel="noreferrer">schedule</a> to see when our doors will be open again.</p>
<p>Roguelike Celebration is currently closed! Check the <a href={`https://roguelike.club/event${thisYear}.html`} target="_blank" rel="noreferrer">schedule</a> to see when our doors will be open again.</p>
<p>We look forward to celebrating again with you soon :)</p>
</div>
)
Expand Down
4 changes: 3 additions & 1 deletion src/components/LoggedOutView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,12 @@ const uiConfig = {
}

export default function LoggedOutView () {
const thisYear: string = `${(new Date()).getFullYear()}`

return (
<div>
<header role="banner">
<h1>Welcome to Roguelike Celebration 2024!</h1>
<h1>Welcome to Roguelike Celebration {thisYear}!</h1>
</header>
<main role="main">
<p>
Expand Down
18 changes: 11 additions & 7 deletions src/components/NameView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -33,10 +33,15 @@ export default function NameView (props: Props) {

const isSelf = props.userId === myId

// This will fail if the user's client has the wrong year set,
// that shouldn't be a concern?
const thisYear: string = `${(new Date()).getFullYear()}`
const lastYear: string = `${(new Date()).getFullYear() - 1}`

const user: User = userMap[props.userId]
const username = user && user.username
const isMod = user && user.isMod
const isSpeaker = user && user.isSpeaker
const isSpeaker = user && user.speakerYears?.includes(thisYear)
const isBanned = user && user.isBanned

// isMod = the user whose name being rendered is a mod
Expand Down Expand Up @@ -80,15 +85,15 @@ export default function NameView (props: Props) {
const doSpeaker = confirm(
`Are you sure you would like to ${isSpeaker ? 'remove' : 'add'} the user '${
data.username
}' ${isSpeaker ? 'from' : 'to'} the speaker list?`
}' ${isSpeaker ? 'from' : 'to'} the current (${thisYear}) speaker list?`
)
if (doSpeaker) {
toggleUserSpeaker(data.id, '2024')
toggleUserSpeaker(data.id, thisYear)
}
}

const handlePastSpeaker = (e, data) => {
toggleUserSpeaker(data.id, '2023')
toggleUserSpeaker(data.id, lastYear)
}

const pastSpeakerButton = userIsMod ? (
Expand All @@ -98,7 +103,7 @@ export default function NameView (props: Props) {
}
onClick={handlePastSpeaker}
>
Make 2023 speaker
Make Previous (${lastYear}) Speaker
</MenuItem>
) : (
''
Expand Down Expand Up @@ -154,8 +159,7 @@ export default function NameView (props: Props) {
const badges = (user.equippedBadges || [])
.map((b, i) => <BadgeView key={`badge-${i}`} emoji={b?.emoji} description={b?.description} isCustom={b?.isCustom} />)

// TODO: This is not yet being set anywhere
if (user.isSpeaker) {
if (isSpeaker) {
badges.unshift(
<BadgeView key='badge-speaker' isCustom={true} emoji='speaker' description='Speaker' />
)
Expand Down
Loading