- # This row is owned by a member of users_list, or owned by a group
- # readable by a member of users_list
- # or
- # This row uuid is the uuid of a member of users_list
- # or
- # A permission link exists ('write' and 'manage' implicitly include
- # 'read') from a member of users_list, or a group readable by users_list,
- # to this row, or to the owner of this row (see join() below).
- sql_conds += ["#{sql_table}.uuid in (?)"]
- sql_params += [user_uuids]
+ exclude_trashed_records = ""
+ if !include_trash and (sql_table == "groups" or sql_table == "collections") then
+ # Only include records that are not explicitly trashed
+ exclude_trashed_records = "AND #{sql_table}.is_trashed = false"
+ end
+
+ if users_list.select { |u| u.is_admin }.any?
+ # Admin skips most permission checks, but still want to filter on trashed items.
+ if !include_trash
+ if sql_table != "api_client_authorizations"
+ # Only include records where the owner is not trashed
+ sql_conds = "#{sql_table}.owner_uuid NOT IN (SELECT target_uuid FROM #{PERMISSION_VIEW} "+
+ "WHERE trashed = 1) #{exclude_trashed_records}"
+ end
+ end
+ else
+ trashed_check = ""
+ if !include_trash then
+ trashed_check = "AND trashed = 0"
+ end
+
+ # Note: it is possible to combine the direct_check and
+ # owner_check into a single EXISTS() clause, however it turns
+ # out query optimizer doesn't like it and forces a sequential
+ # table scan. Constructing the query with separate EXISTS()
+ # clauses enables it to use the index.
+ #
+ # see issue 13208 for details.
+
+ # Match a direct read permission link from the user to the record uuid
+ direct_check = "#{sql_table}.uuid IN (SELECT target_uuid FROM #{PERMISSION_VIEW} "+
+ "WHERE user_uuid IN (:user_uuids) AND perm_level >= 1 #{trashed_check})"
+
+ # Match a read permission link from the user to the record's owner_uuid
+ owner_check = ""
+ if sql_table != "api_client_authorizations" and sql_table != "groups" then
+ owner_check = "OR #{sql_table}.owner_uuid IN (SELECT target_uuid FROM #{PERMISSION_VIEW} "+
+ "WHERE user_uuid IN (:user_uuids) AND perm_level >= 1 #{trashed_check} AND target_owner_uuid IS NOT NULL) "
+ end
+
+ links_cond = ""
+ if sql_table == "links"
+ # Match any permission link that gives one of the authorized
+ # users some permission _or_ gives anyone else permission to
+ # view one of the authorized users.
+ links_cond = "OR (#{sql_table}.link_class IN (:permission_link_classes) AND "+
+ "(#{sql_table}.head_uuid IN (:user_uuids) OR #{sql_table}.tail_uuid IN (:user_uuids)))"
+ end