Skip to content

Commit

Permalink
Ability for users to signal that they are done (#321)
Browse files Browse the repository at this point in the history
  • Loading branch information
antoinejaussoin authored Oct 17, 2021
1 parent fbb3ab7 commit 99e581d
Show file tree
Hide file tree
Showing 31 changed files with 231 additions and 41 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@ This will run a demo version, which you can turn into a fully licenced version b

### Version 4.9.1 (unreleased)

- Add the ability for users to signal if they are done with their posts, to help the moderator
- ⏫ Upgrading dependencies

### Version 4.9.0
Expand Down
18 changes: 18 additions & 0 deletions backend/src/db/actions/sessions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -437,3 +437,21 @@ export function isAllowed(

return { allowed: true };
}

export async function toggleReady(
sessionId: string,
userId: string
): Promise<boolean> {
return await transaction(async (manager) => {
const sessionRepository = manager.getCustomRepository(SessionRepository);
const session = await sessionRepository.findOne(sessionId);
if (!session) {
return false;
}
session.ready = session.ready.includes(userId)
? session.ready.filter((id) => id !== userId)
: [...session.ready, userId];
await sessionRepository.save(session);
return session.ready.includes(userId);
});
}
4 changes: 4 additions & 0 deletions backend/src/db/entities/Session.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,8 @@ export default class SessionEntity {
visitors: UserEntity[] | undefined;
@Column({ default: false })
public locked: boolean;
@Column('text', { array: true, default: '{}' })
public ready: string[];
@CreateDateColumn({ type: 'timestamp with time zone' })
public created: Date | undefined;
@UpdateDateColumn({ type: 'timestamp with time zone' })
Expand All @@ -75,6 +77,7 @@ export default class SessionEntity {
posts: this.posts === undefined ? [] : this.posts.map((p) => p.toJson()),
encrypted: this.encrypted,
locked: this.locked,
ready: this.ready,
};
}

Expand All @@ -90,5 +93,6 @@ export default class SessionEntity {
this.options = new SessionOptionsEntity(options);
this.encrypted = null;
this.locked = false;
this.ready = [];
}
}
14 changes: 14 additions & 0 deletions backend/src/db/migrations/1634486639965-ReadyUsers.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import {MigrationInterface, QueryRunner} from "typeorm";

export class ReadyUsers1634486639965 implements MigrationInterface {
name = 'ReadyUsers1634486639965'

public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(`ALTER TABLE "sessions" ADD "ready" text array NOT NULL DEFAULT '{}'`);
}

public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(`ALTER TABLE "sessions" DROP COLUMN "ready"`);
}

}
26 changes: 26 additions & 0 deletions backend/src/game.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import {
WsErrorPayload,
WebsocketMessage,
WsGroupUpdatePayload,
WsUserReadyPayload,
} from '@retrospected/common';
import { RateLimiterMemory } from 'rate-limiter-flexible';
import chalk from 'chalk';
Expand All @@ -44,6 +45,7 @@ import {
saveTemplate,
doesSessionExists,
wasSessionCreatedBy,
toggleReady,
} from './db/actions/sessions';
import { getUser, getUserView } from './db/actions/users';
import {
Expand All @@ -69,6 +71,8 @@ const {
RECEIVE_EDIT_POST,
RECEIVE_DELETE_POST_GROUP,
RECEIVE_EDIT_POST_GROUP,
RECEIVE_USER_READY,
USER_READY,
ADD_POST_SUCCESS,
ADD_POST_GROUP_SUCCESS,
DELETE_POST,
Expand Down Expand Up @@ -201,6 +205,12 @@ export default (io: Server) => {
}
}

/**
* Check that UserIds is not null
* @param userIds User IDs
* @param socket Socket
* @returns Whether User is not null
*/
function checkUser(
userIds: UserIds | null,
socket: Socket
Expand Down Expand Up @@ -356,6 +366,21 @@ export default (io: Server) => {
}
};

const onUserReady = async (
userIds: UserIds | null,
sessionId: string,
_data: void,
socket: Socket
) => {
if (checkUser(userIds, socket)) {
const ready = await toggleReady(sessionId, userIds.userId);
sendToAll<WsUserReadyPayload>(socket, sessionId, RECEIVE_USER_READY, {
userId: userIds.userId,
ready,
});
}
};

const onDeletePost = async (
userIds: UserIds | null,
sessionId: string,
Expand Down Expand Up @@ -563,6 +588,7 @@ export default (io: Server) => {
{ type: REQUEST_BOARD, handler: onRequestBoard },
{ type: RENAME_SESSION, handler: onRenameSession },
{ type: LEAVE_SESSION, handler: onLeaveSession },
{ type: USER_READY, handler: onUserReady },
{ type: EDIT_OPTIONS, handler: onEditOptions, onlyAuthor: true },
{ type: EDIT_COLUMNS, handler: onEditColumns, onlyAuthor: true },
{ type: SAVE_TEMPLATE, handler: onSaveTemplate, onlyAuthor: true },
Expand Down
2 changes: 2 additions & 0 deletions common/src/actions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ export default {
SAVE_TEMPLATE: 'retrospected/session/template/save',
LOCK_SESSION: 'retrospected/session/lock',
REQUEST_BOARD: 'retrospected/session/request',
USER_READY: 'retrospected/user-ready',

RECEIVE_POST: 'retrospected/posts/receive/add',
RECEIVE_DELETE_POST: 'retrospected/posts/receive/delete',
Expand All @@ -34,4 +35,5 @@ export default {
RECEIVE_UNAUTHORIZED: 'retrospected/session/receive/unauthorized',
RECEIVE_RATE_LIMITED: 'retrospected/rate-limited-error',
RECEIVE_ERROR: 'retrospected/receive/error',
RECEIVE_USER_READY: 'retrospected/receive/user-ready',
};
1 change: 1 addition & 0 deletions common/src/models.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,4 +28,5 @@ export const defaultSession: Omit<Session, 'createdBy'> = {
options: { ...defaultOptions },
encrypted: null,
locked: false,
ready: [],
};
1 change: 1 addition & 0 deletions common/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ export interface Session extends PostContainer, Entity {
encrypted: string | null;
locked: boolean;
createdBy: User;
ready: string[];
}

export interface SessionMetadata extends Entity {
Expand Down
5 changes: 5 additions & 0 deletions common/src/ws.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,11 @@ export interface WsSaveTemplatePayload {
options: SessionOptions;
}

export interface WsUserReadyPayload {
userId: string;
ready: boolean;
}

export type WsErrorType =
| 'cannot_save_post'
| 'cannot_save_group'
Expand Down
2 changes: 1 addition & 1 deletion frontend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@
"recoil": "^0.4.1",
"rehype-raw": "^6.1.0",
"shortid": "^2.2.16",
"socket.io-client": "4.2.0",
"socket.io-client": "4.3.2",
"source-map-explorer": "^2.5.2",
"typescript": "^4.4.4",
"uuid": "^8.3.2",
Expand Down
1 change: 1 addition & 0 deletions frontend/src/testing/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ export const initialSession: Session = {
options: {
...defaultOptions,
},
ready: [],
};

export const AllTheProviders: React.FC = ({ children }) => {
Expand Down
2 changes: 2 additions & 0 deletions frontend/src/translations/ar.ts
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,8 @@ export default {
notLoggedIn: undefined,
error: undefined,
maxPostsReached: undefined,
iAmDone: undefined,
iAmNotDoneYet: undefined,
},
GameMenu: {
board: undefined,
Expand Down
2 changes: 2 additions & 0 deletions frontend/src/translations/de.ts
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,8 @@ export default {
notLoggedIn: undefined,
error: undefined,
maxPostsReached: undefined,
iAmDone: undefined,
iAmNotDoneYet: undefined,
},
GameMenu: {
board: undefined,
Expand Down
2 changes: 2 additions & 0 deletions frontend/src/translations/en.ts
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,8 @@ export default {
}
},
maxPostsReached: `You have reached the maximum number of posts set by the moderator.`,
iAmDone: "I'm done!",
iAmNotDoneYet: "I'm not done yet...",
},
GameMenu: {
board: 'Board',
Expand Down
2 changes: 2 additions & 0 deletions frontend/src/translations/es.ts
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,8 @@ export default {
notLoggedIn: undefined,
error: undefined,
maxPostsReached: undefined,
iAmDone: undefined,
iAmNotDoneYet: undefined,
},
GameMenu: {
board: undefined,
Expand Down
2 changes: 2 additions & 0 deletions frontend/src/translations/fr.ts
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,8 @@ export default {
}
},
maxPostsReached: `Vous avez atteint le nombre de posts maximum prévu par le modérateur.`,
iAmDone: "J'ai fini !",
iAmNotDoneYet: "Je n'ai pas encore fini...",
},
GameMenu: {
board: 'Board', // Si qqn à une suggestion de traduction...
Expand Down
2 changes: 2 additions & 0 deletions frontend/src/translations/hu.ts
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,8 @@ export default {
notLoggedIn: undefined,
error: undefined,
maxPostsReached: undefined,
iAmDone: undefined,
iAmNotDoneYet: undefined,
},
GameMenu: {
board: undefined,
Expand Down
2 changes: 2 additions & 0 deletions frontend/src/translations/it.ts
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,8 @@ export default {
notLoggedIn:
'Non sei autenticato. Puoi assistere a questa sessione come spettatore ma non puoi partecipare',
maxPostsReached: undefined,
iAmDone: undefined,
iAmNotDoneYet: undefined,
},
GameMenu: {
board: 'Board',
Expand Down
2 changes: 2 additions & 0 deletions frontend/src/translations/ja.ts
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,8 @@ export default {
notLoggedIn: undefined,
error: undefined,
maxPostsReached: undefined,
iAmDone: undefined,
iAmNotDoneYet: undefined,
},
GameMenu: {
board: undefined,
Expand Down
2 changes: 2 additions & 0 deletions frontend/src/translations/nl.ts
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,8 @@ export default {
notLoggedIn:
'Je bent niet ingelogd. Je kan de sessie bekijken als toeschouwer maar moet inloggen om deel te nemen.',
maxPostsReached: undefined,
iAmDone: undefined,
iAmNotDoneYet: undefined,
},
GameMenu: {
board: 'Bord',
Expand Down
2 changes: 2 additions & 0 deletions frontend/src/translations/pl.ts
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,8 @@ export default {
notLoggedIn: undefined,
error: undefined,
maxPostsReached: undefined,
iAmDone: undefined,
iAmNotDoneYet: undefined,
},
GameMenu: {
board: undefined,
Expand Down
2 changes: 2 additions & 0 deletions frontend/src/translations/pt-br.ts
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,8 @@ export default {
notLoggedIn: undefined,
error: undefined,
maxPostsReached: undefined,
iAmDone: undefined,
iAmNotDoneYet: undefined,
},
GameMenu: {
board: undefined,
Expand Down
2 changes: 2 additions & 0 deletions frontend/src/translations/ru.ts
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,8 @@ export default {
notLoggedIn: undefined,
error: undefined,
maxPostsReached: undefined,
iAmDone: undefined,
iAmNotDoneYet: undefined,
},
GameMenu: {
board: 'Записи',
Expand Down
2 changes: 2 additions & 0 deletions frontend/src/translations/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,8 @@ export interface Translation {
notLoggedIn?: string;
error?: (error: WsErrorType) => string;
maxPostsReached?: string;
iAmDone?: string;
iAmNotDoneYet?: string;
};
GameMenu: {
board?: string;
Expand Down
2 changes: 2 additions & 0 deletions frontend/src/translations/zh-cn.ts
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,8 @@ export default {
notLoggedIn: undefined,
error: undefined,
maxPostsReached: undefined,
iAmDone: undefined,
iAmNotDoneYet: undefined,
},
GameMenu: {
board: undefined,
Expand Down
2 changes: 2 additions & 0 deletions frontend/src/translations/zh-tw.ts
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,8 @@ export default {
notLoggedIn: undefined,
error: undefined,
maxPostsReached: undefined,
iAmDone: undefined,
iAmNotDoneYet: undefined,
},
GameMenu: {
board: undefined,
Expand Down
3 changes: 2 additions & 1 deletion frontend/src/views/Game.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ function GamePage() {
onEditColumns,
onSaveTemplate,
onLockSession,
onUserReady,
reconnect,
} = useGame(gameId);

Expand Down Expand Up @@ -182,7 +183,7 @@ function GamePage() {
/>
) : null}
<ParticipantContainer>
<Participants />
<Participants onReady={onUserReady} />
</ParticipantContainer>
</div>
);
Expand Down
Loading

0 comments on commit 99e581d

Please sign in to comment.