Skip to content

Commit a9fcce1

Browse files
committed
manually implemented pr #208 (avoid rebase mess)
1 parent d017a1a commit a9fcce1

17 files changed

Lines changed: 432 additions & 23 deletions

File tree

core/controllers/media.php

Lines changed: 54 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,11 @@ public function formats_save()
7676
public function media_my_searches()
7777
{
7878
$this->user->require_authenticated();
79-
return [true,'Searches',['saved' => $this->models->media('search_get_saved', ['type' => 'saved']), 'history' => $this->models->media('search_get_saved', ['type' => 'history'])]];
79+
return [true,'Searches',[
80+
'saved' => $this->models->media('search_get_saved', ['type' => 'saved']),
81+
'history' => $this->models->media('search_get_saved', ['type' => 'history']),
82+
'shared' => $this->models->media('search_get_shared')
83+
]];
8084
}
8185

8286
/**
@@ -178,6 +182,55 @@ public function media_my_searches_unset_default()
178182
}
179183
}
180184

185+
/**
186+
* Share a saved search with users and/or groups.
187+
*
188+
* @param id
189+
* @param user_ids
190+
* @param group_ids
191+
*
192+
* @route POST /v2/media/searches/share
193+
*/
194+
public function media_my_searches_share()
195+
{
196+
$this->user->require_authenticated();
197+
198+
$user_ids = $this->data('user_ids');
199+
$group_ids = $this->data('group_ids');
200+
201+
if ($this->models->media('search_share', [
202+
'id' => $this->data('id'),
203+
'user_id' => $this->user->param('id'),
204+
'user_ids' => is_array($user_ids) ? $user_ids : [],
205+
'group_ids' => is_array($group_ids) ? $group_ids : [],
206+
])) {
207+
return [true,'Search shared successfully.'];
208+
} else {
209+
return [false,'Error sharing search.'];
210+
}
211+
}
212+
213+
/**
214+
* Remove sharing for a saved search.
215+
*
216+
* @param id
217+
*
218+
* @route DELETE /v2/media/searches/share/(:id:)
219+
*/
220+
public function media_my_searches_unshare()
221+
{
222+
$this->user->require_authenticated();
223+
224+
if ($this->models->media('search_unshare', [
225+
'id' => $this->data('id'),
226+
'user_id' => $this->user->param('id'),
227+
])) {
228+
return [true,'Search sharing removed.'];
229+
} else {
230+
return [false,'Error removing search sharing.'];
231+
}
232+
}
233+
181234
/**
182235
* Returns a boolean value determining whether the current user can edit the
183236
* provided media item. Private method used by a number of other methods in

core/models/media_model.php

Lines changed: 161 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -658,6 +658,167 @@ public function search_edit($args = [])
658658
return true;
659659
}
660660

661+
/**
662+
* Share a saved search with users and/or groups.
663+
*
664+
* @param id Search ID to share.
665+
* @param user_id Owner of the search (for validation).
666+
* @param user_ids Array of user IDs to share with.
667+
* @param group_ids Array of group IDs to share with.
668+
*
669+
* @return success
670+
*/
671+
public function search_share($args = [])
672+
{
673+
OBFHelpers::require_args($args, ['id', 'user_id']);
674+
OBFHelpers::default_args($args, ['user_ids' => [], 'group_ids' => []]);
675+
676+
// verify this search belongs to the user and is saved
677+
$this->db->where('id', $args['id']);
678+
$this->db->where('user_id', $args['user_id']);
679+
$this->db->where('type', 'saved');
680+
$search = $this->db->get_one('media_searches');
681+
682+
if (!$search) {
683+
return false;
684+
}
685+
686+
// remove existing shares for this search
687+
$this->db->where('search_id', $args['id']);
688+
$this->db->delete('media_searches_shared');
689+
690+
// share with users
691+
if (!empty($args['user_ids'])) {
692+
foreach ($args['user_ids'] as $share_user_id) {
693+
$share_user_id = (int) $share_user_id;
694+
695+
// don't share with self
696+
if ($share_user_id == $args['user_id']) {
697+
continue;
698+
}
699+
$this->db->insert('media_searches_shared', [
700+
'search_id' => $args['id'],
701+
'shared_by' => $args['user_id'],
702+
'shared_with_user_id' => $share_user_id,
703+
]);
704+
}
705+
}
706+
707+
// share with groups
708+
if (!empty($args['group_ids'])) {
709+
foreach ($args['group_ids'] as $group_id) {
710+
$this->db->insert('media_searches_shared', [
711+
'search_id' => $args['id'],
712+
'shared_by' => $args['user_id'],
713+
'shared_with_group_id' => (int) $group_id,
714+
]);
715+
}
716+
}
717+
718+
return true;
719+
}
720+
721+
/**
722+
* Remove all sharing for a saved search.
723+
*
724+
* @param id Search ID to unshare.
725+
* @param user_id Owner of the search (for validation).
726+
*
727+
* @return success
728+
*/
729+
public function search_unshare($args = [])
730+
{
731+
OBFHelpers::require_args($args, ['id', 'user_id']);
732+
733+
// verify this search belongs to the user
734+
$this->db->where('id', $args['id']);
735+
$this->db->where('user_id', $args['user_id']);
736+
$search = $this->db->get_one('media_searches');
737+
738+
if (!$search) {
739+
return false;
740+
}
741+
742+
$this->db->where('search_id', $args['id']);
743+
return $this->db->delete('media_searches_shared');
744+
}
745+
746+
/**
747+
* Get searches shared with the current user (directly or via groups).
748+
*
749+
* @return searches
750+
*/
751+
public function search_get_shared()
752+
{
753+
if (!$this->user->param('id')) {
754+
return [];
755+
}
756+
757+
$user_id = $this->db->escape($this->user->param('id'));
758+
759+
$this->db->query("
760+
SELECT DISTINCT ms.id, ms.query, ms.description, ms.`default`,
761+
mss.shared_by,
762+
u.display_name AS shared_by_name
763+
FROM media_searches ms
764+
JOIN media_searches_shared mss ON mss.search_id = ms.id
765+
LEFT JOIN users_to_groups utg ON utg.group_id = mss.shared_with_group_id
766+
LEFT JOIN users u ON u.id = mss.shared_by
767+
WHERE mss.shared_with_user_id = \"{$user_id}\"
768+
OR utg.user_id = \"{$user_id}\"
769+
");
770+
771+
$searches = $this->db->assoc_list();
772+
if (!is_array($searches)) {
773+
return [];
774+
}
775+
776+
foreach ($searches as $index => $search) {
777+
$searches[$index]['query'] = unserialize($search['query']);
778+
}
779+
780+
return $searches;
781+
}
782+
783+
/**
784+
* Get the recipients (users and groups) a search is shared with.
785+
*
786+
* @param id Search ID.
787+
* @param user_id Owner of the search (for validation).
788+
*
789+
* @return recipients Array with 'user_ids' and 'group_ids'.
790+
*/
791+
public function search_get_shared_recipients($args = [])
792+
{
793+
OBFHelpers::require_args($args, ['id', 'user_id']);
794+
795+
// verify ownership
796+
$this->db->where('id', $args['id']);
797+
$this->db->where('user_id', $args['user_id']);
798+
$search = $this->db->get_one('media_searches');
799+
800+
if (!$search) {
801+
return false;
802+
}
803+
804+
$this->db->where('search_id', $args['id']);
805+
$shares = $this->db->get('media_searches_shared');
806+
807+
$user_ids = [];
808+
$group_ids = [];
809+
810+
foreach ($shares as $share) {
811+
if (!empty($share['shared_with_user_id'])) {
812+
$user_ids[] = (int) $share['shared_with_user_id'];
813+
}
814+
if (!empty($share['shared_with_group_id'])) {
815+
$group_ids[] = (int) $share['shared_with_group_id'];
816+
}
817+
}
818+
819+
return ['user_ids' => $user_ids, 'group_ids' => $group_ids];
820+
}
821+
661822
/**
662823
* Get captions URL for media item
663824
*

core/updates/20260219.php

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
<?php
2+
3+
namespace OpenBroadcaster\Updates;
4+
5+
use OpenBroadcaster\Base\Update;
6+
7+
class OBUpdate20260219 extends Update
8+
{
9+
public function items()
10+
{
11+
$updates = [];
12+
$updates[] = "Create media_searches_shared table for sharing saved searches with users and groups.";
13+
return $updates;
14+
}
15+
16+
public function run()
17+
{
18+
$this->db->query('CREATE TABLE IF NOT EXISTS `media_searches_shared` (
19+
`id` INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
20+
`search_id` INT(10) UNSIGNED NOT NULL,
21+
`shared_by` INT(10) UNSIGNED NOT NULL,
22+
`shared_with_user_id` INT(10) UNSIGNED DEFAULT NULL,
23+
`shared_with_group_id` INT(10) UNSIGNED DEFAULT NULL,
24+
PRIMARY KEY (`id`),
25+
KEY `search_id` (`search_id`),
26+
KEY `shared_by` (`shared_by`),
27+
KEY `shared_with_user_id` (`shared_with_user_id`),
28+
KEY `shared_with_group_id` (`shared_with_group_id`),
29+
FOREIGN KEY (`search_id`) REFERENCES `media_searches`(`id`) ON DELETE CASCADE ON UPDATE CASCADE,
30+
FOREIGN KEY (`shared_by`) REFERENCES `users`(`id`) ON DELETE CASCADE ON UPDATE CASCADE,
31+
FOREIGN KEY (`shared_with_user_id`) REFERENCES `users`(`id`) ON DELETE CASCADE ON UPDATE CASCADE,
32+
FOREIGN KEY (`shared_with_group_id`) REFERENCES `users_groups`(`id`) ON DELETE CASCADE ON UPDATE CASCADE
33+
) ENGINE=InnoDB DEFAULT CHARSET=utf8;');
34+
35+
return true;
36+
}
37+
}

public/html/sidebar/my_searches.html

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,14 @@
1111
<div id="my_searches_saved"></div>
1212
</fieldset>
1313

14+
<fieldset>
15+
<legend data-t>Shared With Me</legend>
16+
17+
<p id="my_searches_shared_nosearches" class="hidden" data-t>No shared searches found.</p>
18+
19+
<div id="my_searches_shared"></div>
20+
</fieldset>
21+
1422
<fieldset>
1523
<legend data-t>Search History</legend>
1624

@@ -44,6 +52,11 @@
4452
<div class="hidden" id="my_searches_context_menu_unset_default">
4553
<a class="context_menu_item" onclick="OB.Sidebar.mySearchesUnsetDefault();" data-t>Unset Default</a>
4654
</div>
55+
<div><a class="context_menu_item" onclick="OB.Sidebar.mySearchesShareWindow();" data-t>Share</a></div>
4756
<div><a class="context_menu_item" onclick="OB.Sidebar.mySearchesDelete();" data-t>Delete</a></div>
4857
</div>
58+
59+
<div class="my_searches_context_menu" id="my_searches_shared_context_menu">
60+
<div><a class="context_menu_item" onclick="OB.Sidebar.mySearchesSearch($('.my_searches_item.context_menu_on').attr('data-id'));" data-t>Search</a></div>
61+
</div>
4962
</div>
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
<obwidget id="share_search_message" type="message"></obwidget>
2+
3+
<div>
4+
<p data-t>Select users and/or groups to share this search with.</p>
5+
6+
<fieldset>
7+
<legend data-t>Share With Users</legend>
8+
<div class="fieldrow">
9+
<select id="share_search_users" multiple size="6" style="width: 100%;"></select>
10+
</div>
11+
</fieldset>
12+
13+
<fieldset>
14+
<legend data-t>Share With Groups</legend>
15+
<div class="fieldrow">
16+
<select id="share_search_groups" multiple size="4" style="width: 100%;"></select>
17+
</div>
18+
</fieldset>
19+
20+
<fieldset>
21+
<div class="fieldrow">
22+
<ob-element-button
23+
data-text="Share"
24+
data-icon-name="share-nodes"
25+
data-icon-style="solid"
26+
onclick="OB.Sidebar.mySearchesShareSubmit();"
27+
data-t
28+
>Share</ob-element-button
29+
>
30+
<ob-element-button
31+
data-text="Cancel"
32+
data-icon-name="xmark"
33+
data-icon-style="solid"
34+
onclick="OB.UI.closeModalWindow();"
35+
data-t
36+
>Cancel</ob-element-button
37+
>
38+
</div>
39+
</fieldset>
40+
</div>

0 commit comments

Comments
 (0)