source: extensions/community/main.inc.php @ 27038

Last change on this file since 27038 was 27038, checked in by plg, 7 years ago

2.6 compatibility: bug fixed on album creation and all "admin_only" methods.
This option was added in Piwigo 2.6 and disturbs the hack in Community that
gives "admin" status to users with upload permission when calling specific
API methods.

Discussion in progress to implement this hack in a cleaner way.

File size: 18.8 KB
Line 
1<?php
2/*
3Plugin Name: Community
4Version: auto
5Description: Non admin users can add photos
6Plugin URI: http://piwigo.org/ext/extension_view.php?eid=303
7Author: plg
8Author URI: http://piwigo.wordpress.com
9*/
10
11if (!defined('PHPWG_ROOT_PATH'))
12{
13  die('Hacking attempt!');
14}
15
16global $prefixeTable;
17
18// +-----------------------------------------------------------------------+
19// | Define plugin constants                                               |
20// +-----------------------------------------------------------------------+
21
22defined('COMMUNITY_ID') or define('COMMUNITY_ID', basename(dirname(__FILE__)));
23define('COMMUNITY_PATH' , PHPWG_PLUGINS_PATH.basename(dirname(__FILE__)).'/');
24define('COMMUNITY_PERMISSIONS_TABLE', $prefixeTable.'community_permissions');
25define('COMMUNITY_PENDINGS_TABLE', $prefixeTable.'community_pendings');
26define('COMMUNITY_VERSION', 'auto');
27
28include_once(COMMUNITY_PATH.'include/functions_community.inc.php');
29
30// init the plugin
31add_event_handler('init', 'community_init');
32/**
33 * plugin initialization
34 *   - check for upgrades
35 *   - unserialize configuration
36 *   - load language
37 */
38function community_init()
39{
40  global $conf, $user, $pwg_loaded_plugins;
41
42  // apply upgrade if needed
43  if (
44    COMMUNITY_VERSION == 'auto' or
45    $pwg_loaded_plugins[COMMUNITY_ID]['version'] == 'auto' or
46    safe_version_compare($pwg_loaded_plugins[COMMUNITY_ID]['version'], COMMUNITY_VERSION, '<')
47  )
48  {
49    // call install function
50    include_once(COMMUNITY_PATH.'include/install.inc.php');
51    community_install();
52
53    // update plugin version in database
54    if ( $pwg_loaded_plugins[COMMUNITY_ID]['version'] != 'auto' and COMMUNITY_VERSION != 'auto' )
55    {
56      $query = '
57UPDATE '. PLUGINS_TABLE .'
58SET version = "'. COMMUNITY_VERSION .'"
59WHERE id = "'. COMMUNITY_ID .'"';
60      pwg_query($query);
61
62      $pwg_loaded_plugins[COMMUNITY_ID]['version'] = COMMUNITY_VERSION;
63    }
64  }
65
66  // prepare plugin configuration
67  $conf['community'] = unserialize($conf['community']);
68
69  // TODO: generate permissions in $user['community_permissions'] if ws.php
70  // + remove all calls of community_get_user_permissions related to webservices
71  if (!defined('IN_ADMIN') or !IN_ADMIN)
72  {
73    $user['community_permissions'] = community_get_user_permissions($user['id']);
74  }
75}
76
77/* Plugin admin */
78add_event_handler('get_admin_plugin_menu_links', 'community_admin_menu');
79function community_admin_menu($menu)
80{
81  global $page;
82 
83  $query = '
84SELECT
85    COUNT(*)
86  FROM '.COMMUNITY_PENDINGS_TABLE.'
87    JOIN '.IMAGES_TABLE.' ON image_id = id
88  WHERE state = \'moderation_pending\'
89;';
90  $result = pwg_query($query);
91  list($page['community_nb_pendings']) = pwg_db_fetch_row($result);
92
93  $name = 'Community';
94  if ($page['community_nb_pendings'] > 0)
95  {
96    $style = 'background-color:#666;';
97    $style.= 'color:white;';
98    $style.= 'padding:1px 5px;';
99    $style.= 'border-radius:10px;';
100    $style.= 'margin-left:5px;';
101   
102    $name.= '<span style="'.$style.'">'.$page['community_nb_pendings'].'</span>';
103
104    if (defined('IN_ADMIN') and IN_ADMIN and $page['page'] == 'intro')
105    {
106      global $template;
107     
108      $template->set_prefilter('intro', 'community_pendings_on_intro');
109      $template->assign(
110        array(
111          'COMMUNITY_PENDINGS' => sprintf(
112            '<a href="%s">'.l10n('%u pending photos').'</a>',
113            get_root_url().'admin.php?page=plugin-community-pendings',
114            $page['community_nb_pendings']
115            ),
116          )
117        );
118    }
119  }
120
121  array_push(
122    $menu,
123    array(
124      'NAME' => $name,
125      'URL'  => get_root_url().'admin.php?page=plugin-community'
126      )
127    );
128
129  return $menu;
130}
131
132function community_pendings_on_intro($content, &$smarty)
133{
134  $pattern = '#<li>\s*{\$DB_ELEMENTS\}#ms';
135  $replacement = '<li>{$COMMUNITY_PENDINGS}</li><li>{$DB_ELEMENTS}';
136  return preg_replace($pattern, $replacement, $content);
137}
138
139add_event_handler('init', 'community_load_language');
140function community_load_language()
141{
142  if (!defined('IN_ADMIN') or !IN_ADMIN)
143  {
144    load_language('admin.lang');
145  }
146 
147  load_language('plugin.lang', COMMUNITY_PATH);
148}
149
150
151add_event_handler('loc_end_section_init', 'community_section_init');
152function community_section_init()
153{
154  global $tokens, $page;
155 
156  if ($tokens[0] == 'add_photos')
157  {
158    $page['section'] = 'add_photos';
159  }
160}
161
162add_event_handler('loc_end_index', 'community_index');
163function community_index()
164{
165  global $page;
166 
167  if (isset($page['section']) and $page['section'] == 'add_photos')
168  {
169    include(COMMUNITY_PATH.'add_photos.php');
170  }
171}
172
173add_event_handler('blockmanager_apply' , 'community_gallery_menu', EVENT_HANDLER_PRIORITY_NEUTRAL+10);
174function community_gallery_menu($menu_ref_arr)
175{
176  global $conf, $user;
177
178  // conditional : depending on community permissions, display the "Add
179  // photos" link in the gallery menu
180  $user_permissions = $user['community_permissions'];
181
182  if (!$user_permissions['community_enabled'])
183  {
184    return;
185  }
186
187  $menu = & $menu_ref_arr[0];
188
189  if (($block = $menu->get_block('mbMenu')) != null )
190  {
191    load_language('plugin.lang', COMMUNITY_PATH);
192
193    array_splice(
194      $block->data,
195      count($block->data),
196      0,
197      array(
198        '' => array(
199          'URL' => make_index_url(array('section' => 'add_photos')),
200          'TITLE' => l10n('Upload your own photos'),
201          'NAME' => l10n('Upload Photos')
202          )
203        )
204      );
205  }
206}
207
208
209add_event_handler('ws_add_methods', 'community_switch_user_to_admin', EVENT_HANDLER_PRIORITY_NEUTRAL+5);
210function community_switch_user_to_admin($arr)
211{
212  global $user, $community;
213
214  $service = &$arr[0];
215
216  if (is_admin())
217  {
218    return;
219  }
220 
221  $community = array('method' => $_REQUEST['method']);
222
223  if ('pwg.images.addSimple' == $community['method'])
224  {
225    $community['category'] = $_REQUEST['category'];
226  }
227  elseif ('pwg.images.add' == $community['method'])
228  {
229    $community['category'] = $_REQUEST['categories'];
230    $community['md5sum'] = $_REQUEST['original_sum'];
231  }
232
233  // $print_params = $params;
234  // unset($print_params['data']);
235  // file_put_contents('/tmp/community.log', '['.$methodName.'] '.json_encode($print_params)."\n" ,FILE_APPEND);
236
237  // conditional : depending on community permissions, display the "Add
238  // photos" link in the gallery menu
239  $user_permissions = community_get_user_permissions($user['id']);
240
241  if (count($user_permissions['upload_categories']) == 0 and !$user_permissions ['create_whole_gallery'])
242  {
243    return;
244  }
245
246  // if level of trust is low, then we have to set level to 16
247
248  $methods = array();
249  $methods[] = 'pwg.tags.add';
250  $methods[] = 'pwg.images.exist';
251  $methods[] = 'pwg.images.add';
252  $methods[] = 'pwg.images.addSimple';
253  $methods[] = 'pwg.images.addChunk';
254  $methods[] = 'pwg.images.checkUpload';
255  $methods[] = 'pwg.images.checkFiles';
256  $methods[] = 'pwg.images.setInfo';
257
258  if (in_array($community['method'], $methods))
259  {
260    $user['status'] = 'admin';
261  }
262
263  if ('pwg.categories.add' == $community['method'])
264  {
265    if (in_array($_REQUEST['parent'], $user_permissions['create_categories'])
266        or $user_permissions['create_whole_gallery'])
267    {
268      $user['status'] = 'admin';
269    }
270  }
271
272  return;
273}
274
275add_event_handler('ws_add_methods', 'community_ws_replace_methods', EVENT_HANDLER_PRIORITY_NEUTRAL+5);
276function community_ws_replace_methods($arr)
277{
278  global $conf, $user;
279 
280  $service = &$arr[0];
281
282  if (is_admin())
283  {
284    return;
285  }
286
287  $user_permissions = community_get_user_permissions($user['id']);
288 
289  if (count($user_permissions['permission_ids']) == 0)
290  {
291    return;
292  }
293 
294  // the plugin Community is activated, the user has upload permissions, we
295  // use a specific function to list available categories, assuming the user
296  // wants to list categories where upload is possible for him
297 
298  $service->addMethod(
299    'pwg.categories.getList',
300    'community_ws_categories_getList',
301    array(
302      'cat_id' =>       array('default'=>0),
303      'recursive' =>    array('default'=>false),
304      'public' =>       array('default'=>false),
305      'tree_output' =>  array('default'=>false),
306      'fullname' =>     array('default'=>false),
307      ),
308    'retrieves a list of categories'
309    );
310 
311  $service->addMethod(
312    'pwg.tags.getAdminList',
313    'community_ws_tags_getAdminList',
314    array(),
315    'administration method only'
316    );
317}
318
319/**
320 * returns a list of categories (web service method)
321 */
322function community_ws_categories_getList($params, &$service)
323{
324  global $user, $conf;
325
326  if ($params['tree_output'])
327  {
328    if (!isset($_GET['format']) or !in_array($_GET['format'], array('php', 'json')))
329    {
330      // the algorithm used to build a tree from a flat list of categories
331      // keeps original array keys, which is not compatible with
332      // PwgNamedArray.
333      //
334      // PwgNamedArray is useful to define which data is an attribute and
335      // which is an element in the XML output. The "hierarchy" output is
336      // only compatible with json/php output.
337
338      return new PwgError(405, "The tree_output option is only compatible with json/php output formats");
339    }
340  }
341 
342  $where = array('1=1');
343  $join_type = 'LEFT';
344  $join_user = $user['id'];
345
346  if (!$params['recursive'])
347  {
348    if ($params['cat_id']>0)
349      $where[] = '(id_uppercat='.(int)($params['cat_id']).'
350    OR id='.(int)($params['cat_id']).')';
351    else
352      $where[] = 'id_uppercat IS NULL';
353  }
354  else if ($params['cat_id']>0)
355  {
356    $where[] = 'uppercats '.DB_REGEX_OPERATOR.' \'(^|,)'.
357      (int)($params['cat_id'])
358      .'(,|$)\'';
359  }
360
361  if ($params['public'])
362  {
363    $where[] = 'status = "public"';
364    $where[] = 'visible = "true"';
365   
366    $join_user = $conf['guest_id'];
367  }
368
369  $user_permissions = community_get_user_permissions($user['id']);
370  $upload_categories = $user_permissions['upload_categories'];
371  if (count($upload_categories) == 0)
372  {
373    $upload_categories = array(-1);
374  }
375
376  $where[] = 'id IN ('.implode(',', $upload_categories).')';
377
378  $query = '
379SELECT
380    id,
381    name,
382    permalink,
383    uppercats,
384    global_rank,
385    comment,
386    nb_images,
387    count_images AS total_nb_images,
388    date_last,
389    max_date_last,
390    count_categories AS nb_categories
391  FROM '.CATEGORIES_TABLE.'
392   '.$join_type.' JOIN '.USER_CACHE_CATEGORIES_TABLE.' ON id=cat_id AND user_id='.$join_user.'
393  WHERE '. implode('
394    AND ', $where);
395
396  $result = pwg_query($query);
397
398  $cats = array();
399  while ($row = pwg_db_fetch_assoc($result))
400  {
401    $row['url'] = make_index_url(
402        array(
403          'category' => $row
404          )
405      );
406    foreach( array('id','nb_images','total_nb_images','nb_categories') as $key)
407    {
408      $row[$key] = (int)$row[$key];
409    }
410
411    if ($params['fullname'])
412    {
413      $row['name'] = strip_tags(get_cat_display_name_cache($row['uppercats'], null, false));
414    }
415    else
416    {
417      $row['name'] = strip_tags(
418        trigger_event(
419          'render_category_name',
420          $row['name'],
421          'ws_categories_getList'
422          )
423        );
424    }
425   
426    $row['comment'] = strip_tags(
427      trigger_event(
428        'render_category_description',
429        $row['comment'],
430        'ws_categories_getList'
431        )
432      );
433   
434    array_push($cats, $row);
435  }
436  usort($cats, 'global_rank_compare');
437
438  if ($params['tree_output'])
439  {
440    return categories_flatlist_to_tree($cats);
441  }
442  else
443  {
444    return array(
445      'categories' => new PwgNamedArray(
446        $cats,
447        'category',
448        array(
449          'id',
450          'url',
451          'nb_images',
452          'total_nb_images',
453          'nb_categories',
454          'date_last',
455          'max_date_last',
456          )
457        )
458      );
459  }
460}
461
462function community_ws_tags_getAdminList($params, &$service)
463{
464  $tags = get_available_tags();
465
466  // keep orphan tags
467  include_once(PHPWG_ROOT_PATH.'admin/include/functions.php');
468  $orphan_tags = get_orphan_tags();
469  if (count($orphan_tags) > 0)
470  {
471    $orphan_tag_ids = array();
472    foreach ($orphan_tags as $tag)
473    {
474      $orphan_tag_ids[] = $tag['id'];
475    }
476   
477    $query = '
478SELECT *
479  FROM '.TAGS_TABLE.'
480  WHERE id IN ('.implode(',', $orphan_tag_ids).')
481;';
482    $result = pwg_query($query);
483    while ($row = pwg_db_fetch_assoc($result))
484    {
485      $tags[] = $row;
486    }
487  }
488
489  usort($tags, 'tag_alpha_compare');
490 
491  return array(
492    'tags' => new PwgNamedArray(
493      $tags,
494      'tag',
495      array(
496        'name',
497        'id',
498        'url_name',
499        )
500      )
501    );
502}
503
504add_event_handler('sendResponse', 'community_sendResponse');
505function community_sendResponse($encodedResponse)
506{
507  global $community, $user;
508
509  if (!isset($community['method']))
510  {
511    return;
512  }
513
514  if ('pwg.images.addSimple' == $community['method'])
515  {
516    $response = json_decode($encodedResponse);
517    $image_id = $response->result->image_id;
518  }
519  elseif ('pwg.images.add' == $community['method'])
520  {   
521    $query = '
522SELECT
523    id
524  FROM '.IMAGES_TABLE.'
525  WHERE md5sum = \''.$community['md5sum'].'\'
526  ORDER BY id DESC
527  LIMIT 1
528;';
529    list($image_id) = pwg_db_fetch_row(pwg_query($query));
530  }
531  else
532  {
533    return;
534  }
535 
536  $image_ids = array($image_id);
537
538  // $category_id is set in the photos_add_direct_process.inc.php included script
539  $category_infos = get_cat_info($community['category']);
540
541  // should the photos be moderated?
542  //
543  // if one of the user community permissions is not moderated on the path
544  // to gallery root, then the upload is not moderated. For example, if the
545  // user is allowed to upload to events/parties with no admin moderation,
546  // then he's not moderated when uploading in
547  // events/parties/happyNewYear2011
548  $moderate = true;
549
550  $user_permissions = community_get_user_permissions($user['id']);
551  $query = '
552SELECT
553    cp.category_id,
554    c.uppercats
555  FROM '.COMMUNITY_PERMISSIONS_TABLE.' AS cp
556    LEFT JOIN '.CATEGORIES_TABLE.' AS c ON category_id = c.id
557  WHERE cp.id IN ('.implode(',', $user_permissions['permission_ids']).')
558    AND cp.moderated = \'false\'
559;';
560  $result = pwg_query($query);
561  while ($row = pwg_db_fetch_assoc($result))
562  {
563    if (empty($row['category_id']))
564    {
565      $moderate = false;
566    }
567    elseif (preg_match('/^'.$row['uppercats'].'(,|$)/', $category_infos['uppercats']))
568    {
569      $moderate = false;
570    }
571  }
572 
573  if ($moderate)
574  {
575    $inserts = array();
576
577    $query = '
578SELECT
579    id,
580    date_available
581  FROM '.IMAGES_TABLE.'
582  WHERE id IN ('.implode(',', $image_ids).')
583;';
584    $result = pwg_query($query);
585    while ($row = pwg_db_fetch_assoc($result))
586    {
587      array_push(
588        $inserts,
589        array(
590          'image_id' => $row['id'],
591          'added_on' => $row['date_available'],
592          'state' => 'moderation_pending',
593          )
594        );
595    }
596   
597    mass_inserts(
598      COMMUNITY_PENDINGS_TABLE,
599      array_keys($inserts[0]),
600      $inserts
601      );
602   
603    // the level of a user upload photo with moderation is 16
604    $level = 16;
605  }
606  else
607  {
608    // the level of a user upload photo with no moderation is 0
609    $level = 0;
610  }
611
612  $query = '
613UPDATE '.IMAGES_TABLE.'
614  SET level = '.$level.'
615  WHERE id IN ('.implode(',', $image_ids).')
616;';
617  pwg_query($query);
618
619  invalidate_user_cache();
620}
621
622add_event_handler('delete_user', 'community_delete_user');
623function community_delete_user($user_id)
624{
625  $query = '
626DELETE
627  FROM '.COMMUNITY_PERMISSIONS_TABLE.'
628  WHERE user_id = '.$user_id.'
629;';
630  pwg_query($query);
631
632  community_reject_user_pendings($user_id);
633}
634
635add_event_handler('delete_categories', 'community_delete_category');
636function community_delete_category($category_ids)
637{
638  // $category_ids includes all the sub-category ids
639  $query = '
640DELETE
641  FROM '.COMMUNITY_PERMISSIONS_TABLE.'
642  WHERE category_id IN ('.implode(',', $category_ids).')
643;';
644  pwg_query($query);
645 
646  community_update_cache_key();
647}
648
649add_event_handler('delete_elements', 'community_delete_elements');
650function community_delete_elements($image_ids)
651{
652  $query = '
653DELETE
654  FROM '.COMMUNITY_PENDINGS_TABLE.'
655  WHERE image_id IN ('.implode(',', $image_ids).')
656;';
657  pwg_query($query);
658}
659
660add_event_handler('invalidate_user_cache', 'community_refresh_cache_update_time');
661function community_refresh_cache_update_time()
662{
663  community_update_cache_key();
664}
665
666add_event_handler('init', 'community_uploadify_privacy_level');
667function community_uploadify_privacy_level()
668{
669  if (script_basename() == 'uploadify' and !is_admin())
670  {
671    $_POST['level'] = 16;
672  }
673}
674
675// +-----------------------------------------------------------------------+
676// | User Albums                                                           |
677// +-----------------------------------------------------------------------+
678
679add_event_handler('loc_end_cat_modify', 'community_set_prefilter_cat_modify', 50);
680// add_event_handler('loc_begin_admin_page', 'community_cat_modify_submit', 45);
681
682// Change the variables used by the function that changes the template
683// add_event_handler('loc_begin_admin_page', 'community_cat_modify_add_vars_to_template');
684
685function community_set_prefilter_cat_modify()
686{
687        global $template, $conf, $category;
688
689  if (!isset($conf['community']['user_albums']) or !$conf['community']['user_albums'])
690  {
691    return;
692  }
693 
694  $template->set_prefilter('album_properties', 'community_cat_modify_prefilter');
695
696  $query = '
697SELECT
698    '.$conf['user_fields']['id'].' AS id,
699    '.$conf['user_fields']['username'].' AS username
700  FROM '.USERS_TABLE.' AS u
701    INNER JOIN '.USER_INFOS_TABLE.' AS uf ON uf.user_id = u.'.$conf['user_fields']['id'].'
702  WHERE uf.status IN (\'normal\',\'generic\')
703;';
704  $result = pwg_query($query);
705  $users = array();
706  while ($row = pwg_db_fetch_assoc($result))
707  {
708    $users[$row['id']] = $row['username'];
709  }
710
711  $template->assign(
712    array(
713      'community_user_options' => $users,
714      'community_user_selected' => $category['community_user'],
715      )
716    );
717}
718
719function community_cat_modify_prefilter($content, &$smarty)
720{
721        $search = "#<strong>{'Name'#";
722
723        // We use the <tr> from the Creation date, and give them a new <tr>
724        $replacement = '<strong>(Community) {\'Album of user\'|@translate}</strong>
725                <br>
726                        <select name="community_user">
727                                <option value="">--</option>
728                                {html_options options=$community_user_options selected=$community_user_selected}
729                        </select>
730      <em>{\'a user can own only one album\'|@translate}</em>
731                </p>
732       
733        </p>
734  <p>
735                <strong>{\'Name\'';
736
737  return preg_replace($search, $replacement, $content);
738}
739
740add_event_handler('loc_begin_cat_modify', 'community_cat_modify_submit');
741function community_cat_modify_submit()
742{
743  global $category, $conf;
744
745  if (!isset($conf['community']['user_albums']) or !$conf['community']['user_albums'])
746  {
747    return;
748  }
749 
750  if (isset($_POST['community_user']))
751  {
752    // echo '<pre>'; print_r($_POST); echo '</pre>'; exit();
753    // only one album for each user, first we remove ownership on any other album
754    single_update(
755      CATEGORIES_TABLE,
756      array('community_user' => null),
757      array('community_user' => $_POST['community_user'])
758      );
759
760    // then we give the album to the user
761    single_update(
762      CATEGORIES_TABLE,
763      array('community_user' => $_POST['community_user']),
764      array('id' => $category['id'])
765      );
766  }
767}
768?>
Note: See TracBrowser for help on using the repository browser.