diff --git a/lib/ops/community-store-ops.js b/lib/ops/community-store-ops.js --- a/lib/ops/community-store-ops.js +++ b/lib/ops/community-store-ops.js @@ -43,6 +43,19 @@ | RemoveCommunitiesOperation | RemoveAllCommunitiesOperation; +function convertCommunityInfoToClientDBCommunityInfo({ + id, + communityInfo, +}: { + +id: string, + +communityInfo: CommunityInfo, +}): ClientDBCommunityInfo { + return { + id, + communityInfo: JSON.stringify(communityInfo), + }; +} + const communityStoreOpsHandlers: BaseStoreOpsHandlers< CommunityStore, CommunityStoreOperation, @@ -89,10 +102,7 @@ return { type: 'replace_community', - payload: { - id: operation.payload.id, - communityInfo: JSON.stringify(operation.payload.communityInfo), - }, + payload: convertCommunityInfoToClientDBCommunityInfo(operation.payload), }; }); }, @@ -110,4 +120,7 @@ }, }; -export { communityStoreOpsHandlers }; +export { + communityStoreOpsHandlers, + convertCommunityInfoToClientDBCommunityInfo, +}; diff --git a/native/cpp/CommonCpp/DatabaseManagers/DatabaseQueryExecutor.h b/native/cpp/CommonCpp/DatabaseManagers/DatabaseQueryExecutor.h --- a/native/cpp/CommonCpp/DatabaseManagers/DatabaseQueryExecutor.h +++ b/native/cpp/CommonCpp/DatabaseManagers/DatabaseQueryExecutor.h @@ -1,6 +1,7 @@ #pragma once #include "../CryptoTools/Persist.h" +#include "entities/CommunityInfo.h" #include "entities/Draft.h" #include "entities/KeyserverInfo.h" #include "entities/Message.h" @@ -72,6 +73,10 @@ virtual void removeKeyservers(const std::vector &ids) const = 0; virtual void removeAllKeyservers() const = 0; virtual std::vector getAllKeyservers() const = 0; + virtual void replaceCommunity(const CommunityInfo &community_info) const = 0; + virtual void removeCommunities(const std::vector &ids) const = 0; + virtual void removeAllCommunities() const = 0; + virtual std::vector getAllCommunities() const = 0; virtual void beginTransaction() const = 0; virtual void commitTransaction() const = 0; virtual void rollbackTransaction() const = 0; diff --git a/native/cpp/CommonCpp/DatabaseManagers/SQLiteQueryExecutor.h b/native/cpp/CommonCpp/DatabaseManagers/SQLiteQueryExecutor.h --- a/native/cpp/CommonCpp/DatabaseManagers/SQLiteQueryExecutor.h +++ b/native/cpp/CommonCpp/DatabaseManagers/SQLiteQueryExecutor.h @@ -3,6 +3,7 @@ #include "../CryptoTools/Persist.h" #include "DatabaseQueryExecutor.h" #include "NativeSQLiteConnectionManager.h" +#include "entities/CommunityInfo.h" #include "entities/Draft.h" #include "entities/KeyserverInfo.h" #include "entities/UserInfo.h" @@ -87,6 +88,10 @@ void removeKeyservers(const std::vector &ids) const override; void removeAllKeyservers() const override; std::vector getAllKeyservers() const override; + void replaceCommunity(const CommunityInfo &community_info) const override; + void removeCommunities(const std::vector &ids) const override; + void removeAllCommunities() const override; + std::vector getAllCommunities() const override; void beginTransaction() const override; void commitTransaction() const override; void rollbackTransaction() const override; diff --git a/native/cpp/CommonCpp/DatabaseManagers/SQLiteQueryExecutor.cpp b/native/cpp/CommonCpp/DatabaseManagers/SQLiteQueryExecutor.cpp --- a/native/cpp/CommonCpp/DatabaseManagers/SQLiteQueryExecutor.cpp +++ b/native/cpp/CommonCpp/DatabaseManagers/SQLiteQueryExecutor.cpp @@ -1,6 +1,7 @@ #include "SQLiteQueryExecutor.h" #include "Logger.h" +#include "entities/CommunityInfo.h" #include "entities/EntityQueryHelpers.h" #include "entities/KeyserverInfo.h" #include "entities/Metadata.h" @@ -1491,6 +1492,48 @@ SQLiteQueryExecutor::getConnection(), getAllUsersSQL); } +void SQLiteQueryExecutor::replaceCommunity( + const CommunityInfo &community_info) const { + static std::string replaceCommunitySQL = + "REPLACE INTO communities (id, community_info) " + "VALUES (?, ?);"; + replaceEntity( + SQLiteQueryExecutor::getConnection(), + replaceCommunitySQL, + community_info); +} + +void SQLiteQueryExecutor::removeAllCommunities() const { + static std::string removeAllCommunitiesSQL = "DELETE FROM communities;"; + removeAllEntities( + SQLiteQueryExecutor::getConnection(), removeAllCommunitiesSQL); +} + +void SQLiteQueryExecutor::removeCommunities( + const std::vector &ids) const { + if (!ids.size()) { + return; + } + + std::stringstream removeCommunitiesByKeysSQLStream; + removeCommunitiesByKeysSQLStream << "DELETE FROM communities " + "WHERE id IN " + << getSQLStatementArray(ids.size()) << ";"; + + removeEntitiesByKeys( + SQLiteQueryExecutor::getConnection(), + removeCommunitiesByKeysSQLStream.str(), + ids); +} + +std::vector SQLiteQueryExecutor::getAllCommunities() const { + static std::string getAllCommunitiesSQL = + "SELECT * " + "FROM communities;"; + return getAllEntities( + SQLiteQueryExecutor::getConnection(), getAllCommunitiesSQL); +} + void SQLiteQueryExecutor::beginTransaction() const { executeQuery(SQLiteQueryExecutor::getConnection(), "BEGIN TRANSACTION;"); } diff --git a/native/cpp/CommonCpp/DatabaseManagers/entities/CommunityInfo.h b/native/cpp/CommonCpp/DatabaseManagers/entities/CommunityInfo.h new file mode 100644 --- /dev/null +++ b/native/cpp/CommonCpp/DatabaseManagers/entities/CommunityInfo.h @@ -0,0 +1,24 @@ +#pragma once + +#include "SQLiteDataConverters.h" +#include +#include + +namespace comm { + +struct CommunityInfo { + std::string id; + std::string community_info; + + static CommunityInfo fromSQLResult(sqlite3_stmt *sqlRow, int idx) { + return CommunityInfo{ + getStringFromSQLRow(sqlRow, idx), getStringFromSQLRow(sqlRow, idx + 1)}; + } + + int bindToSQL(sqlite3_stmt *sql, int idx) const { + bindStringToSQL(id, sql, idx); + return bindStringToSQL(community_info, sql, idx + 1); + } +}; + +} // namespace comm diff --git a/web/cpp/SQLiteQueryExecutorBindings.cpp b/web/cpp/SQLiteQueryExecutorBindings.cpp --- a/web/cpp/SQLiteQueryExecutorBindings.cpp +++ b/web/cpp/SQLiteQueryExecutorBindings.cpp @@ -48,6 +48,9 @@ value_object("MessageStoreThreads") .field("id", &MessageStoreThread::id) .field("startReached", &MessageStoreThread::start_reached); + value_object("CommunityInfo") + .field("id", &CommunityInfo::id) + .field("communityInfo", &CommunityInfo::community_info); value_object("WebThread") .field("id", &WebThread::id) @@ -158,6 +161,11 @@ .function( "removeAllKeyservers", &SQLiteQueryExecutor::removeAllKeyservers) .function("getAllKeyservers", &SQLiteQueryExecutor::getAllKeyservers) + .function("replaceCommunity", &SQLiteQueryExecutor::replaceCommunity) + .function("removeCommunities", &SQLiteQueryExecutor::removeCommunities) + .function( + "removeAllCommunities", &SQLiteQueryExecutor::removeAllCommunities) + .function("getAllCommunities", &SQLiteQueryExecutor::getAllCommunities) .function("beginTransaction", &SQLiteQueryExecutor::beginTransaction) .function("commitTransaction", &SQLiteQueryExecutor::commitTransaction) .function( diff --git a/web/database/_generated/comm_query_executor.wasm b/web/database/_generated/comm_query_executor.wasm index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 GIT binary patch literal 0 Hc$@ { + let queryExecutor: ?SQLiteQueryExecutor = null; + let dbModule: ?EmscriptenModule = null; + + beforeAll(async () => { + dbModule = getDatabaseModule(); + }); + + beforeEach(() => { + if (!dbModule) { + return; + } + + queryExecutor = new dbModule.SQLiteQueryExecutor(FILE_PATH); + queryExecutor?.replaceCommunity( + convertCommunityInfoToClientDBCommunityInfo({ + communityInfo: TEST_COMMUNITY_1, + id: '1', + }), + ); + queryExecutor?.replaceCommunity( + convertCommunityInfoToClientDBCommunityInfo({ + communityInfo: TEST_COMMUNITY_2, + id: '2', + }), + ); + }); + + afterEach(() => { + if (!dbModule || !queryExecutor) { + return; + } + + clearSensitiveData(dbModule, FILE_PATH, queryExecutor); + }); + + it('should return all communities', () => { + const communities = queryExecutor?.getAllCommunities(); + + expect(communities).toHaveLength(2); + }); + + it('should remove all communities', () => { + queryExecutor?.removeAllCommunities(); + const communities = queryExecutor?.getAllCommunities(); + + expect(communities).toHaveLength(0); + }); + + it('should update community enabled apps', () => { + const community2Updated: CommunityInfo = { + enabledApps: { + calendar: true, + wiki: true, + tasks: true, + files: true, + }, + }; + + queryExecutor?.replaceCommunity( + convertCommunityInfoToClientDBCommunityInfo({ + communityInfo: community2Updated, + id: '2', + }), + ); + + const communities = queryExecutor?.getAllCommunities(); + if (!communities) { + throw new Error('communities not defined'); + } + + expect(communities).toHaveLength(2); + + const communitiesFromDB = + communityStoreOpsHandlers.translateClientDBData(communities); + + expect(communitiesFromDB['2']).toBeDefined(); + expect(communitiesFromDB['2'].enabledApps.calendar).toBe(true); + expect(communitiesFromDB['2'].enabledApps.wiki).toBe(true); + expect(communitiesFromDB['2'].enabledApps.tasks).toBe(true); + expect(communitiesFromDB['2'].enabledApps.files).toBe(true); + }); + + it('should remove community', () => { + queryExecutor?.removeCommunities(['2']); + + const communities = queryExecutor?.getAllCommunities(); + if (!communities) { + throw new Error('communities not defined'); + } + + expect(communities.length).toBe(1); + + const communitiesFromDB = + communityStoreOpsHandlers.translateClientDBData(communities); + + expect(communitiesFromDB['1']).toBeDefined(); + }); +}); diff --git a/web/database/types/sqlite-query-executor.js b/web/database/types/sqlite-query-executor.js --- a/web/database/types/sqlite-query-executor.js +++ b/web/database/types/sqlite-query-executor.js @@ -1,5 +1,6 @@ // @flow +import type { ClientDBCommunityInfo } from 'lib/ops/community-store-ops.js'; import type { ClientDBKeyserverInfo } from 'lib/ops/keyserver-store-ops.js'; import type { ClientDBReport } from 'lib/ops/report-store-ops.js'; import type { ClientDBUserInfo } from 'lib/ops/user-store-ops.js'; @@ -99,6 +100,11 @@ removeAllKeyservers(): void; getAllKeyservers(): ClientDBKeyserverInfo[]; + replaceCommunity(communityInfo: ClientDBCommunityInfo): void; + removeCommunities(ids: $ReadOnlyArray): void; + removeAllCommunities(): void; + getAllCommunities(): ClientDBCommunityInfo[]; + beginTransaction(): void; commitTransaction(): void; rollbackTransaction(): void;