Display user badges
This commit is contained in:
parent
927c22ef73
commit
f647c4e053
95 changed files with 2891 additions and 424 deletions
|
@ -34,6 +34,7 @@ import { cleanDataForIpc } from './cleanDataForIpc';
|
|||
import type { ReactionType } from '../types/Reactions';
|
||||
import type { ConversationColorType, CustomColorType } from '../types/Colors';
|
||||
import type { UUIDStringType } from '../types/UUID';
|
||||
import type { BadgeType } from '../badges/types';
|
||||
import type { ProcessGroupCallRingRequestResult } from '../types/Calling';
|
||||
import type { RemoveAllConfiguration } from '../types/RemoveAllConfiguration';
|
||||
import createTaskWithTimeout from '../textsecure/TaskWithTimeout';
|
||||
|
@ -272,6 +273,10 @@ const dataInterface: ClientInterface = {
|
|||
updateEmojiUsage,
|
||||
getRecentEmojis,
|
||||
|
||||
getAllBadges,
|
||||
updateOrCreateBadges,
|
||||
badgeImageFileDownloaded,
|
||||
|
||||
removeAll,
|
||||
removeAllConfiguration,
|
||||
|
||||
|
@ -1575,6 +1580,27 @@ async function getRecentEmojis(limit = 32) {
|
|||
return channels.getRecentEmojis(limit);
|
||||
}
|
||||
|
||||
// Badges
|
||||
|
||||
function getAllBadges(): Promise<Array<BadgeType>> {
|
||||
return channels.getAllBadges();
|
||||
}
|
||||
|
||||
async function updateOrCreateBadges(
|
||||
badges: ReadonlyArray<BadgeType>
|
||||
): Promise<void> {
|
||||
if (badges.length) {
|
||||
await channels.updateOrCreateBadges(badges);
|
||||
}
|
||||
}
|
||||
|
||||
function badgeImageFileDownloaded(
|
||||
url: string,
|
||||
localPath: string
|
||||
): Promise<void> {
|
||||
return channels.badgeImageFileDownloaded(url, localPath);
|
||||
}
|
||||
|
||||
// Other
|
||||
|
||||
async function removeAll() {
|
||||
|
|
|
@ -21,6 +21,7 @@ import type { AttachmentType } from '../types/Attachment';
|
|||
import type { BodyRangesType } from '../types/Util';
|
||||
import type { QualifiedAddressStringType } from '../types/QualifiedAddress';
|
||||
import type { UUIDStringType } from '../types/UUID';
|
||||
import type { BadgeType } from '../badges/types';
|
||||
import type { RemoveAllConfiguration } from '../types/RemoveAllConfiguration';
|
||||
import type { LoggerType } from '../types/Logging';
|
||||
|
||||
|
@ -446,6 +447,10 @@ export type DataInterface = {
|
|||
updateEmojiUsage: (shortName: string, timeUsed?: number) => Promise<void>;
|
||||
getRecentEmojis: (limit?: number) => Promise<Array<EmojiType>>;
|
||||
|
||||
getAllBadges(): Promise<Array<BadgeType>>;
|
||||
updateOrCreateBadges(badges: ReadonlyArray<BadgeType>): Promise<void>;
|
||||
badgeImageFileDownloaded(url: string, localPath: string): Promise<void>;
|
||||
|
||||
removeAll: () => Promise<void>;
|
||||
removeAllConfiguration: (type?: RemoveAllConfiguration) => Promise<void>;
|
||||
|
||||
|
@ -572,6 +577,7 @@ export type ServerInterface = DataInterface & {
|
|||
removeKnownDraftAttachments: (
|
||||
allStickers: Array<string>
|
||||
) => Promise<Array<string>>;
|
||||
getAllBadgeImageFileLocalPaths: () => Promise<Set<string>>;
|
||||
};
|
||||
|
||||
export type ClientInterface = DataInterface & {
|
||||
|
|
145
ts/sql/Server.ts
145
ts/sql/Server.ts
|
@ -44,6 +44,9 @@ import { formatCountForLogging } from '../logging/formatCountForLogging';
|
|||
import type { ConversationColorType, CustomColorType } from '../types/Colors';
|
||||
import { ProcessGroupCallRingRequestResult } from '../types/Calling';
|
||||
import { RemoveAllConfiguration } from '../types/RemoveAllConfiguration';
|
||||
import type { BadgeType, BadgeImageType } from '../badges/types';
|
||||
import { parseBadgeCategory } from '../badges/BadgeCategory';
|
||||
import { parseBadgeImageTheme } from '../badges/BadgeImageTheme';
|
||||
import type { LoggerType } from '../types/Logging';
|
||||
import * as log from '../logging/log';
|
||||
import type { EmptyQuery, ArrayQuery, Query, JSONRows } from './util';
|
||||
|
@ -260,6 +263,10 @@ const dataInterface: ServerInterface = {
|
|||
updateEmojiUsage,
|
||||
getRecentEmojis,
|
||||
|
||||
getAllBadges,
|
||||
updateOrCreateBadges,
|
||||
badgeImageFileDownloaded,
|
||||
|
||||
removeAll,
|
||||
removeAllConfiguration,
|
||||
|
||||
|
@ -289,6 +296,7 @@ const dataInterface: ServerInterface = {
|
|||
removeKnownAttachments,
|
||||
removeKnownStickers,
|
||||
removeKnownDraftAttachments,
|
||||
getAllBadgeImageFileLocalPaths,
|
||||
};
|
||||
export default dataInterface;
|
||||
|
||||
|
@ -3571,12 +3579,149 @@ async function getRecentEmojis(limit = 32): Promise<Array<EmojiType>> {
|
|||
return rows || [];
|
||||
}
|
||||
|
||||
async function getAllBadges(): Promise<Array<BadgeType>> {
|
||||
const db = getInstance();
|
||||
|
||||
const [badgeRows, badgeImageFileRows] = db.transaction(() => [
|
||||
db.prepare<EmptyQuery>('SELECT * FROM badges').all(),
|
||||
db.prepare<EmptyQuery>('SELECT * FROM badgeImageFiles').all(),
|
||||
])();
|
||||
|
||||
const badgeImagesByBadge = new Map<
|
||||
string,
|
||||
Array<undefined | BadgeImageType>
|
||||
>();
|
||||
for (const badgeImageFileRow of badgeImageFileRows) {
|
||||
const { badgeId, order, localPath, url, theme } = badgeImageFileRow;
|
||||
const badgeImages = badgeImagesByBadge.get(badgeId) || [];
|
||||
badgeImages[order] = {
|
||||
...(badgeImages[order] || {}),
|
||||
[parseBadgeImageTheme(theme)]: {
|
||||
localPath: dropNull(localPath),
|
||||
url,
|
||||
},
|
||||
};
|
||||
badgeImagesByBadge.set(badgeId, badgeImages);
|
||||
}
|
||||
|
||||
return badgeRows.map(badgeRow => ({
|
||||
id: badgeRow.id,
|
||||
category: parseBadgeCategory(badgeRow.category),
|
||||
name: badgeRow.name,
|
||||
descriptionTemplate: badgeRow.descriptionTemplate,
|
||||
images: (badgeImagesByBadge.get(badgeRow.id) || []).filter(isNotNil),
|
||||
}));
|
||||
}
|
||||
|
||||
// This should match the logic in the badges Redux reducer.
|
||||
async function updateOrCreateBadges(
|
||||
badges: ReadonlyArray<BadgeType>
|
||||
): Promise<void> {
|
||||
const db = getInstance();
|
||||
|
||||
const insertBadge = prepare<Query>(
|
||||
db,
|
||||
`
|
||||
INSERT OR REPLACE INTO badges (
|
||||
id,
|
||||
category,
|
||||
name,
|
||||
descriptionTemplate
|
||||
) VALUES (
|
||||
$id,
|
||||
$category,
|
||||
$name,
|
||||
$descriptionTemplate
|
||||
);
|
||||
`
|
||||
);
|
||||
const getImageFilesForBadge = prepare<Query>(
|
||||
db,
|
||||
'SELECT url, localPath FROM badgeImageFiles WHERE badgeId = $badgeId'
|
||||
);
|
||||
const insertBadgeImageFile = prepare<Query>(
|
||||
db,
|
||||
`
|
||||
INSERT INTO badgeImageFiles (
|
||||
badgeId,
|
||||
'order',
|
||||
url,
|
||||
localPath,
|
||||
theme
|
||||
) VALUES (
|
||||
$badgeId,
|
||||
$order,
|
||||
$url,
|
||||
$localPath,
|
||||
$theme
|
||||
);
|
||||
`
|
||||
);
|
||||
|
||||
db.transaction(() => {
|
||||
badges.forEach(badge => {
|
||||
const { id: badgeId } = badge;
|
||||
|
||||
const oldLocalPaths = new Map<string, string>();
|
||||
for (const { url, localPath } of getImageFilesForBadge.all({ badgeId })) {
|
||||
if (localPath) {
|
||||
oldLocalPaths.set(url, localPath);
|
||||
}
|
||||
}
|
||||
|
||||
insertBadge.run({
|
||||
id: badgeId,
|
||||
category: badge.category,
|
||||
name: badge.name,
|
||||
descriptionTemplate: badge.descriptionTemplate,
|
||||
});
|
||||
|
||||
for (const [order, image] of badge.images.entries()) {
|
||||
for (const [theme, imageFile] of Object.entries(image)) {
|
||||
insertBadgeImageFile.run({
|
||||
badgeId,
|
||||
localPath:
|
||||
imageFile.localPath || oldLocalPaths.get(imageFile.url) || null,
|
||||
order,
|
||||
theme,
|
||||
url: imageFile.url,
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
})();
|
||||
}
|
||||
|
||||
async function badgeImageFileDownloaded(
|
||||
url: string,
|
||||
localPath: string
|
||||
): Promise<void> {
|
||||
const db = getInstance();
|
||||
prepare<Query>(
|
||||
db,
|
||||
'UPDATE badgeImageFiles SET localPath = $localPath WHERE url = $url'
|
||||
).run({ url, localPath });
|
||||
}
|
||||
|
||||
async function getAllBadgeImageFileLocalPaths(): Promise<Set<string>> {
|
||||
const db = getInstance();
|
||||
const localPaths = db
|
||||
.prepare<EmptyQuery>(
|
||||
'SELECT localPath FROM badgeImageFiles WHERE localPath IS NOT NULL'
|
||||
)
|
||||
.pluck()
|
||||
.all();
|
||||
return new Set(localPaths);
|
||||
}
|
||||
|
||||
// All data in database
|
||||
async function removeAll(): Promise<void> {
|
||||
const db = getInstance();
|
||||
|
||||
db.transaction(() => {
|
||||
db.exec(`
|
||||
DELETE FROM badges;
|
||||
DELETE FROM badgeImageFiles;
|
||||
DELETE FROM conversations;
|
||||
DELETE FROM identityKeys;
|
||||
DELETE FROM items;
|
||||
|
|
43
ts/sql/migrations/44-badges.ts
Normal file
43
ts/sql/migrations/44-badges.ts
Normal file
|
@ -0,0 +1,43 @@
|
|||
// Copyright 2021 Signal Messenger, LLC
|
||||
// SPDX-License-Identifier: AGPL-3.0-only
|
||||
|
||||
import type { Database } from 'better-sqlite3';
|
||||
|
||||
import type { LoggerType } from '../../types/Logging';
|
||||
|
||||
export default function updateToSchemaVersion44(
|
||||
currentVersion: number,
|
||||
db: Database,
|
||||
logger: LoggerType
|
||||
): void {
|
||||
if (currentVersion >= 44) {
|
||||
return;
|
||||
}
|
||||
|
||||
db.transaction(() => {
|
||||
db.exec(
|
||||
`
|
||||
CREATE TABLE badges(
|
||||
id TEXT PRIMARY KEY,
|
||||
category TEXT NOT NULL,
|
||||
name TEXT NOT NULL,
|
||||
descriptionTemplate TEXT NOT NULL
|
||||
);
|
||||
|
||||
CREATE TABLE badgeImageFiles(
|
||||
badgeId TEXT REFERENCES badges(id)
|
||||
ON DELETE CASCADE
|
||||
ON UPDATE CASCADE,
|
||||
'order' INTEGER NOT NULL,
|
||||
url TEXT NOT NULL,
|
||||
localPath TEXT,
|
||||
theme TEXT NOT NULL
|
||||
);
|
||||
`
|
||||
);
|
||||
|
||||
db.pragma('user_version = 44');
|
||||
})();
|
||||
|
||||
logger.info('updateToSchemaVersion44: success!');
|
||||
}
|
|
@ -19,6 +19,7 @@ import type { Query, EmptyQuery } from '../util';
|
|||
import updateToSchemaVersion41 from './41-uuid-keys';
|
||||
import updateToSchemaVersion42 from './42-stale-reactions';
|
||||
import updateToSchemaVersion43 from './43-gv2-uuid';
|
||||
import updateToSchemaVersion44 from './44-badges';
|
||||
|
||||
function updateToSchemaVersion1(
|
||||
currentVersion: number,
|
||||
|
@ -1901,6 +1902,7 @@ export const SCHEMA_VERSIONS = [
|
|||
updateToSchemaVersion41,
|
||||
updateToSchemaVersion42,
|
||||
updateToSchemaVersion43,
|
||||
updateToSchemaVersion44,
|
||||
];
|
||||
|
||||
export function updateSchema(db: Database, logger: LoggerType): void {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue