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.runtime.i18n.I18nizableText;
033import org.ametys.runtime.plugin.component.AbstractLogEnabled;
034
035/**
036 * Utils for Mentions
037 */
038public class MentionUtils extends AbstractLogEnabled implements Component, Serviceable
039{
040    /** Avalon role */
041    public static final String ROLE = MentionUtils.class.getName();
042
043    /** Regex used to extract mentions from a text. A mention is inside a @() */
044    public static final String EXTRACT_MENTIONS_REGEX_SIMPLE_TEXT = "@\\(([^()]+)\\)";
045
046    /** Regex used to extract mentions from a text. A mention is inside a @() */
047    public static final String EXTRACT_MENTIONS_REGEX_RICH_TEXT = "data-ametys-mention-user=\"([^\"]+)\"";
048    
049    /** A prefix to have before full name of a mentioned user */
050    public static final String MENTIONED_USER_PREFIX = "@";
051
052    /** The user manager */
053    protected UserManager _userManager;
054
055    /** The i18n utils. */
056    protected I18nUtils _i18nUtils;
057    
058    public void service(ServiceManager manager) throws ServiceException
059    {
060        _userManager = (UserManager) manager.lookup(UserManager.ROLE);
061        _i18nUtils = (I18nUtils) manager.lookup(I18nUtils.ROLE);
062    }
063
064    /**
065     * Extract mentioned users from simple text content
066     * @param content the simple text content
067     * @return the set of mentioned users
068     */
069    public static Set<UserIdentity> extractMentionedUsersFromSimpleText(String content)
070    {
071        Set<UserIdentity> mentionendUsers = new HashSet<>();
072        if (content != null)
073        {
074            Pattern pattern = Pattern.compile(EXTRACT_MENTIONS_REGEX_SIMPLE_TEXT);
075            Matcher matcher = pattern.matcher(content);
076            
077            while (matcher.find())
078            {
079                String userIdentityAsString = matcher.group(1);
080                UserIdentity userIdentity = UserIdentity.stringToUserIdentity(userIdentityAsString);
081                mentionendUsers.add(userIdentity);
082            }
083        }
084        return mentionendUsers;
085    }
086    
087    /**
088     * Extract mentioned users from rich text content
089     * @param content the rich text content
090     * @return the set of mentioned users
091     */
092    public Set<UserIdentity> extractMentionedUsersFromRichText(String content)
093    {
094        Set<UserIdentity> mentionedUsers = new HashSet<>();
095        Pattern pattern = Pattern.compile("data-ametys-mention-user=\"([^\"]+)\"");
096        Matcher matcher = pattern.matcher(content);
097
098        while (matcher.find())
099        {
100            String userIdentityAsString = matcher.group(1);
101            UserIdentity userIdentity = UserIdentity.stringToUserIdentity(userIdentityAsString);
102            mentionedUsers.add(userIdentity);
103        }
104        return mentionedUsers;
105    }
106
107    /**
108     * 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
109     * @param syntaxText the syntax text
110     * @param recipient the recipient of the mail, for mail purposes
111     * @return the transformed text with colors according to the recipient
112     */
113    public String transformRichTextToReadableText(String syntaxText, UserIdentity recipient)
114    {
115        String readableText = syntaxText;
116
117        if (syntaxText != null)
118        {
119            Pattern pattern = Pattern.compile(EXTRACT_MENTIONS_REGEX_RICH_TEXT);
120            Matcher matcher = pattern.matcher(syntaxText);
121            StringBuffer sb = new StringBuffer();
122
123            while (matcher.find())
124            {
125                String mentionBackgroundColor = _getMentionColor(recipient, matcher);
126                
127                StringBuilder replaceBy = new StringBuilder("style=\"background: ").append(mentionBackgroundColor).append("; color: #1264a3\"");
128                
129                matcher.appendReplacement(sb, Matcher.quoteReplacement(replaceBy.toString()));
130            }
131            matcher.appendTail(sb);
132            readableText = sb.toString();
133        }
134        return readableText;
135    }
136    
137    /**
138     * 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
139     * @param syntaxText the syntax text
140     * @param recipient the recipient of the mail, for mail purposes, can be null for any other purposes
141     * @return the transformed text with colors according to the recipient if not null, with full name in plain text otherwise
142     */
143    public String transformTextToReadableText(String syntaxText, UserIdentity recipient)
144    {
145        String readableText = syntaxText;
146
147        if (syntaxText != null)
148        {
149            Pattern pattern = Pattern.compile(EXTRACT_MENTIONS_REGEX_SIMPLE_TEXT);
150            Matcher matcher = pattern.matcher(syntaxText);
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(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}