# Copyright (c) 2001-2010 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: SQL.pm,v 1.71 2011/03/11 20:23:34 nagler Exp $ package Bivio::PetShop::Util::SQL; use strict; use Bivio::Base 'ShellUtil'; # export BCONF=~/bconf/petshop.bconf # cd files/ddl # perl -w ../../b-petshop init_dbms # perl -w ../../b-petshop create_test_db our($VERSION) = sprintf('%d.%02d', q$Revision: 1.71 $ =~ /\d+/g); my($_DT) = b_use('Type.DateTime'); my($_R) = b_use('Auth.Role'); my($_AR) = b_use('Auth.Realm'); my($_S) = b_use('Type.String'); my($_F) = b_use('IO.File'); my($_WN) = b_use('Type.WikiName'); my($_WDN) = b_use('Type.WikiDataName'); my($_SN) = b_use('Type.SettingsName'); sub BTEST_ADMIN { return 'btest_admin'; } sub BTEST_READ { return 'btest_read'; } sub CRM_CLIENT { return 'crm_client' . $_[1]; } sub CRM_FORUM { return 'crm_forum'; } sub CRM_TUPLE_FORUM { return 'crm_tuple_forum'; } sub CRM_TECH { return 'crm_tech' . $_[1]; } sub DEMO { return 'demo'; } sub DEMO_EMAIL { my($proto) = @_; return $proto->format_email($proto->DEMO); } sub DEMO_LAST_NAME { return 'User'; } sub FOUREM { return 'fourem'; } sub GUEST { return 'guest'; } sub MAIL_FORUM { return 'mail_forum'; } sub MAIL_FORUM_PUBLIC { return 'mail_forum_public'; } sub MAIL_FORUM_ALLOW_PUBLIC { return 'mail_forum_allow_public'; } sub MAIL_USER { return 'mail_user' . $_[1]; } sub MULTI_ROLE_USER { return 'multi_role_user'; } sub OTP { return 'otp'; } sub PASSWORD { return 'password'; } sub ROOT { return b_use('ShellUtil.TestUser')->ADM; } sub ROOT_EMAIL { my($proto) = @_; return $proto->format_email($proto->ROOT); } sub TUPLE_FORUM { return 'tuple_forum'; } sub TUPLE_USER { return 'tuple_user'; } sub SITE_ADM { return 'site_adm'; } sub SITE_ACCOUNTANT { return 'site_accountant'; } sub USAGE { return shift->SUPER::USAGE . <<'EOF'; demo_users -- lists demo user names demo_all_tuples -- clears tuple table in realm EOF } sub XAPIAN_DEMO { return 'xapian_demo'; } sub XAPIAN_GUEST { return 'xapian_guest'; } sub XAPIAN_WITHDRAWN { return 'xapian_withdrawn'; } sub create_user_with_account { my($self, $user) = @_; $self->model('UserAccountForm', { 'User.first_name' => ucfirst($user), 'User.last_name' => $self->DEMO_LAST_NAME, 'Email.email' => $self->format_email($user), 'Address.street1' => '1313 Mockingbird Lane', 'Address.street2' => undef, 'Address.city' => 'Boulder', 'Address.state' => 'CO', 'Address.zip' => '80304', 'Address.country' => 'US', 'Phone.phone' => '555-1212', 'RealmOwner.password' => $self->PASSWORD, force_create => 1, }); # test accounts have real names, for ease of logging in $self->req->get('auth_user')->update({ name => $user, display_name => join(' ', ucfirst($user), $self->DEMO_LAST_NAME), }); return $self->req('auth_user_id'); } sub ddl_files { return [map { my($base) = $_; map { $base.'-'.$_.'.sql'; } qw(tables constraints sequences); } qw(bOP petshop)]; } sub delete_all_tuples { my($self) = @_; my($req) = $self->initialize_ui; $self->model('Tuple')->delete_all; return; } sub demo_users { my($self) = @_; return [ map($self->$_(), qw(ROOT DEMO GUEST XAPIAN_DEMO XAPIAN_GUEST XAPIAN_WITHDRAWN MULTI_ROLE_USER BTEST_ADMIN BTEST_READ OTP), ), ]; } sub format_email { return shift->format_test_email(@_); } sub initialize_db { my($self) = shift; my(@res) = $self->SUPER::initialize_db(@_); $self->new_other('SiteForum')->init; return @res; } sub initialize_test_data { my($self) = @_; _init_site_admin($self); _init_demo_categories($self); _init_demo_products($self); _init_demo_items($self); _init_demo_users($self); _init_demo_files($self); _init_forum($self); _init_email_alias($self); _init_tuple($self); _init_logo($self); _init_default_tuple($self); _init_mail($self); $self->new_other('TestCRM')->init; $self->new_other('TestData')->init; _init_remote_copy($self); _init_task_log($self); _init_bulletin($self); _init_motion($self); $self->new_other('RealmUser')->audit_all_users; return; } sub internal_realm_role_config_data { return __PACKAGE__->internal_data_section; } sub internal_upgrade_db { my($self) = @_; # Add time_zone field to CalendarEvent table $self->run(<<'EOF'); ALTER TABLE calendar_event_t ADD time_zone NUMERIC(4) ; EOF return; } sub realm_file_create { my($self, $path, $content) = @_; return $self->model('RealmFile')->create_or_update_with_content( {path => $path}, ref($content) ? $content : \$content); } sub top_level_forum { my($self, $name, $admins, $users) = @_; $self->req->set_realm(undef); $self->model(ForumForm => { 'RealmOwner.display_name' => $_S->to_camel_case($name), 'RealmOwner.name' => $name, mail_want_reply_to => 1, }); my($rid) = $self->req('auth_id'); $self->model('ForumUserDeleteForm', { 'RealmUser.realm_id' => $rid, 'User.user_id' => _realm_id($self, $self->ROOT), }); foreach my $user (@$admins, @$users) { $self->model('ForumUserAddForm', { 'RealmUser.realm_id' => $rid, 'User.user_id' => _realm_id($self, $user), administrator => grep($user eq $_, @$admins) ? 1 : 0, }); } return; } sub _init_bulletin { my($self) = @_; $self->new_other('SiteForum')->init_bulletin('bulletin'); $self->model('ForumUserAddForm', { 'RealmUser.realm_id' => _realm_id($self, 'bulletin'), 'User.user_id' => _realm_id($self, 'bulletin_user'), }); return; } sub _init_default_tuple { my($self) = @_; my($req) = $self->req; $self->top_level_forum($self->TUPLE_FORUM, [$self->TUPLE_USER], []); $self->model('TupleSlotType')->create_from_hash({ Status => { type_class => 'TupleSlot', choices => [qw(Open Closed New)], default_value => 'New', }, }); $self->model('TupleDef')->create_from_hash({ 'req#Requests' => [ { label => 'Title', type => 'String', }, { label => 'Status', type => 'Status', }, ], }); $self->model('TupleUse')->create_from_label('Requests'); $self->model('RowTag')->create_value( $req->get('auth_id'), 'DEFAULT_TUPLE_MONIKER', 'req'); return; } sub _init_demo_categories { my($self) = @_; # Initializes Model.Category. my($model) = Bivio::Biz::Model->new($self->get_request, 'Category'); foreach my $enum (b_use('Type.Category')->get_list) { # Don't create the '0' (UNKNOWN) case next if $enum->as_int == 0; $model->create({ category_id => $enum->get_name, name => $enum->get_short_desc, description => $enum->get_long_desc, }); } return; } sub _init_demo_files { my($self) = @_; my($req) = $self->get_request; Bivio::IO::File->chdir( Bivio::IO::File->mkdir_p(Bivio::IO::File->rm_rf( my $d = File::Spec->rel2abs('demo_files.tmp')))); foreach my $x ( ['Public/file.txt' => 'text/plain'], ['private/file.html' => '
text/html'], ['private/image.gif' => 'image/gif'], ) { my($f, $c) = @$x; Bivio::IO::File->mkdir_parent_only($f); Bivio::IO::File->write($f, $c); } foreach my $u (qw(DEMO XAPIAN_DEMO GUEST XAPIAN_GUEST BTEST_READ)) { $self->set_realm_and_user($self->$u(), $self->$u()); $self->new_other('Bivio::Util::RealmFile')->import_tree(''); Bivio::Biz::Model->new('RealmFile')->do_iterate( sub { my($f) = @_; $f->update({is_public => 1}) if $f->get('path') =~ /public/i; return 1; }, 'path', ); } Bivio::IO::File->chdir('..'); return; } sub _init_demo_items { my($self) = @_; # Init Model.Item and Model.inventory. foreach my $record (@{$self->new_other('CSV')->parse_records(<<'EOF')}) { item_id,product_id,list_price,unit_cost,attr1 EST-1,FI-SW-01,16.5,10,Large EST-2,FI-SW-01,16.5,10,Small EST-3,FI-SW-02,18.5,12,Toothless EST-4,FI-FW-01,18.5,12,Spotted EST-5,FI-FW-01,18.5,12,Spotless EST-6,K9-BD-01,18.5,12,Male Adult EST-7,K9-BD-01,18.5,12,Female Puppy EST-8,K9-PO-02,18.5,12,Male Puppy EST-9,K9-DL-01,18.5,12,Spotless Male Puppy EST-10,K9-DL-01,18.5,12,Spotted Adult Female EST-11,RP-SN-01,18.5,12,Venomless EST-12,RP-SN-01,18.5,12,Rattleless EST-13,RP-LI-02,18.5,12,Green Adult EST-14,FL-DSH-01,58.5,12,Tailless EST-15,FL-DSH-01,23.5,12,With tail EST-16,FL-DLH-02,93.5,12,Adult Female EST-17,FL-DLH-02,93.5,12,Adult Male EST-18,AV-CB-01,193.5,92,Adult Male EST-19,AV-SB-02,15.5,2,Adult Male EST-20,FI-FW-02,5.5,2,Adult Male EST-21,FI-FW-02,5.29,1,Adult Female EST-22,K9-RT-01,135.5,100,Adult Male EST-23,K9-RT-01,145.49,100,Adult Female EST-24,K9-RT-02,255.5,92,Adult Male EST-25,K9-RT-02,325.29,90,Adult Female EOF $self->model('Inventory')->create({ item_id => $self->model('Item')->create($record)->get('item_id'), quantity => 10_000, }); } return; } sub _init_demo_products { my($self) = @_; # Initializes Model.Product. foreach my $record (@{$self->new_other('CSV')->parse_records(<<'EOF')}) { product_id,category_id,name,image_name,description FI-SW-01,FISH,Angelfish,angelfish,Salt Water fish from Australia FI-SW-02,FISH,Tiger Shark,tigershark,Salt Water fish from Australia FI-FW-01,FISH,Koi,koi,Fresh Water fish from Japan FI-FW-02,FISH,Goldfish,reeffish,Fresh Water fish from China K9-BD-01,DOGS,Corgi,corgi,Friendly dog from Wales K9-PO-02,DOGS,Poodle,poodle,Cute dog from France K9-DL-01,DOGS,Dalmation,dalmation,Great dog for a Fire Station K9-RT-01,DOGS,German Shepherd,shepherd,Great family dog K9-RT-02,DOGS,Labrador Retriever,lab,Great hunting dog RP-SN-01,REPTILES,Rattlesnake,rattlesnake,Doubles as a watch dog RP-LI-02,REPTILES,Iguana,iguana,Friendly green friend FL-DSH-01,CATS,Manx,manx,Great for reducing mouse populations FL-DLH-02,CATS,Persian,persian,Friendly house cat, doubles as a princess AV-CB-01,BIRDS,Amazon Parrot,parrot,Great companion for up to 75 years AV-SB-02,BIRDS,Finch,finch,Great stress reliever EOF $self->model('Product')->create($record); } return; } sub _init_demo_users { my($self) = @_; my($req) = $self->get_request; my($demo_id); foreach my $u (@{$self->demo_users()}) { next if $u eq $self->ROOT; $self->create_user_with_account($u); $req->with_realm($self->DEMO, sub { $self->new_other('RealmRole')->edit_categories('+feature_file'); return; }); my($uid) = $req->get('auth_user_id'); if ($u eq $self->DEMO || $u eq $self->XAPIAN_DEMO) { $demo_id = $uid; } elsif ($u eq $self->GUEST || $u eq $self->XAPIAN_GUEST) { Bivio::Biz::Model->new($req, 'RealmUser')->create({ realm_id => $demo_id || die('DEMO must come before GUEST'), user_id => $uid, role => $_R->GUEST, }); } elsif ($u eq $self->XAPIAN_WITHDRAWN) { Bivio::Biz::Model->new($req, 'RealmUser')->create({ realm_id => $demo_id || die('DEMO must come before GUEST'), user_id => $uid, role => $_R->WITHDRAWN, }); } elsif ($u eq $self->MULTI_ROLE_USER) { Bivio::Biz::Model->new($req, 'RealmUser')->create({ realm_id => $_AR->get_general->get('id'), user_id => $uid, role => $_R->TEST_ROLE1, }); Bivio::Biz::Model->new($req, 'RealmUser')->create({ realm_id => $_AR->get_general->get('id'), user_id => $uid, role => $_R->TEST_ROLE2, }); } elsif ($u eq $self->OTP) { $self->new_other('OTP')->reset_user; } } $self->create_test_user( b_use('TestLanguage.HTTP')->generate_remote_email('support')); $self->create_test_user('invalidated_user'); $req->get('auth_user')->invalidate_password; return; } sub _init_email_alias { my($self) = @_; my($req) = $self->get_request; foreach my $x ( [qw(demo-alias demo)], [qw(fourem-alias fourem)], [qw(random-alias random@example.com)], ) { $self->model('EmailAlias')->create({ incoming => $self->format_test_email($x->[0]), outgoing => $x->[1], }); } $self->model('EmailAlias')->create({ incoming => '@in.bunit', outgoing => '@out.bunit', }); return; } sub _init_forum { my($self) = @_; my($req) = $self->get_request; $req->set_realm(undef); $req->set_user($self->ROOT); $self->model('ForumForm', { 'RealmOwner.display_name' => 'RealmFile2', 'RealmOwner.name' => 'realmfile2', }); $req->set_realm(undef); $self->model('ForumForm', { 'RealmOwner.display_name' => 'Unit Test Forum', 'RealmOwner.name' => $self->FOUREM, }); # Must agree with easy-form.btest (or test will fail) $self->realm_file_create('Public/EasyForm-btest.html', <<'EOF'); EOF $self->realm_file_create('Public/EasyForm-btest-done.html', <<'EOF'); completed EOF $self->realm_file_create($_WN->to_absolute('EasyForm_btest', 1), <<'EOF'); @form method=POST action=/fourem/Forms/btest?goto=/fourem/bp/EasyForm_btest_done @table @tr @td Input: @td @input type=text name=input @/td @/tr @tr @td @input type=submit name=ok value=OK @/td @/tr @/table @/form EOF $self->realm_file_create( $_WN->to_absolute('EasyForm_btest_done', 1), <<'EOF'); wiki completed EOF $self->realm_file_create('Forms/btest.csv', <<'EOF'); &client_addr,&date,&email,input,ok EOF $self->realm_file_create($_WN->to_absolute('PublicPage', 1), <<'EOF'); @h1 My Public Header My Public Page EOF $self->realm_file_create($_WN->to_absolute('PrivatePage'), <<'EOF'); My Example Page. EOF $self->realm_file_create(b_use('Type.BlogFileName')->to_absolute('20071225000000', 1), <<'EOF'); @h1 Merry Xmas Ho, ho, ho! EOF $self->realm_file_create($_SN->to_absolute('RealmSettingList1.csv'), <<'EOF'); Name,Number,Letter,Lesson,Other alpha,1,a,arithmetic,