Wiki source code of User API

Last modified by Vincent Massol on 2024/02/26 17:54

Show last authors
1 {{toc/}}
2
3 Package: ##org.xwiki.user##
4 Modules:
5
6 * ##xwiki-platform-user-api##
7 * ##xwiki-platform-user-script##
8 * ##xwiki-platform-user-resource##
9
10 = Use Cases =
11
12 Here are use cases that drove the design of the User API:
13
14 * Requirement 1: Make the API as simple and short to use as possible (e.g. ##$services.user.resolveUser('...').configuration.editor## is more complex than ##$services.user.properties.editor##)
15 * Requirement 2: Make the API as performant as possible in 2 areas:
16 ** Execution time: make it be as fast as possible to execute for the main needs (i.e. getting user properties)
17 ** Memory: Make it use the less memory possible
18 * Requirement 3: Ability to retrieve user properties
19 * Requirement 4: Ability to create, delete, update users and their properties and check for user existence
20 * Requirement 5: Ability to generate URLs that points to User profile pages
21 * Requirement 6: Ability to resolve not only direct user properties but also with fallbacks at different levels (current space, current wiki, xwiki.properties, etc)
22 * Requirement 7: The API has to be independent of the User store implementation (ie users stored in wiki pages or elsewhere)
23 * Requirement 8: The API has to be both read (get properties) and write (create users, update properties)
24 * Requirement 9 (added Nov 2020): Ability to use several stores at the same time (i.e. possibility to have one user reference coming from one store and another coming from another store). This allows for example to use User References from both XWiki and the Fediverse (webfinger) at the same time and have a user picker for both.
25
26 = Iteration Nov 2020 =
27
28 Requirement 9 implies adding a new textual format for user references in the form ##(<store hint><delimitation character(s)>)+<store-dependent reference id>##.
29
30 We need to find a delimitation character that is backward-compatible with the "document" store references (which is of the form ##<wiki>:<space1>.<spaceN>.<page>##, ##<space1>.<spaceN>.<page>## or ##<page>##).
31
32 Issue to resolve:
33 * Imagine that we have a user reference that is dependent on the store. It means this reference will be saved in various DB tables (author of a document, etc). Then imagine we change the store! Suddenly all existing references become invalid and cannot be used => We need a fixed reference format.
34
35 = Iteration N =
36
37 See:
38
39 * https://forum.xwiki.org/t/replace-concept-of-user-in-new-user-api-and-more/6470
40 * https://forum.xwiki.org/t/user-api-and-urls/6467
41
42 = Iteration 2 =
43
44 See https://github.com/xwiki/xwiki-platform/commit/d361507b181272ed37c57e7aaf2c64338e2c8b01
45
46 = Iteration 1 =
47
48 {{code language="java"}}
49 /**
50 * Represents an XWiki user. Note that it's independent from where users are stored, and should remain that way, so
51 * that we can switch the user store in the future.
52 *
53 * @version $Id$
54 * @since 12.2RC1
55 */
56 @Unstable
57 public interface User
58 {
59 /**
60 * @return true if the user is configured to display hidden documents in the wiki
61 */
62 boolean displayHiddenDocuments();
63
64 /**
65 * @return true if the user is active in the wiki. An active user can log in.
66 */
67 boolean isActive();
68
69 /**
70 * @return the first name of the user or null if not set
71 */
72 String getFirstName();
73
74 /**
75 * @return the last name of the user or null if not set
76 */
77 String getLastName();
78
79 /**
80 * @return the email address of the user and null if not set
81 */
82 String getEmail();
83
84 /**
85 * @return the type of the user (simple user, advanced user)
86 * @see <a href="https://bit.ly/37TUlCp">user profile</a>
87 */
88 UserType getType();
89
90 /**
91 * @return true if the user's email has been checked. In some configurations, users must have had their emails
92 * verified before they can access the wiki. Also, disabled users must have their emails checked to be
93 * able to view pages.
94 */
95 boolean isEmailChecked();
96
97 /**
98 * @return true if this user is the guest user (i.e. not a real user)
99 */
100 boolean isGuest();
101
102 /**
103 * @return true if this user is registered in the main wiki (i.e. it's a global user)
104 */
105 boolean isGlobal();
106
107 /**
108 * @return true if this user is the {@code superadmin} user
109 */
110 boolean isSuperAdmin();
111
112 /**
113 * @param propertyName the name of the user property to look for
114 * @return the value of the passed user property
115 */
116 Object getProperty(String propertyName);
117
118 /**
119 * @return the reference to his user (i.e. a way to retrieve this user's data)
120 */
121 UserReference getUserReference();
122 }
123 {{/code}}
124
125 {{code language="java"}}
126 /**
127 * CRUD operations on users.
128 *
129 * @version $Id$
130 * @since 12.2RC1
131 */
132 @Unstable
133 @Role
134 public interface UserManager
135 {
136 /**
137 * @param userReference the user to retrieve and if null then retrieve the current user
138 * @return the user object representing the user pointed to by the passed reference
139 */
140 User getUser(UserReference userReference);
141 }
142 {{/code}}
143
144 {{code language="java"}}
145 /**
146 * The type of the user (simple user, advanced user).
147 *
148 * @see <a href="https://bit.ly/37TUlCp">user profile</a>
149 * @version $Id$
150 * @since 12.2RC1
151 */
152 @Unstable
153 public enum UserType
154 {
155 /**
156 * Simple user (hides complex actions in the UI for simplicity).
157 */
158 SIMPLE,
159
160 /**
161 * Advanced user (sees all possible actions in the UI).
162 */
163 ADVANCED;
164
165 /**
166 * @param typeAsString the user type represented as a string ("simple", "advanced")
167 * @return the {@link UserType} object matching the passed string representation. All values different than
168 * {@code advanced} are considered to represent a simple user
169 */
170 public static UserType fromString(String typeAsString)
171 {
172 UserType result;
173 if (typeAsString != null && "advanced".equals(typeAsString)) {
174 result = ADVANCED;
175 } else {
176 result = SIMPLE;
177 }
178 return result;
179 }
180 }
181 {{/code}}
182
183 {{code language="java"}}
184 /**
185 * Abstracts the concept of User reference. This allows to support several store implementations for users.
186 * For example for an implementation storing the users in wiki pages, the internal reference would be a
187 * {@link org.xwiki.model.reference.DocumentReference}. The reference allows retrieving all the data about a user.
188 * Another internal reference implementation could be an ActivityPub URL for example.
189 *
190 * @version $Id$
191 * @since 12.2RC1
192 */
193 @Unstable
194 public interface UserReference
195 {
196 /**
197 * @param <T> the internal type of the reference
198 * @return the internal reference (e.g. a {@link org.xwiki.model.reference.DocumentReference} for an implementation
199 * storing users in wiki pages)
200 */
201 <T> T getReference();
202 }
203 {{/code}}
204
205 == Notes ==
206
207 * I've removed the UserManager#getCurrentUser() because it's not the purpose of UserManager to do that. Normally the current User should be put in the Execution Context and retrieved directly from there. However I don't know how to implement this for the moment. Currently the old XWikiUser object is put in the XWikiContext and it's complex to replace it with the User object (This requires changing the Authentication code (which currently returns a XWikiUser object). The other problem is that XWikiContext is in oldcore and thus we cannot have it depend on the user-default module (since that modules depends on oldcore itself). So we need to refactor how the user is set in the context and find a way to inject that information from either some authentication module (ie move authentication code currently located in oldcore - XWikiAuthServiceImpl - to some other module outside of oldcore) or from the user-default module. Thus FTM, I've chosen to offer a convenience way to get the current User object, by passing ##null## to UserManager#getUser(). This should be modified in the future when we can directly get the current User object from the context.
208
209 = TODO =
210
211 * Store the current User object in the Execution Context (or in the XWikiContext as a start)
212 * Add createUser() and deleteUser() to UserManager
213 * Add setters to User and add a saveUser() (or updateUser() to UserManager)

Get Connected