001/*
002 *  Copyright 2023 Anyware Services
003 *
004 *  Licensed under the Apache License, Version 2.0 (the "License");
005 *  you may not use this file except in compliance with the License.
006 *  You may obtain a copy of the License at
007 *
008 *      http://www.apache.org/licenses/LICENSE-2.0
009 *
010 *  Unless required by applicable law or agreed to in writing, software
011 *  distributed under the License is distributed on an "AS IS" BASIS,
012 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 *  See the License for the specific language governing permissions and
014 *  limitations under the License.
015 */
016package org.ametys.plugins.workspaces.statistics;
017
018import java.util.ArrayList;
019import java.util.List;
020import java.util.Map;
021
022import org.apache.avalon.framework.service.ServiceException;
023import org.apache.avalon.framework.service.ServiceManager;
024import org.apache.avalon.framework.service.Serviceable;
025import org.apache.commons.lang3.StringUtils;
026
027import org.ametys.plugins.workspaces.project.ProjectManager;
028import org.ametys.plugins.workspaces.project.modules.WorkspaceModule;
029import org.ametys.plugins.workspaces.project.modules.WorkspaceModuleExtensionPoint;
030import org.ametys.plugins.workspaces.project.objects.Project;
031import org.ametys.runtime.config.Config;
032import org.ametys.runtime.i18n.I18nizableText;
033import org.ametys.runtime.plugin.component.PluginAware;
034import org.ametys.runtime.plugins.admin.statistics.Statistics;
035import org.ametys.runtime.plugins.admin.statistics.StatisticsNode;
036import org.ametys.runtime.plugins.admin.statistics.StatisticsProvider;
037import org.ametys.runtime.plugins.admin.statistics.StatisticsValue;
038
039/**
040 * Send workspaces statistics
041 */
042public class WorkspacesStatisticsProvider implements StatisticsProvider, Serviceable, PluginAware
043{
044    private ProjectManager _projectManager;
045    private WorkspaceModuleExtensionPoint _workspaceModuleEP;
046    private String _id;
047
048    public void service(ServiceManager manager) throws ServiceException
049    {
050        _projectManager = (ProjectManager) manager.lookup(ProjectManager.ROLE);
051        _workspaceModuleEP = (WorkspaceModuleExtensionPoint) manager.lookup(WorkspaceModuleExtensionPoint.ROLE);
052    }
053    
054    public void setPluginInfo(String pluginName, String featureName, String id)
055    {
056        _id = id;
057    }
058    
059    public Statistics getStatistics()
060    {
061        return new StatisticsNode(
062            _id,
063            new I18nizableText("plugin.workspaces", "PLUGINS_WORKSPACES_STATISTICS_LABEL"),
064            "ametysicon-abecedary4",
065            null,
066            List.of(
067                _configStats(),
068                _projectsStats(),
069                _modulesStats() 
070            ),
071            true
072        );
073    }
074
075    private StatisticsNode _configStats()
076    { 
077        boolean configChat = Config.getInstance().getValue("workspaces.chat.active", false, false);
078        boolean configVisio = configChat && StringUtils.isNotBlank(Config.getInstance().getValue("workspaces.chat.video.url", false, ""));
079        boolean configOOPreview = Config.getInstance().getValue("workspaces.onlyoffice.enabled", false, false);
080        boolean configOOEdit = configOOPreview && Config.getInstance().getValue("workspaces.onlyoffice.edition.enabled", false, false);
081        boolean configWebdav = Config.getInstance().getValue("workspaces.msoffice.enabled", false, false);
082        
083        return new StatisticsNode(
084            "config",
085            new I18nizableText("plugin.workspaces", "PLUGINS_WORKSPACES_STATISTICS_CONFIG_LABEL"),
086            "ametysicon-gear39",
087            (configChat ? 1 : 0) + (configVisio ? 1 : 0) + (configOOPreview ? 1 : 0) + (configOOEdit ? 1 : 0) + (configWebdav ? 1 : 0),
088            List.of(
089                new StatisticsValue(
090                    "chat",
091                    new I18nizableText("plugin.workspaces", "PLUGINS_WORKSPACES_STATISTICS_CONFIG_CHAT_LABEL"),
092                    "ametysicon-object-megaphone",
093                    configChat
094                ),
095                new StatisticsValue(
096                    "visio",
097                    new I18nizableText("plugin.workspaces", "PLUGINS_WORKSPACES_STATISTICS_CONFIG_VISIO_LABEL"),
098                    "ametysicon-object-camera",
099                    configVisio
100                ),                
101                new StatisticsValue(
102                    "oopreview",
103                    new I18nizableText("plugin.workspaces", "PLUGINS_WORKSPACES_STATISTICS_CONFIG_OOPREVIEW_LABEL"),
104                    "ametysicon-code-html-picture62",
105                    configOOPreview
106                ),                
107                new StatisticsValue(
108                    "ooedit",
109                    new I18nizableText("plugin.workspaces", "PLUGINS_WORKSPACES_STATISTICS_CONFIG_OOEDIT_LABEL"),
110                    "ametysicon-editor-indent-more",
111                    configOOEdit
112                ),                
113                new StatisticsValue(
114                    "webdav",
115                    new I18nizableText("plugin.workspaces", "PLUGINS_WORKSPACES_STATISTICS_CONFIG_WEBDAV_LABEL"),
116                    "ametysicon-file-extension-doc",
117                    configWebdav
118                )                
119            ),
120            false
121        );
122    }
123    
124    private StatisticsNode _modulesStats()
125    {
126        List<Map<String, Object>> projectsStatistics = _projectManager.getProjectsStatisticsForClientSide();
127        
128        List<Statistics> modulesStats = new ArrayList<>();
129        for (WorkspaceModule module : _workspaceModuleEP.getModules())
130        {
131            modulesStats.add(_moduleStat(projectsStatistics, module));
132        }
133        
134        return new StatisticsNode(
135            "modules",
136            new I18nizableText("plugin.workspaces", "PLUGINS_WORKSPACES_STATISTICS_MODULES_LABEL"),
137            "ametysicon-puzzle-piece1",
138            null,
139            modulesStats,
140            true
141        );
142    }
143    
144    private Statistics _moduleStat(List<Map<String, Object>> projectsStatistics, WorkspaceModule module)
145    {
146        long totalActivated = 0;
147        
148        long totalSize = 0;
149        long maxSize = 0;
150        List<Long> sizes = new ArrayList<>();
151        
152        long totalCount = 0;
153        long maxCount = 0;
154        List<Long> counts = new ArrayList<>();
155        
156        for (Map<String, Object> oneProjectStatistics : projectsStatistics)
157        {
158            if ((Boolean) oneProjectStatistics.get(module.getModuleName() + "$activated"))
159            {
160                totalActivated++;
161                
162                long size = (Long) oneProjectStatistics.get(module.getModuleName() + "$size");
163                if (size > 0) // negative size are error messages
164                {
165                    totalSize += size;
166                    maxSize = Math.max(maxSize, size);
167                    sizes.add(size);
168                }
169                
170                String numberKey = oneProjectStatistics.keySet().stream().filter(k -> k.startsWith(module.getModuleName() + "$") && k.endsWith("_number")).findFirst().orElse(null);
171                if (numberKey != null)
172                {
173                    long count = ((Number) oneProjectStatistics.get(numberKey)).longValue();
174                    totalCount += count;
175                    maxCount = Math.max(maxCount, count);
176                    counts.add(count);
177                }
178            } 
179        }
180        
181        counts.sort(null);
182        sizes.sort(null);
183        
184        return new StatisticsNode(
185            module.getModuleName(),
186            module.getModuleTitle(),
187            "ametysicon-puzzle33",
188            totalActivated,
189            List.of(
190                new StatisticsNode(
191                    "count",
192                    new I18nizableText("plugin.workspaces", "PLUGINS_WORKSPACES_STATISTICS_MODULES_COUNT_LABEL"),
193                    "ametysicon-maths-abacus",
194                    totalCount,
195                    List.of(
196                        new StatisticsValue(
197                            "max",
198                            new I18nizableText("plugin.workspaces", "PLUGINS_WORKSPACES_STATISTICS_MODULES_COUNT_MAX_LABEL"),
199                            "ametysicon-sort51",
200                            maxCount
201                        ),
202                        new StatisticsValue(
203                            "median",
204                            new I18nizableText("plugin.workspaces", "PLUGINS_WORKSPACES_STATISTICS_MODULES_COUNT_MEDIAN_LABEL"),
205                            "ametysicon-maths-window-symbol-x",
206                            counts.size() > 0 ? counts.get(counts.size() / 2) : 0
207                        )                        
208                    ),
209                    false
210                ),
211                new StatisticsNode(
212                    "size",
213                    new I18nizableText("plugin.workspaces", "PLUGINS_WORKSPACES_STATISTICS_MODULES_SIZE_LABEL"),
214                    "ametysicon-code-css-letter-spacing",
215                    totalSize,
216                    List.of(
217                        new StatisticsValue(
218                            "max",
219                            new I18nizableText("plugin.workspaces", "PLUGINS_WORKSPACES_STATISTICS_MODULES_SIZE_MAX_LABEL"),
220                            "ametysicon-sort51",
221                            maxSize
222                        ),
223                        new StatisticsValue(
224                            "median",
225                            new I18nizableText("plugin.workspaces", "PLUGINS_WORKSPACES_STATISTICS_MODULES_SIZE_MEDIAN_LABEL"),
226                            "ametysicon-maths-window-symbol-x",
227                            sizes.size() > 0 ? sizes.get(sizes.size() / 2) : 0
228                        ) 
229                    ),
230                    false
231                )
232            ),
233            false
234        );
235    }
236    
237    private StatisticsNode _projectsStats()
238    {
239        long nbPrivate = 0;
240        long nbModerated = 0;
241        long nbPublic = 0;
242           
243        for (Project project : _projectManager.getProjects())
244        {
245            switch (project.getInscriptionStatus())
246            {
247                case OPEN:
248                    nbPublic++;
249                    break;
250                case MODERATED:
251                    nbModerated++;
252                    break;
253                case PRIVATE:
254                    nbPrivate++;
255                    break;
256                default:
257                    throw new IllegalArgumentException("Unknown inscriptionStatus " + project.getInscriptionStatus().toString() + " for project " + project.getId());
258            }
259        }
260        
261        return new StatisticsNode(
262            "count",
263            new I18nizableText("plugin.workspaces", "PLUGINS_WORKSPACES_STATISTICS_PROJECTS_LABEL"),
264            "ametysicon-file98",
265            nbPrivate + nbModerated + nbPublic,
266            List.of(
267                new StatisticsValue(
268                    "open",
269                    new I18nizableText("plugin.workspaces", "PLUGINS_WORKSPACES_STATISTICS_PROJECTS_OPEN_LABEL"),
270                    "ametysicon-body-group",
271                    nbPublic
272                ),
273                new StatisticsValue(
274                    "moderated",
275                    new I18nizableText("plugin.workspaces", "PLUGINS_WORKSPACES_STATISTICS_PROJECTS_MODERATED_LABEL"),
276                    "ametysicon-body-people-tie",
277                    nbModerated
278                ),
279                new StatisticsValue(
280                    "private",
281                    new I18nizableText("plugin.workspaces", "PLUGINS_WORKSPACES_STATISTICS_PROJECTS_PRIVATE_LABEL"),
282                    "ametysicon-body-people",
283                    nbPrivate
284                )
285            ),
286            false
287        );
288    }
289}