/* * server component for the TimeLimit App * Copyright (C) 2019 - 2020 Jonas Lochmann * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as * published by the Free Software Foundation, version 3 of the License. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ import { difference, filter } from 'lodash' import * as Sequelize from 'sequelize' import { Database } from '../../../database' import { ClientDataStatusApps } from '../../../object/clientdatastatus' import { ServerInstalledAppsData } from '../../../object/serverdatastatus' import { GetServerDataStatusIllegalStateException } from './exception' import { FamilyEntry } from './family-entry' export async function getAppList ({ database, transaction, familyEntry, appsStatus }: { database: Database transaction: Sequelize.Transaction familyEntry: FamilyEntry appsStatus: ClientDataStatusApps }): Promise | null> { const serverInstalledAppsVersions = (await database.device.findAll({ where: { familyId: familyEntry.familyId }, attributes: ['deviceId', 'installedAppsVersion'], transaction })).map((item) => ({ deviceId: item.deviceId, installedAppsVersion: item.installedAppsVersion })) const getServerInstalledAppsVersionByDeviceId = (deviceId: string) => { const entry = serverInstalledAppsVersions.find((item) => item.deviceId === deviceId) if (!entry) { throw new GetServerDataStatusIllegalStateException({ staticMessage: 'could not find device entry' }) } return entry.installedAppsVersion } const serverDeviceIds = serverInstalledAppsVersions.map((item) => item.deviceId) const clientDeviceIds = Object.keys(appsStatus) const addedDeviceIds = difference(serverDeviceIds, clientDeviceIds) const deviceIdsWhereInstalledAppsHaveChanged = filter(Object.keys(appsStatus), (deviceId) => { const installedAppsVersion = appsStatus[deviceId] const serverEntry = serverInstalledAppsVersions.find((item) => item.deviceId === deviceId) return !!serverEntry && serverEntry.installedAppsVersion !== installedAppsVersion }) const idsOfDevicesWhereInstalledAppsMustBeSynced = [...addedDeviceIds, ...deviceIdsWhereInstalledAppsHaveChanged] if (idsOfDevicesWhereInstalledAppsMustBeSynced.length > 0) { const [appsToSync, activitiesToSync] = await Promise.all([ (async () => { return (await database.app.findAll({ where: { familyId: familyEntry.familyId, deviceId: { [Sequelize.Op.in]: idsOfDevicesWhereInstalledAppsMustBeSynced } }, attributes: [ 'deviceId', 'packageName', 'title', 'isLaunchable', 'recommendation' ], transaction })).map((item) => ({ deviceId: item.deviceId, packageName: item.packageName, title: item.title, isLaunchable: item.isLaunchable, recommendation: item.recommendation })) })(), (async () => { return (await database.appActivity.findAll({ where: { familyId: familyEntry.familyId, deviceId: { [Sequelize.Op.in]: idsOfDevicesWhereInstalledAppsMustBeSynced } }, attributes: [ 'deviceId', 'packageName', 'title', 'activityName' ], transaction })).map((item) => ({ deviceId: item.deviceId, packageName: item.packageName, activityName: item.activityName, title: item.title })) })() ]) return idsOfDevicesWhereInstalledAppsMustBeSynced.map((deviceId): ServerInstalledAppsData => ({ deviceId, apps: appsToSync.filter((item) => item.deviceId === deviceId).map((item) => ({ packageName: item.packageName, title: item.title, isLaunchable: item.isLaunchable, recommendation: item.recommendation })), activities: activitiesToSync.filter((item) => item.deviceId === deviceId).map((item) => ({ p: item.packageName, c: item.activityName, t: item.title })), version: getServerInstalledAppsVersionByDeviceId(deviceId) })) } else return null // no changes }