PluginProbe
OpenStation: Desktop Windows, Dock & Virtual Desktops for WP Admin / 1.1.8
OpenStation: Desktop Windows, Dock & Virtual Desktops for WP Admin v1.1.8
1.1.10 1.1.9 1.1.8 1.1.7 1.1.6 1.1.5 1.1.4 1.1.3 1.1.2 1.1.1 1.1.0 1.0.1 1.0.0 0.9.8 0.9.7 0.9.6 0.9.4 0.9.5 0.9.3 0.9.2 0.9.1 0.9.0 0.8.9 0.8.8 0.8.7 All 34 releases
desktop-mode / includes / desktop-files / types / class-openstation-user-file.php

class-openstation-user-file.php in OpenStation: Desktop Windows, Dock & Virtual Desktops for WP Admin 1.1.8, at includes/desktop-files/types/class-openstation-user-file.php

170 lines 4.8 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * OpenStation — `user` file type.
4 *
5 * @package OpenStation
6 */
7
8 defined( 'ABSPATH' ) || exit;
9
10 /**
11 * The `user` desktop file type.
12 */
13 class OpenStation_User_File extends OpenStation_File {
14
15 /**
16 * Get the file type identifier.
17 *
18 * @return string
19 */
20 public static function type(): string {
21 return 'user';
22 }
23
24 /**
25 * Whether the underlying user account still exists.
26 *
27 * @return bool
28 */
29 public function exists(): bool {
30 return $this->user() instanceof WP_User;
31 }
32
33 /**
34 * Get the user's display name.
35 *
36 * @return string
37 */
38 public function title(): string {
39 $user = $this->user();
40 if ( ! $user ) {
41 return __( '(missing user)', 'desktop-mode' );
42 }
43 return (string) $user->display_name;
44 }
45
46 /**
47 * Get the Dashicon class for user tiles.
48 *
49 * @return string
50 */
51 public function icon(): string {
52 return 'dashicons-admin-users';
53 }
54
55 /**
56 * Get the user's avatar URL for tile previews.
57 *
58 * @return string Empty string when no avatar is available.
59 */
60 public function preview_url(): string {
61 $user = $this->user();
62 if ( ! $user ) {
63 return '';
64 }
65 $avatar = get_avatar_url( $user->ID, array( 'size' => 96 ) );
66 return is_string( $avatar ) ? $avatar : '';
67 }
68
69 /**
70 * Gate visibility on the `list_users` capability so shared
71 * folders don't leak the user roster.
72 *
73 * @param int $user_id
74 * @return bool
75 */
76 public function can_read( int $user_id ): bool {
77 // Reading the existence of another user is gated on
78 // `list_users` to avoid leaking the user roster via shared
79 // folders. Tighter than `read` (every logged-in user has
80 // `read`) but looser than `edit_users`.
81 return user_can( $user_id, 'list_users' );
82 }
83
84 /**
85 * Augment the base serialized shape with roles, author archive
86 * URL, and agent metadata when applicable.
87 *
88 * @return array
89 */
90 public function serialize(): array {
91 $shape = parent::serialize();
92 $user = $this->user();
93 $shape['roles'] = $user ? array_values( (array) $user->roles ) : array();
94 // Author archive URL — surfaced so cross-frame drag handlers
95 // can build a `<a href>` to the author's posts on drop into
96 // Gutenberg without a REST roundtrip.
97 $shape['link'] = $user ? (string) get_author_posts_url( (int) $user->ID ) : '';
98
99 // OpenStation agent surface. `isAgent` marks the tile; the
100 // drag-trigger entity kinds ship inline so the tile drop
101 // handler can gate synchronously without an agents REST
102 // roundtrip: null = no drag trigger configured (tile rejects
103 // drops), [] = drag trigger with no filter (accepts every
104 // entity kind).
105 //
106 // The two guards test DIFFERENT things and both are load-
107 // bearing. `openstation_agent_is_agent()` lives in the agents
108 // guard, which loads unconditionally — being an agent is a
109 // property of the user row, and the row survives the feature
110 // being switched off. The definition getters live in store.php,
111 // which does NOT load then. Turning the `agents` extended
112 // option off while an agent tile sits on someone's desktop
113 // otherwise fatals the whole admin on the next boot payload.
114 if (
115 $user
116 && function_exists( 'openstation_agent_is_agent' )
117 && openstation_agent_is_agent( $user->ID )
118 ) {
119 $shape['isAgent'] = true;
120
121 // Named one by one rather than probing a single getter as
122 // a proxy for "store.php loaded": the proxy reads as an
123 // unguarded call at every other site, and this is a rule a
124 // test has to be able to check mechanically.
125 $has_definition = function_exists( 'openstation_agent_get_description' )
126 && function_exists( 'openstation_agent_get_triggers' );
127 // The "when to use" line — the chat window's subtitle when
128 // the tile opener starts a conversation.
129 $shape['agentDescription'] = $has_definition
130 ? openstation_agent_get_description( (int) $user->ID )
131 : '';
132
133 // Null while the framework is off: the tile still reads as
134 // an agent, but rejects every drop, because nothing can run
135 // to receive it.
136 $drag_kinds = null;
137 $triggers = $has_definition
138 ? openstation_agent_get_triggers( (int) $user->ID )
139 : array();
140 foreach ( $triggers as $trigger ) {
141 if ( 'drag' !== ( isset( $trigger['kind'] ) ? $trigger['kind'] : '' ) ) {
142 continue;
143 }
144 $kinds = isset( $trigger['config']['entityKinds'] ) && is_array( $trigger['config']['entityKinds'] )
145 ? $trigger['config']['entityKinds']
146 : array();
147 $drag_kinds = array_values( array_map( 'strval', $kinds ) );
148 break;
149 }
150 $shape['agentDragKinds'] = $drag_kinds;
151 }
152
153 return $shape;
154 }
155
156 /**
157 * Lazily resolve the underlying WP_User from the stored ref.
158 *
159 * @return WP_User|null Null when the user is gone or the ref is invalid.
160 */
161 private function user(): ?WP_User {
162 $id = (int) $this->ref;
163 if ( $id <= 0 ) {
164 return null;
165 }
166 $user = get_userdata( $id );
167 return $user instanceof WP_User ? $user : null;
168 }
169 }
170