# Copyright (c) 2006-2011 bivio Software, Inc. All Rights Reserved. # # Visit http://www.bivio.biz for more info. # # This library is free software; you can redistribute it and/or modify # it under the terms of the GNU Lesser General Public License as # published by the Free Software Foundation; either version 2.1 of the # License, or (at your option) any later version. # # This library is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public # License along with this library; If not, you may get a copy from: # http://www.opensource.org/licenses/lgpl-license.html # # $Id: SearchList.pm,v 1.32 2011/02/06 21:55:38 nagler Exp $ package Bivio::Biz::Model::SearchList; use strict; use Bivio::Base 'Biz.ListModel'; our($VERSION) = sprintf('%d.%02d', q$Revision: 1.32 $ =~ /\d+/g); my($_MTL) = b_use('Model.MailThreadList'); my($_BFN) = b_use('Type.BlogFileName'); my($_MFN) = b_use('Type.MailFileName'); my($_TS) = b_use('Type.String'); my($_WDN) = b_use('Type.WikiDataName'); my($_WN) = b_use('Type.WikiName'); my($_S) = b_use('Bivio.Search'); my($_REALM_FILE_FIELDS) = [qw( realm_file_id path path_lc realm_id modified_date_time is_public is_read_only user_id )]; my($_REALM_OWNER_FIELDS) = [qw( name display_name realm_type )]; my($_FP) = b_use('Type.FilePath'); my($_R) = b_use('Auth.Realm'); my($_IDI) = __PACKAGE__->instance_data_index; sub format_uri_params_with_row { my($self, $row) = @_; my($req) = $self->req; # Order needs to be clear. Possibly by registration order or dependencies? return $_BFN->is_absolute($row->{'RealmFile.path'}) ? { # What if I removed realm from the task? What would happen? task_id => 'FORUM_BLOG_DETAIL', realm => $row->{'RealmOwner.name'}, query => undef, path_info => $_BFN->from_absolute($row->{'RealmFile.path'}), } : $_WN->is_absolute($row->{'RealmFile.path'}) ? $_WN->uri_hash_for_realm_and_path( $row->{'RealmOwner.name'}, $row->{'RealmFile.path'}) : $_WDN->is_absolute($row->{'RealmFile.path'}) ? $_WDN->uri_hash_for_realm_and_path( $row->{'RealmOwner.name'}, $row->{'RealmFile.path'}) : $_MFN->is_absolute($row->{'RealmFile.path'}) ? $req->with_realm( $row->{'RealmOwner.name'}, sub { my($crm) = $req->get('auth_realm') ->does_user_have_permissions(['FEATURE_CRM'], $req); my($realm_mail) = $self->new_other('RealmMail')->load({ realm_file_id => $row->{'RealmFile.realm_file_id'}}); my($pid) = $realm_mail->get('thread_root_id'); #TODO: Is this necessary now that we're caching? # $row->{result_title} = $realm_mail->get('subject'); if ($crm) { my($m) = $self->new_other('CRMThread'); # Remote possibility that the message isn't a CRMThread # due to switchover after realm had mail. $pid = $m->get('crm_thread_num') if $m->unsafe_load({thread_root_id => $pid}); } return { task_id => $crm ? 'FORUM_CRM_THREAD_LIST' : 'FORUM_MAIL_THREAD_LIST', realm => $row->{'RealmOwner.name'}, query => {'ListQuery.parent_id' => $pid}, #TODO: Integrate with View.Mail->internal_part_list (need ) anchor => $_MTL->get_message_anchor($row->{'RealmFile.realm_file_id'}), }; }, ) : { task_id => 'FORUM_FILE', realm => $row->{'RealmOwner.name'}, query => undef, path_info => $row->{'RealmFile.path'}, }; } sub internal_initialize { my($self) = @_; return $_S->query_list_model_initialize( $self, $self->merge_initialize_info($self->SUPER::internal_initialize, { other => [ $self->field_decl( [ qw( result_uri result_title result_excerpt result_author result_realm_uri ), [qw(show_byline Boolean)], ], 'Text', 'NOT_NULL', ), $self->field_decl( [map("RealmOwner.$_", @$_REALM_OWNER_FIELDS)], {in_select => 0}, ), { name => 'model', constraint => 'NOT_NULL', type => 'Biz.PropertyModel', }, ], other_query_keys => [qw(b_realm_only)], }), ); } sub internal_load_rows { my($self, $query) = @_; my($s, $pn, $c) = $query->unsafe_get(qw(search page_number count)); return [] unless defined(($_TS->from_literal($s))[0]); my($x) = _b_realm_only($self, $query); $self->[$_IDI] = {map(($_ => 1), @{$x->{private_realm_ids}})}; my($rows) = $_S->query({ phrase => $s, offset => ($pn - 1) * $c, length => $c + 1, req => $self->req, %$x, }); if (@$rows > $c) { $query->put( has_next => 1, next_page => $pn + 1, ); pop(@$rows); }; $query->put( has_prev => 1, prev_page => $pn - 1, ) if $pn > $query->FIRST_PAGE; return $rows; } sub internal_post_load_row { my($self, $row) = @_; return 0 unless $self->load_row_with_model($row, $row->{model}); $row->{show_byline} = $self->[$_IDI]->{$row->{'RealmOwner.realm_id'}} || 0; return 1; } sub internal_post_load_row_with_model { Bivio::IO::Alert->warn_deprecated('use load_row_with_model'); return shift->load_row_with_model(@_); } sub internal_private_realm_ids { my($self, $query) = @_; my($req) = $self->req; return $req->map_user_realms( sub { my($rid) = shift->{'RealmUser.realm_id'}; #TODO-SECURITY: This needs to be more selective return $_R->new($rid, $req) ->does_user_have_permissions(['DATA_READ'], $req) ? $rid : (); }, ); } sub internal_public_realm_ids { return []; } sub internal_want_all_public { return 1; } sub load_row_with_model { my($self, $row, $model) = @_; foreach my $f (@$_REALM_FILE_FIELDS) { $row->{"RealmFile.$f"} = $model->get($f); } #TODO: realm_ids are a security issue. Need to cache the realms, and then # verify they are here. Can save the info above in # internal_get_realm_ids #TODO: Optimize by caching realms my($ro) = $model->new_other('RealmOwner') ->unauth_load_or_die({realm_id => $model->get_auth_id}); foreach my $f (@$_REALM_OWNER_FIELDS) { $row->{"RealmOwner.$f"} = $ro->get($f); } $row->{result_realm_uri} = $ro->format_uri; $row->{result_title} = length($row->{title}) ? $row->{title} : $_FP->get_tail($model->unsafe_get('path') || ''); $row->{result_author} = length($row->{author}) ? $row->{author} : $ro->unauth_load_or_die({realm_id => $row->{'RealmFile.user_id'}}) ->get('display_name'); $row->{result_excerpt} = length($row->{excerpt}) ? $row->{excerpt} : ''; $row->{result_uri} = $self->req->format_uri( $self->format_uri_params_with_row($row)); return 1; } sub _b_realm_only { my($self, $query) = @_; return { private_realm_ids => $self->internal_private_realm_ids($query), public_realm_ids => $self->internal_public_realm_ids($query), want_all_public => $self->internal_want_all_public($query), } unless $query->unsafe_get('b_realm_only'); my($aid) = $self->req('auth_id'); return { private_realm_ids => [grep($aid eq $_, @{$self->internal_private_realm_ids($query)})], public_realm_ids => [$aid], want_all_public => 0, }; } 1;