appwrite-database-repository
Version:
249 lines (248 loc) • 11.7 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.AppwriteRepository = void 0;
const node_appwrite_1 = require("node-appwrite");
const permission_type_enum_1 = require("./domain/permission-type.enum");
const NOT_FOUND_STATUS_CODE = 404;
const MAX_PAGE_SIZE = 5000;
class AppwriteRepository {
constructor(client, databaseId, collectionId) {
this.client = client;
this.databaseId = databaseId;
this.collectionId = collectionId;
this.databases = new node_appwrite_1.Databases(this.client);
}
async listDocuments(queries) {
return this.databases.listDocuments(this.databaseId, this.collectionId, queries);
}
async listByProperties(properties, extraQueries) {
const queries = [];
for (const [key, value] of Object.entries(properties)) {
queries.push(node_appwrite_1.Query.equal(key, value));
}
if (extraQueries) {
queries.push(...extraQueries);
}
return this.databases.listDocuments(this.databaseId, this.collectionId, queries);
}
async createDocument(data, permissions) {
const result = await this.databases.createDocument(this.databaseId, this.collectionId, node_appwrite_1.ID.unique(), data, permissions);
return result;
}
async createDocumentWithId(documentId, data, permissions) {
const result = await this.databases.createDocument(this.databaseId, this.collectionId, documentId, data, permissions);
return result;
}
async getDocument(documentId, queries) {
try {
return await this.databases.getDocument(this.databaseId, this.collectionId, documentId, queries);
}
catch (err) {
if (err.code === NOT_FOUND_STATUS_CODE) {
return null;
}
throw err;
}
}
async getDocumentBy(query) {
const queryList = [];
for (const [key, value] of Object.entries(query)) {
queryList.push(node_appwrite_1.Query.equal(key, value));
}
queryList.push(node_appwrite_1.Query.limit(1));
const { documents } = await this.databases.listDocuments(this.databaseId, this.collectionId, queryList);
return documents.length ? documents[0] : null;
}
async updateDocument(documentId, data, permissions) {
const result = await this.databases.updateDocument(this.databaseId, this.collectionId, documentId, data, permissions);
return result;
}
async deleteDocument(documentId) {
await this.databases.deleteDocument(this.databaseId, this.collectionId, documentId);
}
async createOrUpdateDocument(query, data, permissions) {
const existingDocument = await this.getDocumentBy(query);
if (existingDocument) {
return this.updateDocument(existingDocument.$id, data, permissions);
}
return this.createDocument(data, permissions);
}
async createOrUpdateBooleanAttribute(key, required, xdefault, array) {
const exists = await this.attributeExists(key);
if (exists) {
await this.databases.updateBooleanAttribute(this.databaseId, this.collectionId, key, required, xdefault ?? null);
}
else {
await this.databases.createBooleanAttribute(this.databaseId, this.collectionId, key, required, xdefault, array);
}
}
async createOrUpdateStringAttribute(key, size, required, xdefault, array, encrypt) {
const exists = await this.attributeExists(key);
if (exists) {
await this.databases.updateStringAttribute(this.databaseId, this.collectionId, key, required, xdefault ?? null);
}
else {
await this.databases.createStringAttribute(this.databaseId, this.collectionId, key, size, required, xdefault, array, encrypt);
}
}
async createOrUpdateDateTimeAttribute(key, required, xdefault, array) {
const exists = await this.attributeExists(key);
if (exists) {
await this.databases.updateDatetimeAttribute(this.databaseId, this.collectionId, key, required, xdefault ?? null);
}
else {
await this.databases.createDatetimeAttribute(this.databaseId, this.collectionId, key, required, xdefault, array);
}
}
async createOrUpdateEmailAttribute(key, required, xdefault, array) {
const exists = await this.attributeExists(key);
if (exists) {
await this.databases.updateEmailAttribute(this.databaseId, this.collectionId, key, required, xdefault ?? null);
}
else {
await this.databases.createEmailAttribute(this.databaseId, this.collectionId, key, required, xdefault, array);
}
}
async createOrUpdateEnumAttribute(key, elements, required, xdefault, array) {
const exists = await this.attributeExists(key);
if (exists) {
await this.databases.updateEnumAttribute(this.databaseId, this.collectionId, key, elements, required, xdefault ?? null);
}
else {
await this.databases.createEnumAttribute(this.databaseId, this.collectionId, key, elements, required, xdefault, array);
}
}
async createOrUpdateFloatAttribute(key, required, min, max, xdefault, array) {
const exists = await this.attributeExists(key);
if (exists) {
await this.databases.updateFloatAttribute(this.databaseId, this.collectionId, key, required, min ?? null, max ?? null, xdefault ?? null);
}
else {
await this.databases.createFloatAttribute(this.databaseId, this.collectionId, key, required, min, max, xdefault, array);
}
}
async createOrUpdateIntegerAttribute(key, required, min, max, xdefault) {
const exists = await this.attributeExists(key);
if (exists) {
await this.databases.updateIntegerAttribute(this.databaseId, this.collectionId, key, required, min ?? null, max ?? null, xdefault ?? null);
}
else {
await this.databases.createIntegerAttribute(this.databaseId, this.collectionId, key, required, min, max, xdefault);
}
}
async createOrUpdateIndex(key, type, attributes, orders) {
try {
return await this.databases.getIndex(this.databaseId, this.collectionId, key);
}
catch (err) {
if (err.code === NOT_FOUND_STATUS_CODE) {
return await this.databases.createIndex(this.databaseId, this.collectionId, key, type, attributes, orders);
}
console.error(err);
return await this.databases.createIndex(this.databaseId, this.collectionId, key, type, attributes, orders);
}
}
async getIndex(key) {
return this.databases.getIndex(this.databaseId, this.collectionId, key);
}
async attributeExists(key) {
try {
await this.getAttribute(key);
}
catch (err) {
if (err.code === NOT_FOUND_STATUS_CODE) {
return false;
}
}
return true;
}
async getAttribute(key) {
return this.databases.getAttribute(this.databaseId, this.collectionId, key);
}
async deleteAttribute(key) {
await this.databases.deleteAttribute(this.databaseId, this.collectionId, key);
}
async getCollection() {
return this.databases.getCollection(this.databaseId, this.collectionId);
}
async createOrUpdateCollection(name, permissions, documentSecurity, enabled) {
try {
await this.databases.getCollection(this.databaseId, this.collectionId);
}
catch (err) {
if (err.code === NOT_FOUND_STATUS_CODE) {
return this.databases.createCollection(this.databaseId, this.collectionId, name, permissions, documentSecurity, enabled);
}
console.error(err);
}
return this.databases.updateCollection(this.databaseId, this.collectionId, name, permissions, documentSecurity, enabled);
}
async hasCollectionPermission(client, permissionType) {
const collection = await this.getCollection();
return await this.hasPermission(client, collection.$permissions, permissionType);
}
async hasDocumentPermission(client, document, permissionType) {
return this.hasPermission(client, document.$permissions, permissionType);
}
async hasPermission(client, permissionsToCheck, permissionType) {
const typeIsWritePermission = [permission_type_enum_1.PermissionType.Create, permission_type_enum_1.PermissionType.Delete, permission_type_enum_1.PermissionType.Update].includes(permissionType);
if (typeIsWritePermission) {
const allowedByWritePermission = permissionsToCheck.some(permission => permission === 'write("any")');
if (allowedByWritePermission) {
return true;
}
}
const permissionsOfType = permissionsToCheck.filter((permission) => permission.startsWith(permissionType));
const allowedByAnyPermission = permissionsOfType.some(permission => permission === `${permissionType}("any")`);
if (allowedByAnyPermission) {
return true;
}
const userId = client.decodedToken.userId;
const allowedByUserPermission = permissionsOfType.some(permission => permission === `${permissionType}("user:${userId}")`);
if (allowedByUserPermission) {
return true;
}
const clientTeams = await this.findAllTeams(client);
const teamPermissionsWithoutRole = permissionsOfType.filter(permission => permission.includes('team:'));
const allowedByTeamPermission = teamPermissionsWithoutRole.some((teamPermission) => {
return clientTeams.some(team => teamPermission === `${permissionType}("team:${team.$id}")`);
});
if (allowedByTeamPermission) {
return true;
}
const teams = new node_appwrite_1.Teams(this.client);
const teamPermissionsWithRole = permissionsOfType.filter(permission => permission.startsWith(`${permissionType}("team:`) && permission.includes('/'));
for (const rolePermission of teamPermissionsWithRole) {
const teamId = this.getTeamIdFromTeamRolePermission(rolePermission);
if (!teamId) {
continue;
}
const memberships = (await teams.listMemberships(teamId, [node_appwrite_1.Query.equal('userId', client.decodedToken.userId)])).memberships;
const allMemberRoles = memberships.map(membership => membership.roles).flat();
const hasRolePermission = allMemberRoles.some((role) => rolePermission === `${permissionType}("team:${teamId}/${role}")`);
if (hasRolePermission) {
return true;
}
}
return false;
}
getTeamIdFromTeamRolePermission(permission) {
const teamSearch = 'team:';
const startIndex = permission.indexOf(teamSearch) + teamSearch.length;
const endIndex = permission.indexOf('/');
if (startIndex >= 5 && endIndex !== -1) {
return permission.substring(startIndex, endIndex);
}
else {
return null;
}
}
async findAllTeams(client) {
const teams = new node_appwrite_1.Teams(client);
return (await teams.list([node_appwrite_1.Query.limit(MAX_PAGE_SIZE)])).teams;
}
asAppClient(client) {
return new AppwriteRepository(client, this.databaseId, this.collectionId);
}
}
exports.AppwriteRepository = AppwriteRepository;