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}