001/* 002 * Copyright 2024 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.cms.repository.mentions; 017 018import java.util.HashSet; 019import java.util.Set; 020import java.util.regex.Matcher; 021import java.util.regex.Pattern; 022 023import org.apache.avalon.framework.component.Component; 024import org.apache.avalon.framework.service.ServiceException; 025import org.apache.avalon.framework.service.ServiceManager; 026import org.apache.avalon.framework.service.Serviceable; 027 028import org.ametys.core.user.User; 029import org.ametys.core.user.UserIdentity; 030import org.ametys.core.user.UserManager; 031import org.ametys.core.util.I18nUtils; 032import org.ametys.core.util.StringUtils; 033import org.ametys.runtime.i18n.I18nizableText; 034import org.ametys.runtime.plugin.component.AbstractLogEnabled; 035 036/** 037 * Utils for Mentions 038 */ 039public class MentionUtils extends AbstractLogEnabled implements Component, Serviceable 040{ 041 /** Avalon role */ 042 public static final String ROLE = MentionUtils.class.getName(); 043 044 /** Regex used to extract mentions from a text. A mention is inside a @() */ 045 public static final String EXTRACT_MENTIONS_REGEX_SIMPLE_TEXT = "@\\(([^()]+)\\)"; 046 047 /** Regex used to extract mentions from a text. A mention is inside a @() */ 048 public static final String EXTRACT_MENTIONS_REGEX_RICH_TEXT = "data-ametys-mention-user=\"([^\"]+)\""; 049 050 /** A prefix to have before full name of a mentioned user */ 051 public static final String MENTIONED_USER_PREFIX = "@"; 052 053 /** The user manager */ 054 protected UserManager _userManager; 055 056 /** The i18n utils. */ 057 protected I18nUtils _i18nUtils; 058 059 public void service(ServiceManager manager) throws ServiceException 060 { 061 _userManager = (UserManager) manager.lookup(UserManager.ROLE); 062 _i18nUtils = (I18nUtils) manager.lookup(I18nUtils.ROLE); 063 } 064 065 /** 066 * Extract mentioned users from simple text content 067 * @param content the simple text content 068 * @return the set of mentioned users 069 */ 070 public static Set<UserIdentity> extractMentionedUsersFromSimpleText(String content) 071 { 072 Set<UserIdentity> mentionendUsers = new HashSet<>(); 073 if (content != null) 074 { 075 Pattern pattern = Pattern.compile(EXTRACT_MENTIONS_REGEX_SIMPLE_TEXT); 076 Matcher matcher = pattern.matcher(content); 077 078 while (matcher.find()) 079 { 080 String userIdentityAsString = matcher.group(1); 081 UserIdentity userIdentity = UserIdentity.stringToUserIdentity(userIdentityAsString); 082 mentionendUsers.add(userIdentity); 083 } 084 } 085 return mentionendUsers; 086 } 087 088 /** 089 * Extract mentioned users from rich text content 090 * @param content the rich text content 091 * @return the set of mentioned users 092 */ 093 public Set<UserIdentity> extractMentionedUsersFromRichText(String content) 094 { 095 Set<UserIdentity> mentionedUsers = new HashSet<>(); 096 Pattern pattern = Pattern.compile("data-ametys-mention-user=\"([^\"]+)\""); 097 Matcher matcher = pattern.matcher(content); 098 099 while (matcher.find()) 100 { 101 String userIdentityAsString = matcher.group(1); 102 UserIdentity userIdentity = UserIdentity.stringToUserIdentity(userIdentityAsString); 103 mentionedUsers.add(userIdentity); 104 } 105 return mentionedUsers; 106 } 107 108 /** 109 * Transform syntax text of a rich text to display text using a regex to find the parts to transform and a function to transform them 110 * @param syntaxText the syntax text 111 * @param recipient the recipient of the mail, for mail purposes 112 * @return the transformed text with colors according to the recipient 113 */ 114 public String transformRichTextToReadableText(String syntaxText, UserIdentity recipient) 115 { 116 String readableText = syntaxText; 117 118 if (syntaxText != null) 119 { 120 Pattern pattern = Pattern.compile(EXTRACT_MENTIONS_REGEX_RICH_TEXT); 121 Matcher matcher = pattern.matcher(syntaxText); 122 StringBuffer sb = new StringBuffer(); 123 124 while (matcher.find()) 125 { 126 String mentionBackgroundColor = _getMentionColor(recipient, matcher); 127 128 StringBuilder replaceBy = new StringBuilder("style=\"background: ").append(mentionBackgroundColor).append("; color: #1264a3\""); 129 130 matcher.appendReplacement(sb, Matcher.quoteReplacement(replaceBy.toString())); 131 } 132 matcher.appendTail(sb); 133 readableText = sb.toString(); 134 } 135 return readableText; 136 } 137 138 /** 139 * Transform syntax text of a simple text to display text using a regex to find the parts to transform and a function to transform them 140 * @param syntaxText the syntax text 141 * @param recipient the recipient of the mail, for mail purposes, can be null for any other purposes 142 * @return the transformed text with colors according to the recipient if not null, with full name in plain text otherwise 143 */ 144 public String transformTextToReadableText(String syntaxText, UserIdentity recipient) 145 { 146 String readableText = syntaxText; 147 if (org.apache.commons.lang3.StringUtils.isNotBlank(syntaxText)) 148 { 149 Pattern pattern = Pattern.compile(EXTRACT_MENTIONS_REGEX_SIMPLE_TEXT); 150 Matcher matcher = pattern.matcher(readableText); 151 StringBuffer sb = new StringBuffer(); 152 153 while (matcher.find()) 154 { 155 String userIdentityAsString = matcher.group(1); 156 UserIdentity mentionedUserIdentity = UserIdentity.stringToUserIdentity(userIdentityAsString); 157 User mentionedUser = _userManager.getUser(mentionedUserIdentity); 158 String mentionedUserName = mentionedUser != null ? (MENTIONED_USER_PREFIX + mentionedUser.getFullName()) : _i18nUtils.translate(new I18nizableText("plugin.core", "PLUGINS_CORE_USERS_UNKNOWN_USER")); 159 160 StringBuilder replaceBy = new StringBuilder(mentionedUserName); 161 if (recipient != null) 162 { 163 String mentionBackgroundColor = _getMentionColor(recipient, matcher); 164 165 replaceBy = new StringBuilder("<span style=\"background: ").append(mentionBackgroundColor).append("; color: #1264a3\">") 166 .append(StringUtils.escapeHTML(mentionedUserName)) 167 .append("</span>"); 168 } 169 170 matcher.appendReplacement(sb, Matcher.quoteReplacement(replaceBy.toString())); 171 } 172 matcher.appendTail(sb); 173 readableText = sb.toString(); 174 } 175 return readableText; 176 } 177 178 private String _getMentionColor(UserIdentity recipient, Matcher matcher) 179 { 180 String userIdentityAsString = matcher.group(1); 181 UserIdentity mentionedUserIdentity = UserIdentity.stringToUserIdentity(userIdentityAsString); 182 183 String mentionBackgroundColor = "rgba(29, 155, 209, 0.1)"; 184 if (mentionedUserIdentity.equals(recipient)) 185 { 186 mentionBackgroundColor = "rgba(255, 198, 0, 0.18)"; 187 } 188 return mentionBackgroundColor; 189 } 190 191}