From b7fe369fabfb4cc46788a74bb2c9bf77274c1fc0 Mon Sep 17 00:00:00 2001 From: enahum Date: Sun, 12 Nov 2017 08:33:42 -0300 Subject: [PATCH] Apply data retention policy (#1122) --- app/actions/views/root.js | 16 +++++-- app/initial_state.js | 15 ++++-- app/store/middleware.js | 98 ++++++++++++++++++++++++++++++--------- assets/base/config.json | 2 - 4 files changed, 101 insertions(+), 30 deletions(-) diff --git a/app/actions/views/root.js b/app/actions/views/root.js index f767a667b..3495be554 100644 --- a/app/actions/views/root.js +++ b/app/actions/views/root.js @@ -1,10 +1,10 @@ // Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved. // See License.txt for license information. -import {PostTypes} from 'mattermost-redux/action_types'; +import {GeneralTypes, PostTypes} from 'mattermost-redux/action_types'; import {Client4} from 'mattermost-redux/client'; import {General} from 'mattermost-redux/constants'; -import {getClientConfig, getLicenseConfig} from 'mattermost-redux/actions/general'; +import {getClientConfig, getDataRetentionPolicy, getLicenseConfig} from 'mattermost-redux/actions/general'; import {getPosts} from 'mattermost-redux/actions/posts'; import {getMyTeams, getMyTeamMembers, selectTeam} from 'mattermost-redux/actions/teams'; @@ -16,11 +16,21 @@ import { export function loadConfigAndLicense() { return async (dispatch, getState) => { - const [config, license] = await Promise.all([ + const [configData, licenseData] = await Promise.all([ getClientConfig()(dispatch, getState), getLicenseConfig()(dispatch, getState) ]); + const config = configData.data || {}; + const license = licenseData.data || {}; + + if (config.DataRetentionEnableMessageDeletion && config.DataRetentionEnableMessageDeletion === 'true' && + license.IsLicensed === 'true' && license.DataRetention === 'true') { + getDataRetentionPolicy()(dispatch, getState); + } else { + dispatch({type: GeneralTypes.RECEIVED_DATA_RETENTION_POLICY, data: {}}); + } + return {config, license}; }; } diff --git a/app/initial_state.js b/app/initial_state.js index 454e1c478..2dbc20e40 100644 --- a/app/initial_state.js +++ b/app/initial_state.js @@ -9,6 +9,7 @@ const state = { appState: false, credentials: {}, config: {}, + dataRetentionPolicy: {}, deviceToken: '', license: {}, serverVersion: '' @@ -45,6 +46,9 @@ const state = { preferences: { myPreferences: {} }, + search: { + recent: [] + }, typing: {} }, errors: [], @@ -108,6 +112,10 @@ const state = { status: 'not_started', error: null }, + dataRetentionPolicy: { + status: 'not_started', + error: null + }, license: { status: 'not_started', error: null @@ -252,8 +260,7 @@ const state = { navigation: '', views: { channel: { - drafts: {}, - loading: false + drafts: {} }, fetchCache: {}, i18n: { @@ -270,7 +277,9 @@ const state = { selectServer: { serverUrl: Config.DefaultServerUrl }, - team: {}, + team: { + lastTeamId: '' + }, thread: { drafts: {} } diff --git a/app/store/middleware.js b/app/store/middleware.js index e176d7c98..42db91216 100644 --- a/app/store/middleware.js +++ b/app/store/middleware.js @@ -4,7 +4,7 @@ import DeviceInfo from 'react-native-device-info'; import {ViewTypes} from 'app/constants'; -import Config from 'assets/config'; +import initialState from 'app/initial_state'; export function messageRetention() { return (next) => (action) => { @@ -23,6 +23,7 @@ export function messageRetention() { // Keep only the last 60 messages for the last 5 viewed channels in each team // and apply data retention on those posts if applies + return next(cleanupState(action)); } else if (action.type === ViewTypes.DATA_CLEANUP) { const nextAction = cleanupState(action, true); @@ -36,8 +37,22 @@ export function messageRetention() { function resetStateForNewVersion(action) { const {payload} = action; const lastChannelForTeam = getLastChannelForTeam(payload); - let users = {}; + let general = initialState.entities.general; + if (payload.entities.general) { + general = payload.entities.general; + } + + let teams = initialState.entities.teams; + if (payload.entities.teams) { + teams = { + currentTeamId: payload.entities.teams.currentTeamId, + teams: payload.entities.teams.teams, + myMembers: payload.entities.teams.myMembers + }; + } + + let users = initialState.entities.users; if (payload.entities.users) { const currentUserId = payload.entities.users.currentUserId; if (currentUserId) { @@ -50,38 +65,74 @@ function resetStateForNewVersion(action) { } } + let preferences = initialState.entities.preferences; + if (payload.entities.preferences) { + preferences = payload.entities.preferences; + } + + let search = initialState.entities.search; + if (payload.entities.search && payload.entities.search.recent) { + search = { + recent: payload.entities.search.recent + }; + } + + let channelDrafts = initialState.views.channel.drafts; + if (payload.views.channel && payload.views.channel.drafts) { + channelDrafts = payload.views.channel.drafts; + } + + let i18n = initialState.views.i18n; + if (payload.views.i18n) { + i18n = payload.views.i18n; + } + + let fetchCache = initialState.views.fetchCache; + if (payload.views.fetchCache) { + fetchCache = payload.views.fetchCache; + } + + let lastTeamId = initialState.views.team.lastTeamId; + if (payload.views.team && payload.views.team.lastTeamId) { + lastTeamId = payload.views.team.lastTeamId; + } + + let threadDrafts = initialState.views.thread.drafts; + if (payload.views.thread && payload.views.thread.drafts) { + threadDrafts = payload.views.thread.drafts; + } + + let selectServer = initialState.views.selectServer; + if (payload.views.selectServer) { + selectServer = payload.views.selectServer; + } + const nextState = { app: { build: DeviceInfo.getBuildNumber(), version: DeviceInfo.getVersion() }, entities: { - general: payload.entities.general, - teams: { - currentTeamId: payload.entities.teams.currentTeamId, - teams: payload.entities.teams.teams, - myMembers: payload.entities.teams.myMembers - }, + general, + teams, users, - preferences: payload.entities.preferences, - search: { - recent: payload.entities.search ? payload.entities.search.recent : {} - } + preferences, + search }, views: { channel: { - drafts: payload.views.channel.drafts + drafts: channelDrafts }, - i18n: payload.views.i18n, - fetchCache: payload.views.fetchCache, + i18n, + fetchCache, team: { - lastTeamId: payload.views.team.lastTeamId, + lastTeamId, lastChannelForTeam }, thread: { - drafts: payload.views.thread.drafts + drafts: threadDrafts }, - selectServer: payload.views.selectServer + selectServer } }; @@ -126,7 +177,12 @@ function cleanupState(action, keepCurrent = false) { } }; - const retentionPeriod = Config.EnableMessageRetention ? Config.MessageRetentionPeriod + 1 : 0; + let retentionPeriod = 0; + if (resetPayload.entities.general && resetPayload.entities.general.dataRetentionPolicy && + resetPayload.entities.general.dataRetentionPolicy.message_deletion_enabled) { + retentionPeriod = resetPayload.entities.general.dataRetentionPolicy.message_retention_cutoff; + } + const postIdsToKeep = Object.values(lastChannelForTeam).reduce((array, channelIds) => { const ids = channelIds.reduce((result, id) => { // we need to check that the channel id is not already included @@ -152,9 +208,7 @@ function cleanupState(action, keepCurrent = false) { const post = payload.entities.posts.posts[postId]; if (post) { - const skip = keepCurrent && currentChannelId === post.channel_id; - - if (!skip && retentionPeriod && (Date.now() - post.create_at) / (1000 * 3600 * 24) > retentionPeriod) { + if (retentionPeriod && post.create_at < retentionPeriod) { const postsInChannel = nextEntitites.posts.postsInChannel[post.channel_id] || []; const index = postsInChannel.indexOf(postId); if (index !== -1) { diff --git a/assets/base/config.json b/assets/base/config.json index a07e7ffa1..6bc89e57d 100644 --- a/assets/base/config.json +++ b/assets/base/config.json @@ -1,7 +1,5 @@ { "DefaultServerUrl": "", - "EnableMessageRetention": false, - "MessageRetentionPeriod": 30, "TestServerUrl": "http://localhost:8065", "DefaultTheme": "default", "ShowErrorsList": false,