diff --git a/webtools/litmus/Litmus.pm b/webtools/litmus/Litmus.pm index 7d58bc63a69..9ff13799a66 100755 --- a/webtools/litmus/Litmus.pm +++ b/webtools/litmus/Litmus.pm @@ -30,8 +30,7 @@ =cut -# Persistant object store for various objects used by -# different modules within Litmus +# Global object store and function library for Litmus package Litmus; @@ -39,15 +38,19 @@ use strict; use Litmus::Template; use Litmus::Config; -use CGI; +use Litmus::Auth; +use Litmus::CGI; -if ($Litmus::Config::disabled) { - my $c = new CGI(); - print $c->header(); - print "Litmus has been shutdown by the administrator. Please try again later."; - exit; +BEGIN { + if ($Litmus::Config::disabled) { + my $c = new CGI(); + print $c->header(); + print "Litmus has been shutdown by the administrator. Please try again later."; + exit; + } } +# Global Template object my $_template; sub template() { my $class = shift; @@ -55,4 +58,20 @@ sub template() { return $_template; } +# Global CGI object +my $_cgi; +sub cgi() { + my $class = shift; + $_cgi ||= Litmus::CGI->new(); + return $_cgi; +} + +# hook to handle a login in progress for any CGI script: +BEGIN { + my $c = cgi(); + if ($c->param("login_type")) { + Litmus::Auth::processLoginForm(); + } +} + 1; diff --git a/webtools/litmus/Litmus/Auth.pm b/webtools/litmus/Litmus/Auth.pm index 25c5c7cedad..dfa82bff62c 100755 --- a/webtools/litmus/Litmus/Auth.pm +++ b/webtools/litmus/Litmus/Auth.pm @@ -34,10 +34,17 @@ package Litmus::Auth; use strict; +# IMPORTANT! +## You _must_ call Litmus::Auth methods before sending a Content-type +## header so that any required cookies can be sent. + require Exporter; use Litmus; use Litmus::DB::User; use Litmus::Error; +use Litmus::Template; +use Time::Piece; +use Time::Seconds; use CGI; @@ -45,8 +52,10 @@ our @ISA = qw(Exporter); our @EXPORT = qw(); my $logincookiename = $Litmus::Config::user_cookiename; +my $cookie_expire_days = 7; + +my $curSession; -# (XXX) stub # Given a username and password, validate the login. Returns the # Lutmus::DB::User object associated with the username if the login # is sucuessful. Returns false otherwise. @@ -54,16 +63,270 @@ sub validate_login($$) { my $username = shift; my $password = shift; - # we'll fill this in later once we actually _have_ passwords. - # for now, just return the user object or false: my @usrobjs = Litmus::DB::User->search(email => $username); - if (@usrobjs) { - return $usrobjs[0]; + my $userobj = $usrobjs[0]; + + if (!$userobj) { return 0; } + + if ($userobj->disabled() && $userobj->disabled() == 1) { + die "account ".$userobj->username()." has been disabled by + the administrator"; + } + + # for security reasons, we use the real (correct) crypt'd passwd + # as the salt: + my $realPasswordCrypted = $userobj->getRealPasswd(); + my $enteredPasswordCrypted = crypt($password, $realPasswordCrypted); + if ($enteredPasswordCrypted eq $enteredPasswordCrypted) { + return $userobj; } else { return 0; } } +# Used by a CGI when a login is required to proceed beyond a certain point. +# requireLogin() will return a Litmus::User object to indicate that the user +# is logged in, or it will redirect to a login page to allow the login to be +# completed. Once the login is complete, the user will be redirected back to +# $return_to and any parameters in the current CGI.pm object will be passed +# to the new script. +# +sub requireLogin { + my $return_to = shift; + my $cgi = Litmus->cgi(); + + # see if we are already logged in: + my $user = getCurrentUser(); + return $user if $user; # well, that was easy... + + my $vars = { + return_to => $return_to, + params => $cgi, + }; + + print $cgi->header(); + Litmus->template()->process("auth/login.html.tmpl", $vars) || + internalError(Litmus->template()->error()); + + exit; +} + +# Used by a CGI in much the same way as requireLogin() when the user must +# be an admin to proceed. +sub requireAdmin { + my $return_to = shift; + my $cgi = Litmus->cgi(); + + my $user = requireLogin(); + if (!$user || !$user->is_admin()) { + basicError("You must be a Litmus administrator to perform this function."); + } + return $user; +} + +# Returns the Litmus::User object corresponding to the current logged-in +# user, or 0 if no valid login cookie exists +sub getCurrentUser() { + my $c = Litmus->cgi(); + + # we're actually processing the login form right now, so the cookie hasn't + # been sent yet... + if ($curSession) { return $curSession->user_id() } + + my $sessionCookie = $c->cookie($logincookiename); + if (! $sessionCookie) { return 0 } + + + my @sessions = Litmus::DB::Session->search(sessioncookie => $sessionCookie); + my $session = $sessions[0]; + if (! $session) { return 0 } + + # see if it's still valid and that the user hasn't been disabled + if (! $session->isValid()) { return 0 } + + return $session->user_id(); +} + +# +# ONLY NON-PUBLIC API BEYOND THIS POINT +# + +# Processes data from a login form (auth/login.html.tmpl) using data +# from the current Litmus::CGI object in use. When complete, returns the +# flow of control to the script the user wanted to reach before the login, +# setting a login cookie for the user. +sub processLoginForm { + my $c = Litmus->cgi(); + + my $type = $c->param("login_type"); + + if ($c->param("accountCreated") && + $c->param("accountCreated") eq "true") { + # make sure they really are logged in and didn't just set + # the accountCreated flag: + requireLogin("index.cgi"); + return; # we're done here + } + + if ($type eq "litmus") { + my $username = $c->param("email"); + my $password = $c->param("password"); + + my $user = validate_login($username, $password); + + if (!$user) { + loginError($c, "Username/Password incorrect. Please try again."); + } + + my $session = makeSession($user); + $c->storeCookie(makeCookie($session)); + + } elsif ($type eq "newaccount") { + my $email = $c->param("email"); + my $name = $c->param("realname"); + my $password = $c->param("password"); + + # some basic form-field validation: + my $emailregexp = q:^[\\w\\.\\+\\-=]+@[\\w\\.\\-]+\\.[\\w\\-]+$:; + if (! $email || ! $email =~ /$emailregexp/) { + loginError($c, "You must enter a valid email address"); + } + if (! $password eq $c->param("password_confirm")) { + loginError($c, "Passwords do not match. Please try again."); + } + if (! $name || $name eq "") { + loginError($c, "You must enter your real name (or a pseudonym) to identify yourself"); + } + my @users = Litmus::DB::User->search(email => $email); + if ($users[0]) { + loginError($c, "User ".$users[0]->email() ." already exists. Please try again."); + } + + my $userobj = + Litmus::DB::User->create({email => $email, + password => bz_crypt($password), + realname => $name, + disabled => 0, + is_admin => 0}); + + my $session = makeSession($userobj); + $c->storeCookie(makeCookie($session)); + + my $vars = { + email => $email, + realname => $name, + return_to => $c->param("login_loc"), + params => $c + }; + + print $c->header(); + Litmus->template()->process("auth/accountcreated.html.tmpl", $vars) || + internalError(Litmus->template()->error()); + + exit; + + } elsif ($type eq "bugzilla") { + my $username = $c->param("username"); + my $password = $c->param("password"); + + + } else { + internalError("Unknown login scheme attempted"); + } +} + +# Given a userobj, process the login and return a session cookie +sub makeSession { + my $userobj = shift; + my $c = Litmus->cgi(); + + my $expires = localtime() + ONE_DAY * $cookie_expire_days; + + my $sessioncookie = randomToken(64); + + my $session = Litmus::DB::Session->create({ + user_id => $userobj, + sessioncookie => $sessioncookie, + expires => $expires}); + + $curSession = $session; + return $session; +} + +# Given a session, create a login cookie to go with it +sub makeCookie { + my $session = shift; + + my $cookie = Litmus->cgi()->cookie( + -name => $logincookiename, + -value => $session->sessioncookie(), + -domain => $main::ENV{"HTTP_HOST"}, + -expires => $session->expires(), + ); + return $cookie; +} + +sub loginError { + my $c = shift; + my $message = shift; + print $c->header(); + + my $return_to = $c->param("login_loc") || ""; + + # We need to unset some params in $c since otherwise we end up with + # a hidden form field set for "email" and friends and madness results: + $c->param('email', ''); + $c->param('login_type', ''); + $c->param('login_loc', ''); + $c->param('realname', ''); + $c->param('password', ''); + $c->param('password_confirm', ''); + + my $vars = { + return_to => $return_to, + params => $c, + message => "Error: ".$message, + }; + + Litmus->template()->process("auth/login.html.tmpl", $vars) || + internalError(Litmus->template()->error()); + + exit; +} + +# Like crypt(), but with a random salt. Thanks to Bugzilla for this. +sub bz_crypt { + my ($password) = @_; + + # The list of characters that can appear in a salt. Salts and hashes + # are both encoded as a sequence of characters from a set containing + # 64 characters, each one of which represents 6 bits of the salt/hash. + # The encoding is similar to BASE64, the difference being that the + # BASE64 plus sign (+) is replaced with a forward slash (/). + my @saltchars = (0..9, 'A'..'Z', 'a'..'z', '.', '/'); + + # Generate the salt. We use an 8 character (48 bit) salt for maximum + # security on systems whose crypt uses MD5. Systems with older + # versions of crypt will just use the first two characters of the salt. + my $salt = ''; + for ( my $i=0 ; $i < 8 ; ++$i ) { + $salt .= $saltchars[rand(64)]; + } + + # Crypt the password. + my $cryptedpassword = crypt($password, $salt); + + # Return the crypted password. + return $cryptedpassword; +} + +sub randomToken { + my $size = shift || 10; # default to 10 chars if nothing specified + return join("", map{ ('0'..'9','a'..'z','A'..'Z')[rand 62] } (1..$size)); +} + +# Deprecated: +# DO NOT USE sub setCookie { my $user = shift; my $expires = shift; @@ -77,7 +340,7 @@ sub setCookie { $expires = '+3d'; } - my $c = new CGI; + my $c = Litmus->cgi(); my $cookie = $c->cookie( -name => $logincookiename, @@ -89,20 +352,9 @@ sub setCookie { return $cookie; } +# Deprecated: sub getCookie() { - my $c = new CGI; - - my $cookie = $c->cookie($logincookiename); - - my $user = Litmus::DB::User->retrieve($cookie); - if (! $user) { - return 0; - } else { - unless ($user->userid() == $cookie) { - invalidInputError("Invalid login cookie"); - } - } - return $user; + return getCurrentUser(); } sub istrusted($) { @@ -126,13 +378,18 @@ sub canEdit($) { ######################################################################### # logout() # -# Unset the user's cookie, and return them to the main index. +# Unset the user's cookie ######################################################################### sub logout() { - my $c = new CGI; + my $c = Litmus->cgi(); - my $cookie = Litmus::Auth::setCookie(undef,'-1d'); - return $cookie; + my $cookie = $c->cookie( + -name => $logincookiename, + -value => '', + -domain => $main::ENV{"HTTP_HOST"}, + -expires => '-1d' + ); + $c->storeCookie($cookie); } diff --git a/webtools/litmus/Litmus/BugzillaDBI.pm b/webtools/litmus/Litmus/BugzillaDBI.pm new file mode 100755 index 00000000000..38ce738a4a8 --- /dev/null +++ b/webtools/litmus/Litmus/BugzillaDBI.pm @@ -0,0 +1,53 @@ +# -*- mode: cperl; c-basic-offset: 8; indent-tabs-mode: nil; -*- + +=head1 COPYRIGHT + + # ***** BEGIN LICENSE BLOCK ***** + # Version: MPL 1.1 + # + # The contents of this file are subject to the Mozilla Public License + # Version 1.1 (the "License"); you may not use this file except in + # compliance with the License. You may obtain a copy of the License + # at http://www.mozilla.org/MPL/ + # + # Software distributed under the License is distributed on an "AS IS" + # basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + # the License for the specific language governing rights and + # limitations under the License. + # + # The Original Code is Litmus. + # + # The Initial Developer of the Original Code is + # the Mozilla Corporation. + # Portions created by the Initial Developer are Copyright (C) 2005 + # the Initial Developer. All Rights Reserved. + # + # Contributor(s): + # Chris Cooper + # Zach Lipton + # + # ***** END LICENSE BLOCK ***** + +=cut + +package Litmus::BugzillaDBI; + +use strict; +use warnings; +use Litmus::Config; +use Litmus::Error; +use Memoize; + +use base 'Litmus::DBI'; + +my $dsn = "dbi:mysql:$Litmus::Config::bugzilla_db:$Litmus::Config::bugzilla_host"; + +Litmus::BugzillaDBI->set_db('Main', + $dsn, + $Litmus::Config::bugzilla_user, + $Litmus::Config::bugzilla_pass); + + + +1; + diff --git a/webtools/litmus/Litmus/CGI.pm b/webtools/litmus/Litmus/CGI.pm new file mode 100755 index 00000000000..f9665055f43 --- /dev/null +++ b/webtools/litmus/Litmus/CGI.pm @@ -0,0 +1,72 @@ +# -*- mode: cperl; c-basic-offset: 8; indent-tabs-mode: nil; -*- + +=head1 COPYRIGHT + + # ***** BEGIN LICENSE BLOCK ***** + # Version: MPL 1.1 + # + # The contents of this file are subject to the Mozilla Public License + # Version 1.1 (the "License"); you may not use this file except in + # compliance with the License. You may obtain a copy of the License + # at http://www.mozilla.org/MPL/ + # + # Software distributed under the License is distributed on an "AS IS" + # basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + # the License for the specific language governing rights and + # limitations under the License. + # + # The Original Code is Litmus. + # + # The Initial Developer of the Original Code is + # the Mozilla Corporation. + # Portions created by the Initial Developer are Copyright (C) 2005 + # the Initial Developer. All Rights Reserved. + # + # Contributor(s): + # Zach Lipton + # + # ***** END LICENSE BLOCK ***** + +=cut + +package Litmus::CGI; + +use strict; +use base 'CGI'; + +# Subclass of CGI.pm that can store cookies in advance and output them +# later when the header() method is called. This feature should probably +# be submitted as a patch to CGI.pm itself. + +sub new { + my $class = shift; + my @args = @_; + + my $self = $class->SUPER::new(@args); + $self->{'litmusCookieStore'} = []; + return $self; +} + +# Stores a cookie to be set later by the header() method +sub storeCookie { + my $self = shift; + my $cookie = shift; + + # "we're like kids in a candy shop" + my @cookieStore = @{$self->{'litmusCookieStore'}}; + push(@cookieStore, $cookie); + $self->{'litmusCookieStore'} = \@cookieStore; +} + +sub header { + my $self = shift; + my @args = @_; + + foreach my $cur ($self->{'litmusCookieStore'}) { + push(@args, {-cookie => $cur}); + } + + $self->SUPER::header(@args); +} + +1; diff --git a/webtools/litmus/Litmus/Cache.pm b/webtools/litmus/Litmus/Cache.pm index 27ad77addaf..0181a82c65e 100755 --- a/webtools/litmus/Litmus/Cache.pm +++ b/webtools/litmus/Litmus/Cache.pm @@ -56,7 +56,7 @@ sub rebuildCache { # whole thing out as javascript with Data::JavaScript # shield your eyes, we're in for a long trip my @litmusconfig; - my @products = Litmus::DB::Product->search(enabled => 'Yes'); + my @products = Litmus::DB::Product->search(enabled => 1); my $prodcount = 0; foreach my $curproduct (@products) { my $prodrow = \%{$litmusconfig[$prodcount]}; diff --git a/webtools/litmus/Litmus/Config.pm b/webtools/litmus/Litmus/Config.pm index 012c6b96be1..f9a1f911a5d 100755 --- a/webtools/litmus/Litmus/Config.pm +++ b/webtools/litmus/Litmus/Config.pm @@ -36,7 +36,7 @@ use strict; do 'localconfig'; -our $version = "0.0.2"; +our $version = "0.3"; # if true, then Litmus will not accept any requests our $disabled = 0; diff --git a/webtools/litmus/Litmus/DB/BugzillaUser.pm b/webtools/litmus/Litmus/DB/BugzillaUser.pm new file mode 100755 index 00000000000..756eaab9d97 --- /dev/null +++ b/webtools/litmus/Litmus/DB/BugzillaUser.pm @@ -0,0 +1,44 @@ +# -*- mode: cperl; c-basic-offset: 8; indent-tabs-mode: nil; -*- + +=head1 COPYRIGHT + + # ***** BEGIN LICENSE BLOCK ***** + # Version: MPL 1.1 + # + # The contents of this file are subject to the Mozilla Public License + # Version 1.1 (the "License"); you may not use this file except in + # compliance with the License. You may obtain a copy of the License + # at http://www.mozilla.org/MPL/ + # + # Software distributed under the License is distributed on an "AS IS" + # basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + # the License for the specific language governing rights and + # limitations under the License. + # + # The Original Code is Litmus. + # + # The Initial Developer of the Original Code is + # the Mozilla Corporation. + # Portions created by the Initial Developer are Copyright (C) 2005 + # the Initial Developer. All Rights Reserved. + # + # Contributor(s): + # Chris Cooper + # Zach Lipton + # + # ***** END LICENSE BLOCK ***** + +=cut + +package Litmus::DB::BugzillaUser; + +use strict; +use base 'Litmus::BugzillaDBI'; + +Litmus::DB::BugzillaUser->table('profiles'); + +Litmus::DB::BugzillaUser->columns(All => qw/userid login_name cryptpassword realname + disabledtext mybugslink refreshed_when extern_id/); + + +1; diff --git a/webtools/litmus/Litmus/DB/Session.pm b/webtools/litmus/Litmus/DB/Session.pm new file mode 100755 index 00000000000..9ac1b233e9e --- /dev/null +++ b/webtools/litmus/Litmus/DB/Session.pm @@ -0,0 +1,69 @@ +# -*- mode: cperl; c-basic-offset: 8; indent-tabs-mode: nil; -*- + +=head1 COPYRIGHT + + # ***** BEGIN LICENSE BLOCK ***** + # Version: MPL 1.1 + # + # The contents of this file are subject to the Mozilla Public License + # Version 1.1 (the "License"); you may not use this file except in + # compliance with the License. You may obtain a copy of the License + # at http://www.mozilla.org/MPL/ + # + # Software distributed under the License is distributed on an "AS IS" + # basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + # the License for the specific language governing rights and + # limitations under the License. + # + # The Original Code is Litmus. + # + # The Initial Developer of the Original Code is + # the Mozilla Corporation. + # Portions created by the Initial Developer are Copyright (C) 2005 + # the Initial Developer. All Rights Reserved. + # + # Contributor(s): + # Chris Cooper + # Zach Lipton + # + # ***** END LICENSE BLOCK ***** + +=cut + +package Litmus::DB::Session; + +use strict; +use base 'Litmus::DBI'; + +use Time::Piece; + +Litmus::DB::Session->table('sessions'); + +Litmus::DB::Session->columns(All => qw/session_id user_id sessioncookie expires/); + +Litmus::DB::Session->has_a(user_id => "Litmus::DB::User"); + +Litmus::DB::Session->autoinflate(dates => 'Time::Piece'); + +# expire the current Session object +sub makeExpire { + my $self = shift; + $self->delete(); +} + +sub isValid { + my $self = shift; + + if ($self->expires() <= localtime()) { + $self->makeExpire(); + return 0; + } + + if ($self->user_id()->disabled() && $self->user_id()->disabled() == 1) { + $self->makeExpire(); + return 0; + } + return 1; +} + +1; diff --git a/webtools/litmus/Litmus/DB/Testresult.pm b/webtools/litmus/Litmus/DB/Testresult.pm index 0409cd87cc5..3537ccb763e 100755 --- a/webtools/litmus/Litmus/DB/Testresult.pm +++ b/webtools/litmus/Litmus/DB/Testresult.pm @@ -48,6 +48,7 @@ Litmus::DB::Testresult->columns(All => qw/testresult_id test_id last_updated sub Litmus::DB::Testresult->column_alias("testresult_id", "testresultid"); Litmus::DB::Testresult->column_alias("test_id", "testid"); +Litmus::DB::Testresult->column_alias("test_id", "test"); Litmus::DB::Testresult->column_alias("submission_time", "timestamp"); Litmus::DB::Testresult->column_alias("user_id", "user"); Litmus::DB::Testresult->column_alias("platform_id", "platform"); diff --git a/webtools/litmus/Litmus/DB/User.pm b/webtools/litmus/Litmus/DB/User.pm index f59637ea6c9..e333b8cdca8 100755 --- a/webtools/litmus/Litmus/DB/User.pm +++ b/webtools/litmus/Litmus/DB/User.pm @@ -37,11 +37,26 @@ use base 'Litmus::DBI'; Litmus::DB::User->table('users'); -Litmus::DB::User->columns(All => qw/user_id email is_trusted/); +Litmus::DB::User->columns(All => qw/user_id bugzilla_uid email password realname + disabled is_admin/); Litmus::DB::User->column_alias("user_id", "userid"); Litmus::DB::User->column_alias("is_trusted", "istrusted"); +Litmus::DB::User->column_alias("is_admin", "is_trusted"); Litmus::DB::User->has_many(testresults => "Litmus::DB::Testresult"); +Litmus::DB::User->has_many(sessions => "Litmus::DB::Session"); +Litmus::DB::User->has_a(bugzilla_uid => "Litmus::DB::BugzillaUser"); + +# returns the crypt'd password from a linked Bugzilla account if it +# exists or the Litmus user account +sub getRealPasswd { + my $self = shift; + if ($self->bugzilla_uid()) { + return $self->bugzilla_uid()->cryptpassword(); + } else { + return $self->password(); + } +} 1; diff --git a/webtools/litmus/Litmus/DBTools.pm b/webtools/litmus/Litmus/DBTools.pm new file mode 100755 index 00000000000..d6f22af3898 --- /dev/null +++ b/webtools/litmus/Litmus/DBTools.pm @@ -0,0 +1,197 @@ + # The contents of this file are subject to the Mozilla Public License + # Version 1.1 (the "License"); you may not use this file except in + # compliance with the License. You may obtain a copy of the License + # at http://www.mozilla.org/MPL/ + # + # Software distributed under the License is distributed on an "AS IS" + # basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + # the License for the specific language governing rights and + # limitations under the License. + # + # The Original Code is Litmus. + # + # The Initial Developer of the Original Code is + # the Mozilla Corporation. + # Portions created by the Initial Developer are Copyright (C) 2005 + # the Initial Developer. All Rights Reserved. + # + # Contributor(s): + # Chris Cooper + # Zach Lipton + +# Utility functions (based on those from Bugzilla's checksetup.pl to +# create new fields and indicies to the schema when upgrading an installation. + +package Litmus::DBTools; + +use strict; + +sub new { + my ($class, $dbh) = @_; + my $self = {}; + $self->{'dbh'} = $dbh; + bless($self); + return $self; +} + +sub ChangeFieldType +{ + my ($self, $table, $field, $newtype) = @_; + + my $ref = GetFieldDef($table, $field); + #print "0: $$ref[0] 1: $$ref[1] 2: $$ref[2] 3: $$ref[3] 4: $$ref[4]\n"; + + my $oldtype = $ref->[1]; + if (! $ref->[2]) { + $oldtype .= qq{ not null}; + } + if ($ref->[4]) { + $oldtype .= qq{ default "$ref->[4]"}; + } + + if ($oldtype ne $newtype) { + print "Updating field type $field in table $table ...\n"; + print "old: $oldtype\n"; + print "new: $newtype\n"; +# 'not null' should be passed as part of the call to ChangeFieldType() +# $newtype .= " NOT NULL" if $$ref[3]; + $self->{'dbh'}->do("ALTER TABLE $table + CHANGE $field + $field $newtype"); + } +} + +sub RenameField +{ + my ($self, $table, $field, $newname) = @_; + + my $ref = GetFieldDef($table, $field); + return unless $ref; # already fixed? + #print "0: $$ref[0] 1: $$ref[1] 2: $$ref[2] 3: $$ref[3] 4: $$ref[4]\n"; + + if ($$ref[1] ne $newname) { + print "Updating field $field in table $table ...\n"; + my $type = $$ref[1]; + $type .= " NOT NULL" if !$$ref[2]; + $type .= " auto_increment" if $$ref[5] =~ /auto_increment/; + $self->{'dbh'}->do("ALTER TABLE $table + CHANGE $field + $newname $type"); + } +} + +sub AddField +{ + my ($self, $table, $field, $definition) = @_; + + my $ref = GetFieldDef($table, $field); + return if $ref; # already added? + + print "Adding new field $field to table $table ...\n"; + $self->{'dbh'}->do("ALTER TABLE $table + ADD COLUMN $field $definition"); +} + +sub DropField +{ + my ($self, $table, $field) = @_; + + my $ref = GetFieldDef($table, $field); + return unless $ref; # already dropped? + + print "Deleting unused field $field from table $table ...\n"; + $self->{'dbh'}->do("ALTER TABLE $table + DROP COLUMN $field"); +} + +# this uses a mysql specific command. +sub TableExists +{ + my ($self, $table) = @_; + my @tables; + my $dbtable; + my $exists = 0; + my $sth = $self->{'dbh'}->prepare("SHOW TABLES"); + $sth->execute; + while ( ($dbtable) = $sth->fetchrow_array ) { + if ($dbtable eq $table) { + $exists = 1; + } + } + return $exists; +} + +sub GetFieldDef +{ + my ($self, $table, $field) = @_; + my $sth = $self->{'dbh'}->prepare("SHOW COLUMNS FROM $table"); + $sth->execute; + + while (my $ref = $sth->fetchrow_arrayref) { + next if $$ref[0] ne $field; + return $ref; + } +} + +sub GetIndexDef +{ + my ($self, $table, $field) = @_; + my $sth = $self->{'dbh'}->prepare("SHOW INDEX FROM $table"); + $sth->execute; + + while (my $ref = $sth->fetchrow_arrayref) { + next if $$ref[2] ne $field; + return $ref; + } +} + +sub CountIndexes +{ + my ($self, $table) = @_; + + my $sth = $self->{'dbh'}->prepare("SHOW INDEX FROM $table"); + $sth->execute; + + if ( $sth->rows == -1 ) { + die ("Unexpected response while counting indexes in $table:" . + " \$sth->rows == -1"); + } + + return ($sth->rows); +} + +sub DropIndexes +{ + my ($self, $table) = @_; + my %SEEN; + + # get the list of indexes + # + my $sth = $self->{'dbh'}->prepare("SHOW INDEX FROM $table"); + $sth->execute; + + # drop each index + # + while ( my $ref = $sth->fetchrow_arrayref) { + + # note that some indexes are described by multiple rows in the + # index table, so we may have already dropped the index described + # in the current row. + # + next if exists $SEEN{$$ref[2]}; + + if ($$ref[2] eq 'PRIMARY') { + # The syntax for dropping a PRIMARY KEY is different + # from the normal DROP INDEX syntax. + $self->{'dbh'}->do("ALTER TABLE $table DROP PRIMARY KEY"); + } + else { + $self->{'dbh'}->do("ALTER TABLE $table DROP INDEX $$ref[2]"); + } + $SEEN{$$ref[2]} = 1; + + } + +} + +1; \ No newline at end of file diff --git a/webtools/litmus/Litmus/Error.pm b/webtools/litmus/Litmus/Error.pm index e9fecde0d5d..c63ef3d5e6f 100755 --- a/webtools/litmus/Litmus/Error.pm +++ b/webtools/litmus/Litmus/Error.pm @@ -40,11 +40,19 @@ use Litmus; our @ISA = qw(Exporter); @Litmus::Error::EXPORT = qw( + basicError invalidInputError internalError lastDitchError ); +# just a general run of the mill error +sub basicError { + my $message = shift; + _doError($message); + exit; +} + # used to alert the user when an unexpected input value is found sub invalidInputError($) { my $message = shift; diff --git a/webtools/litmus/Litmus/SysConfig.pm b/webtools/litmus/Litmus/SysConfig.pm index 2826e3902fc..c5ce95242bd 100755 --- a/webtools/litmus/Litmus/SysConfig.pm +++ b/webtools/litmus/Litmus/SysConfig.pm @@ -68,7 +68,7 @@ sub setCookie { my %cookiedata; - my $c = new CGI; + my $c = Litmus->cgi(); my $cookie = $c->cookie( -name => $configcookiename.'_'.$self->{"product"}->productid(), -value => join('|', $self->{"product"}->productid(), $self->{"platform"}->platformid(), @@ -81,7 +81,7 @@ sub setCookie { sub getCookie() { my $self = shift; - my $c = new CGI; + my $c = Litmus->cgi(); my $product = shift; my $cookie = $c->cookie($configcookiename.'_'.$product->productid()); @@ -165,7 +165,6 @@ sub displayForm { my @locales = Litmus::DB::Locale->retrieve_all( { order_by => 'abbrev' } ); - my $vars = { locales => \@locales, products => \@products, @@ -184,7 +183,7 @@ sub displayForm { $vars->{"defaultlocale"} = $sysconfig->locale(); } - my $cookie = Litmus::Auth::getCookie(); + my $cookie = Litmus::Auth::getCurrentUser(); $vars->{"defaultemail"} = $cookie; $vars->{"show_admin"} = Litmus::Auth::istrusted($cookie); diff --git a/webtools/litmus/Litmus/Utils.pm b/webtools/litmus/Litmus/Utils.pm index f5e7112bf3a..feb6c314518 100755 --- a/webtools/litmus/Litmus/Utils.pm +++ b/webtools/litmus/Litmus/Utils.pm @@ -52,7 +52,7 @@ sub requireField { my ($fieldname, $field) = @_; unless($field && $field ne "---") { - my $c = new CGI; + my $c = Litmus->cgi(); print $c->header(); invalidInputError("You must make a valid selection for field ".$fieldname."."); } diff --git a/webtools/litmus/Makefile b/webtools/litmus/Makefile index 9b8cccbdc52..f86afd5c154 100755 --- a/webtools/litmus/Makefile +++ b/webtools/litmus/Makefile @@ -30,7 +30,8 @@ templates: index.html.tmpl return if (\$$name !~ /\.tmpl\$$/); \ \$$name =~ s/templates\/en\/default\///; \ if (-M 'templates/en/default/'.\$$name < -M 'data/templates/en/default/'.\$$name \ - || ! -e 'data/templates/en/default/'.\$$name) { \ + || ! -e 'data/templates/en/default/'.\$$name \ + || -M 'Litmus/Template.pm' < -M 'data/templates/en/default/'.\$$name) { \ system("make", "\$$name"); \ } \ }, no_chdir => 1 }, 'templates/en/default'); \ @@ -40,6 +41,12 @@ templates: index.html.tmpl # requires Exuberant Ctags to be installed (http://ctags.sf.net/) ctags: `which ctags` --excmd=number --tag-relative=no --fields=+a+m+n+S -R `pwd` + +tags: ctags test: - perl runtests.pl \ No newline at end of file + $(PERL) runtests.pl + +clean: + rm -rf data + make install \ No newline at end of file diff --git a/webtools/litmus/advanced_search.cgi b/webtools/litmus/advanced_search.cgi index dd5a6de5147..7ba51720c28 100755 --- a/webtools/litmus/advanced_search.cgi +++ b/webtools/litmus/advanced_search.cgi @@ -40,7 +40,7 @@ use Litmus::FormWidget; use CGI; use Time::Piece::MySQL; -my $c = new CGI; +my $c = Litmus->cgi(); print $c->header(); use diagnostics; @@ -244,13 +244,3 @@ Litmus->template()->process("reporting/advanced_search.tmpl", $vars) || internalError(Litmus->template()->error()); exit 0; - - - - - - - - - - diff --git a/webtools/litmus/common_results.cgi b/webtools/litmus/common_results.cgi index 87ab8ec1fa2..d8e89914d59 100755 --- a/webtools/litmus/common_results.cgi +++ b/webtools/litmus/common_results.cgi @@ -41,7 +41,7 @@ use CGI; use Time::Piece::MySQL; -my $c = new CGI; +my $c = Litmus->cgi(); print $c->header(); my $results; diff --git a/webtools/litmus/css/litmus.css b/webtools/litmus/css/litmus.css index d6f2d42f087..e54326cb187 100755 --- a/webtools/litmus/css/litmus.css +++ b/webtools/litmus/css/litmus.css @@ -754,6 +754,7 @@ div.error { padding: 5px; } + .skipLink { position: absolute; left: -1200px; @@ -959,3 +960,27 @@ div.formButtons { padding-bottom: 15px; } +/* 12 Authentication and login **************************************** */ + +div.loginbox { + background: #DDD; + border: solid #BBB 1px; + padding: 5px; + font-size: 120%; +} + +div.login_form { + background: #FF9; + border: solid #BBB 1px; + padding: 5px; + width: 40%; +} + +.login_sectitle { + font-weight: bold; + font-size: 120%; +} + +.login_important { + color: #F00; +} diff --git a/webtools/litmus/edit_categories.cgi b/webtools/litmus/edit_categories.cgi index 66bbe39ca71..e0ead26799c 100755 --- a/webtools/litmus/edit_categories.cgi +++ b/webtools/litmus/edit_categories.cgi @@ -44,7 +44,9 @@ use Time::Piece::MySQL; use diagnostics; -my $c = new CGI; +Litmus::Auth::requireAdmin("edit_categories.cgi"); + +my $c = Litmus->cgi(); print $c->header(); if ($c->param) { @@ -53,7 +55,7 @@ if ($c->param) { if ($c->param('add_product')) { my $name = $c->param('new_product_name'); my $icon_path = $c->param('new_icon_path') || ""; - my $enabled = $c->param('new_enabled') ? 'Yes' : 'No'; + my $enabled = $c->param('new_enabled') ? 1 : 0; eval { $product = Litmus::DB::Product->create({ name => $name, @@ -73,9 +75,9 @@ if ($c->param) { $product->name($c->param('modify_product_name')); $product->iconpath($c->param('modify_icon_path')); if ($c->param('modify_enabled')) { - $product->enabled('Yes'); + $product->enabled(1); } else { - $product->enabled('No'); + $product->enabled(0); } eval { $product->update; diff --git a/webtools/litmus/index.cgi b/webtools/litmus/index.cgi index 740f4dcafdf..ea49e6bd55f 100755 --- a/webtools/litmus/index.cgi +++ b/webtools/litmus/index.cgi @@ -52,7 +52,7 @@ my $test_groups = Litmus::FormWidget->getTestGroups(); my $result_statuses = Litmus::FormWidget->getResultStatuses; my $branches = Litmus::FormWidget->getBranches(); -my $c = new CGI; +my $c = Litmus->cgi(); print $c->header(); my $vars = { @@ -70,9 +70,11 @@ if ($results and scalar @$results > 0) { $vars->{results} = $results; } -my $cookie = Litmus::Auth::getCookie(); -$vars->{"defaultemail"} = $cookie; -$vars->{"show_admin"} = Litmus::Auth::istrusted($cookie); +my $user = Litmus::Auth::getCurrentUser(); +if ($user) { + $vars->{"defaultemail"} = $user; + $vars->{"show_admin"} = $user->is_admin(); +} Litmus->template()->process("index.tmpl", $vars) || internalError(Litmus->template()->error()); diff --git a/webtools/litmus/logout.cgi b/webtools/litmus/logout.cgi index bd7b7eb40b7..831494b0a18 100755 --- a/webtools/litmus/logout.cgi +++ b/webtools/litmus/logout.cgi @@ -38,10 +38,10 @@ use diagnostics; my $title = "Log out"; -my $c = new CGI; -my $cookie = Litmus::Auth::logout(); +Litmus::Auth::logout(); -print $c->header(-cookie => $cookie); +my $c = Litmus->cgi(); +print $c->header(); my $vars = { title => $title, diff --git a/webtools/litmus/populatedb.pl b/webtools/litmus/populatedb.pl index d969618d82e..d955fabe9e7 100755 --- a/webtools/litmus/populatedb.pl +++ b/webtools/litmus/populatedb.pl @@ -30,6 +30,7 @@ use strict; use Getopt::Long; use Litmus::Config; +use DBI; $|++; my $reset_db; @@ -67,31 +68,74 @@ EOT exit; } -if ($reset_db) { - my $schema_file = "createdb.sql"; - my $data_file = "populatedb.sql"; - - print "Creating tables..."; - my $cmd = "mysql --user=$Litmus::Config::db_user --password=$Litmus::Config::db_pass $Litmus::Config::db_name < $schema_file"; - my $rv = system($cmd); - if ($rv) { - die "Error creating database $Litmus::Config::db_name"; - } - print "done.\n"; +# Create database tables, in large part borrowed from the old-school +# --TABLE-- code in checksetup.pl: +print "\nChecking for missing/new database tables...\n"; +our %table; +do 'schema.pl'; # import the schema (%table) +my $dbh = DBI->connect("dbi:mysql:;$Litmus::Config::db_host", + $Litmus::Config::db_user, + $Litmus::Config::db_pass) || + die "Could not connect to mysql database $Litmus::Config::db_host"; - print "Populating tables..."; - $cmd = "mysql --user=$Litmus::Config::db_user --password=$Litmus::Config::db_pass $Litmus::Config::db_name < $data_file"; - $rv = system($cmd); +my @databases = $dbh->func('_ListDBs'); + unless (grep($_ eq $Litmus::Config::db_name, @databases)) { + print "Creating database $Litmus::Config::db_name ...\n"; + if (!$dbh->func('createdb', $Litmus::Config::db_name, 'admin')) { + my $error = $dbh->errstr; + die "Could not create database $Litmus::Config::db_name: $error\n"; + } +} +$dbh->disconnect if $dbh; + +$dbh = DBI->connect( + "dbi:mysql:$Litmus::Config::db_name:$Litmus::Config::db_host", + $Litmus::Config::db_user, + $Litmus::Config::db_pass); + + +# Get a list of the existing tables (if any) in the database +my $sth = $dbh->table_info(undef, undef, undef, "TABLE"); +my @tables = @{$dbh->selectcol_arrayref($sth, { Columns => [3] })}; + +# go throught our %table hash and create missing tables +while (my ($tabname, $fielddef) = each %table) { + next if grep($_ eq $tabname, @tables); + print "Creating table $tabname ...\n"; + + $dbh->do("CREATE TABLE $tabname (\n$fielddef\n) TYPE = MYISAM") + or die "Could not create table '$tabname'. Please check your database access.\n"; +} + +# populate the database with the default data in populatedb.sql: +if ($reset_db) { + my $data_file = "populatedb.sql"; + + print "Populating tables with default data..."; + my $cmd = "mysql --user=$Litmus::Config::db_user --password=$Litmus::Config::db_pass $Litmus::Config::db_name < $data_file"; + my $rv = system($cmd); if ($rv) { die "Error populating database $Litmus::Config::db_name"; } print "done.\n"; } -# javascript cache +# UPGRADE THE SCHEMA +# Now we need to deal with upgrading old installations by adding new fields and +# indicies to the schema. To do this, we use the helpful Litmus::DBTools module +# Note that anything changed here should also be added to schema.pl for new +# installations +use Litmus::DBTools; +my $dbtool = Litmus::DBTools->new($dbh); + +# for example: +# $dbtool->AddField('tests', 'newfield', 'varchar(64)'); + + +# javascript cache print "Rebuilding JS cache..."; -use Litmus::Cache; -rebuildCache(); +require Litmus::Cache; +Litmus::Cache::rebuildCache(); print "done.\n"; exit; diff --git a/webtools/litmus/populatedb.sql b/webtools/litmus/populatedb.sql index 3fb2bee00f0..10fa65a710c 100644 --- a/webtools/litmus/populatedb.sql +++ b/webtools/litmus/populatedb.sql @@ -97,7 +97,7 @@ UNLOCK TABLES; /*!40000 ALTER TABLE `products` DISABLE KEYS */; LOCK TABLES `products` WRITE; -INSERT INTO `products` VALUES (1,'Firefox','ff.gif','Yes'),(2,'Seamonkey','moz.png','Yes'),(3,'Thunderbird','tb.gif','Yes'); +INSERT INTO `products` VALUES (1,'Firefox','ff.gif',1),(2,'Seamonkey','moz.png',1),(3,'Thunderbird','tb.gif',1); UNLOCK TABLES; /*!40000 ALTER TABLE `products` ENABLE KEYS */; diff --git a/webtools/litmus/process_test.cgi b/webtools/litmus/process_test.cgi index 8e6625de9f2..7e3570949b5 100755 --- a/webtools/litmus/process_test.cgi +++ b/webtools/litmus/process_test.cgi @@ -42,7 +42,7 @@ use CGI; use Date::Manip; use diagnostics; -my $c = new CGI; +my $c = Litmus->cgi(); my $user; my $sysconfig; @@ -250,4 +250,3 @@ if ($c->param("isSimpleTest")) { Litmus->template()->process("process/process.html.tmpl", $vars) || internalError(Litmus->template()->error()); } - diff --git a/webtools/litmus/run_tests.cgi b/webtools/litmus/run_tests.cgi index 7c7b68ed590..10d8f50e2d3 100755 --- a/webtools/litmus/run_tests.cgi +++ b/webtools/litmus/run_tests.cgi @@ -41,7 +41,7 @@ use Time::Piece::MySQL; my $title = "Run Tests"; -my $c = new CGI; +my $c = Litmus->cgi(); if ($c->param("group")) { # display the test screen page_test(); @@ -73,7 +73,6 @@ sub page_sysSetup { # an area to test: sub page_pickGroupSubgroup { my $sysconfig; - my $user; my $product = Litmus::DB::Product->retrieve($c->param("product")); if (! $product) { @@ -81,29 +80,24 @@ sub page_pickGroupSubgroup { invalidInputError("Invalid product ".$c->param("product")); } + Litmus::Auth::requireLogin("run_tests.cgi"); + if ($c->param("continuetesting")) { # they have already gotten setup and just want to # pick a new group or subgroup: $sysconfig = Litmus::SysConfig->getCookie($product); if (!$sysconfig) {page_pickProduct()}; - $user = Litmus::Auth::getCookie(); print $c->header(); } else { $sysconfig = Litmus::SysConfig->processForm($c); - # get the user id and set a login cookie: - my $email = $c->param("email"); - if (!$email) { - print $c->header(); - invalidInputError("You must enter your email address so we can track your results and contact you if we have any questions."); - } - $user = Litmus::DB::User->find_or_create(email => $email); - - print $c->header(-cookie => [$sysconfig->setCookie(), Litmus::Auth::setCookie($user)]); + # get the user id and set a sysconfig cookie + $c->storeCookie($sysconfig->setCookie()); + print $c->header(); } # get all groups for the product: - my @groups = Litmus::DB::Testgroup->search(product => $sysconfig->product(), obsolete => 'No'); + my @groups = Litmus::DB::Testgroup->search(product => $sysconfig->product(), obsolete => 0); # all possible subgroups per group: my %subgroups; @@ -120,7 +114,7 @@ sub page_pickGroupSubgroup { my $vars = { title => $title, - user => $user, + user => Litmus::Auth::getCurrentUser(), opsys => $sysconfig->opsys(), groups => \@groups, subgroups => \%subgroups, diff --git a/webtools/litmus/schema.pl b/webtools/litmus/schema.pl new file mode 100755 index 00000000000..4e07e817295 --- /dev/null +++ b/webtools/litmus/schema.pl @@ -0,0 +1,277 @@ +# The contents of this file are subject to the Mozilla Public License Version +# 1.1 (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# http://www.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS IS" basis, +# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +# for the specific language governing rights and limitations under the +# License. +# +# The Original Code is Litmus. +# +# The Initial Developer of the Original Code is +# the Mozilla Corporation. +# Portions created by the Initial Developer are Copyright (C) 2005 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Chris Cooper +# Zach Lipton + +# Litmus database schema + +our $table; + +$table{branches} = + 'branch_id smallint not null primary key auto_increment, + product_id tinyint not null, + name varchar(64) not null, + detect_regexp varchar(255), + + index(product_id), + index(name)'; + +$table{build_type_lookup} = + 'build_type_id tinyint not null primary key auto_increment, + name varchar(64) not null, + + index(name)'; + +$table{exit_status_lookup} = + 'exit_status_id tinyint not null primary key auto_increment, + name varchar(64) not null, + + index(name)'; + +$table{locale_lookup} = + 'abbrev varchar(16) not null primary key, + name varchar(64) not null, + + index(name)'; + +$table{log_type_lookup} = + 'log_type_id tinyint not null primary key auto_increment, + name varchar(64) not null, + + index(name)'; + +$table{opsyses} = + 'opsys_id smallint not null primary key auto_increment, + platform_id smallint not null, + name varchar(64) not null, + detect_regexp varchar(255), + + index(platform_id), + index(name)'; + +$table{platforms} = + 'platform_id smallint not null primary key auto_increment, + product_id tinyint not null, + name varchar(64) not null, + detect_regexp varchar(255), + iconpath varchar(255), + + index(product_id), + index(name)'; + +$table{products} = + 'product_id tinyint not null primary key auto_increment, + name varchar(64) not null, + iconpath varchar(255), + enabled tinyint default \'1\', + + index(name), + index(enabled)'; + +$table{subgroups} = + 'subgroup_id smallint not null primary key auto_increment, + testgroup_id smallint not null, + name varchar(64) not null, + sort_order smallint(6), + testrunner_group_id int, + + index(testgroup_id), + index(name), + index(sort_order), + index(testrunner_group_id)'; + +$table{test_format_lookup} = + 'format_id tinyint not null primary key auto_increment, + name varchar(255) not null, + + index(name)'; + +$table{test_groups} = + 'testgroup_id smallint not null primary key auto_increment, + product_id tinyint not null, + name varchar(64) not null, + expiration_days smallint not null, + obsolete tinyint default \'1\', + testrunner_plan_id int, + + index(product_id), + index(name), + index(expiration_days), + index(obsolete), + index(testrunner_plan_id)'; + +$table{test_result_bugs} = + 'test_result_id int not null primary key auto_increment, + last_updated datetime not null, + submission_time datetime not null, + user_id int, + bug_id int not null, + + index(test_result_id), + index(last_updated), + index(submission_time), + index(user_id)'; + +$table{test_result_comments} = + 'comment_id int not null primary key auto_increment, + test_result_id int not null, + last_updated datetime not null, + submission_time datetime not null, + user_id int, + comment text, + + index(test_result_id), + index(last_updated), + index(submission_time), + index(user_id)'; + +$table{test_result_logs} = + 'log_id int not null primary key auto_increment, + test_result_id int not null, + last_updated datetime not null, + submission_time datetime not null, + log_path varchar(255), + log_type_id tinyint not null default \'1\', + + index(test_result_id), + index(last_updated), + index(submission_time), + index(log_path), + index(log_type_id)'; + +$table{test_result_status_lookup} = + 'result_status_id smallint not null primary key auto_increment, + name varchar(64) not null, + style varchar(255) not null, + class_name varchar(16), + + index(name), + index(style), + index(class_name)'; + +$table{test_results} = + 'testresult_id int not null primary key auto_increment, + test_id int not null, + last_updated datetime, + submission_time datetime, + user_id int, + platform_id smallint, + opsys_id smallint, + branch_id smallint, + buildid varchar(45), + user_agent varchar(255), + result_id smallint, + build_type_id tinyint not null default \'1\', + machine_name varchar(64), + exit_status_id tinyint not null default \'1\', + duration_ms int unsigned, + talkback_id int unsigned, + validity_id tinyint not null default \'1\', + vetting_status_id tinyint not null default \'1\', + locale_abbrev varchar(16) not null default \'en-US\', + + index(test_id), + index(last_updated), + index(submission_time), + index(user_id), + index(platform_id), + index(opsys_id), + index(branch_id), + index(user_agent), + index(result_id), + index(build_type_id), + index(machine_name), + index(exit_status_id), + index(duration_ms), + index(talkback_id), + index(validity_id), + index(vetting_status_id), + index(locale_abbrev)'; + +$table{test_status_lookup} = + 'test_status_id tinyint not null primary key auto_increment, + name varchar(64) not null, + + index(name)'; + +$table{tests} = + 'test_id int not null primary key auto_increment, + subgroup_id smallint not null, + summary varchar(255) not null, + details text, + status_id tinyint not null, + community_enabled tinyint(1), + format_id tinyint not null default \'1\', + regression_bug_id int, + steps longtext, + expected_results longtext, + sort_order smallint not null default \'1\', + author_id int not null, + creation_date datetime not null, + last_updated datetime not null, + version smallint not null default \'1\', + testrunner_case_id int, + testrunner_case_version int, + + index(subgroup_id), + index(summary), + index(status_id), + index(community_enabled), + index(regression_bug_id), + index(steps(255)), + index(expected_results(255)), + index(author_id), + index(creation_date), + index(last_updated), + index(testrunner_case_id)'; + +$table{users} = + 'user_id int not null primary key auto_increment, + bugzilla_uid int, + email varchar(255), + password varchar(255), + realname varchar(255), + disabled mediumtext, + is_admin tinyint(1), + + index(bugzilla_uid), + index(email), + index(is_admin)'; + +$table{sessions} = + 'session_id int not null primary key auto_increment, + user_id int not null, + sessioncookie varchar(255) not null, + expires datetime not null, + + index(user_id), + index(sessioncookie), + index(expires)'; + +$table{validity_lookup} = + 'validity_id tinyint not null primary key auto_increment, + name varchar(64) not null, + + index(name)'; + +$table{vetting_status_lookup} = + 'vetting_status_id tinyint not null primary key auto_increment, + name varchar(64) not null, + + index(name)'; \ No newline at end of file diff --git a/webtools/litmus/search_results.cgi b/webtools/litmus/search_results.cgi index 145c6c31447..da6d8bd17e1 100755 --- a/webtools/litmus/search_results.cgi +++ b/webtools/litmus/search_results.cgi @@ -40,7 +40,7 @@ use Litmus::FormWidget; use CGI; use Time::Piece::MySQL; -my $c = new CGI; +my $c = Litmus->cgi(); print $c->header(); use diagnostics; diff --git a/webtools/litmus/show_test.cgi b/webtools/litmus/show_test.cgi index 51f3771b61e..7fe1982337f 100755 --- a/webtools/litmus/show_test.cgi +++ b/webtools/litmus/show_test.cgi @@ -32,7 +32,7 @@ use Litmus::Auth; use CGI; use Time::Piece::MySQL; -my $c = new CGI; +my $c = Litmus->cgi(); print $c->header(); diff --git a/webtools/litmus/simpletest.cgi b/webtools/litmus/simpletest.cgi index ed6660b4213..b1bcadb6309 100755 --- a/webtools/litmus/simpletest.cgi +++ b/webtools/litmus/simpletest.cgi @@ -39,7 +39,7 @@ use Litmus::Auth; use CGI; use Time::Piece::MySQL; -my $c = new CGI; +my $c = Litmus->cgi(); # how old of a build do we want to allow? default is 10 days my $maxbuildage = 10; diff --git a/webtools/litmus/single_result.cgi b/webtools/litmus/single_result.cgi index 46a9ff94fd8..db1cbb20c95 100755 --- a/webtools/litmus/single_result.cgi +++ b/webtools/litmus/single_result.cgi @@ -40,7 +40,7 @@ use Litmus::DB::Resultbug; use CGI; use Date::Manip; -my $c = new CGI; +my $c = Litmus->cgi(); print $c->header(); if ($c->param && $c->param('id')) { diff --git a/webtools/litmus/stats.cgi b/webtools/litmus/stats.cgi index c4eed039a1b..7dfafc5dda2 100755 --- a/webtools/litmus/stats.cgi +++ b/webtools/litmus/stats.cgi @@ -37,7 +37,7 @@ use Litmus::DB::Product; use CGI; use Time::Piece::MySQL; -my $c = new CGI; +my $c = Litmus->cgi(); print $c->header(); diff --git a/webtools/litmus/templates/en/default/admin/form_widgets/update_products.tmpl b/webtools/litmus/templates/en/default/admin/form_widgets/update_products.tmpl index d8e2c795d31..6a4e9fbc2f9 100644 --- a/webtools/litmus/templates/en/default/admin/form_widgets/update_products.tmpl +++ b/webtools/litmus/templates/en/default/admin/form_widgets/update_products.tmpl @@ -26,7 +26,7 @@ function updateProductForm() { document.getElementById("modify_product_icon_path").disabled = false; document.getElementById("modify_product_icon_path").value = update[2]; document.getElementById("modify_product_enabled").disabled = false; - document.getElementById("modify_product_enabled").checked = update[3] == 'Yes' ? true : false; + document.getElementById("modify_product_enabled").checked = update[3] == 1 ? true : false; document.getElementById("delete_product").disabled = false; document.getElementById("update_product").disabled = false; } else { diff --git a/webtools/litmus/templates/en/default/auth/accountcreated.html.tmpl b/webtools/litmus/templates/en/default/auth/accountcreated.html.tmpl new file mode 100755 index 00000000000..7a0c4d103e0 --- /dev/null +++ b/webtools/litmus/templates/en/default/auth/accountcreated.html.tmpl @@ -0,0 +1,77 @@ +[%# ***** BEGIN LICENSE BLOCK ***** + # Version: MPL 1.1 + # + # The contents of this file are subject to the Mozilla Public License Version + # 1.1 (the "License"); you may not use this file except in compliance with + # the License. You may obtain a copy of the License at + # http://www.mozilla.org/MPL/ + # + # Software distributed under the License is distributed on an "AS IS" basis, + # WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + # for the specific language governing rights and limitations under the + # License. + # + # The Original Code is Litmus. + # + # The Initial Developer of the Original Code is + # The Mozilla Corporation. + # Portions created by the Initial Developer are Copyright (C) 2005 + # the Initial Developer. All Rights Reserved. + # + # Contributor(s): + # Chris Cooper + # Zach Lipton + # + # ***** END LICENSE BLOCK ***** +#%] + +[%# INTERFACE: + # $email - the email address of the new user + # $realname - the real name of the user + # $return_to - where to go after logging in + # $params - CGI.pm object containing parameters to store in hidden fields +#%] + +[% INCLUDE global/html_header.tmpl title = 'Account Created' %] +[% INCLUDE global/litmus_header.tmpl title = 'Account Created' %] + +[% # Dump CGI data into hidden fields for safekeeping as the user + # logs in +%] +[% BLOCK create_hidden_fields %] + [% IF params %] + [% FOREACH curdata = params.param() %] + [% IF ! params.param(curdata) %] [% NEXT %] [% END %] + + [% END %] + [% END %] +[% END %] + +
+ +[% INCLUDE sidebar/sidebar.tmpl %] + +
+ +

Account Created

+ +

Thank you [% realname FILTER html %], your account + [% email FILTER html %] has been created

+ +

Thank you for helping out + with Mozilla QA

+ +
+ [% INCLUDE create_hidden_fields %] + + +
+ + + +
+ +
+ +[% INCLUDE global/html_footer.tmpl %] diff --git a/webtools/litmus/templates/en/default/auth/login.html.tmpl b/webtools/litmus/templates/en/default/auth/login.html.tmpl new file mode 100755 index 00000000000..d420dbd9174 --- /dev/null +++ b/webtools/litmus/templates/en/default/auth/login.html.tmpl @@ -0,0 +1,139 @@ +[%# ***** BEGIN LICENSE BLOCK ***** + # Version: MPL 1.1 + # + # The contents of this file are subject to the Mozilla Public License Version + # 1.1 (the "License"); you may not use this file except in compliance with + # the License. You may obtain a copy of the License at + # http://www.mozilla.org/MPL/ + # + # Software distributed under the License is distributed on an "AS IS" basis, + # WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + # for the specific language governing rights and limitations under the + # License. + # + # The Original Code is Litmus. + # + # The Initial Developer of the Original Code is + # The Mozilla Corporation. + # Portions created by the Initial Developer are Copyright (C) 2005 + # the Initial Developer. All Rights Reserved. + # + # Contributor(s): + # Chris Cooper + # Zach Lipton + # + # ***** END LICENSE BLOCK ***** +#%] + +[%# INTERFACE: + # $return_to - the CGI script to redirect to after the login is complete + # %params - the CGI object containing parameters to pass to the + # script in $redirect_to + # $message (optional) - an error message to display +#%] + +[% INCLUDE global/html_header.tmpl title = 'Login' %] +[% INCLUDE global/litmus_header.tmpl title = 'Login' %] + +[% # Dump CGI data into hidden fields for safekeeping as the user + # logs in +%] +[% BLOCK create_hidden_fields %] + [% IF params %] + [% FOREACH curdata = params.param() %] + [% IF ! params.param(curdata) %] [% NEXT %] [% END %] + + [% END %] + [% END %] +[% END %] + +
+ +[% INCLUDE sidebar/sidebar.tmpl %] + +
+ +

Login

+ +

[% message FILTER html %]

+ +
+ + + + + + + + + +
+ +
+ +
+ +[% INCLUDE global/html_footer.tmpl %] diff --git a/webtools/litmus/templates/en/default/runtests/sysconfig.html.tmpl b/webtools/litmus/templates/en/default/runtests/sysconfig.html.tmpl index 90acff65f1a..c1774186800 100755 --- a/webtools/litmus/templates/en/default/runtests/sysconfig.html.tmpl +++ b/webtools/litmus/templates/en/default/runtests/sysconfig.html.tmpl @@ -131,12 +131,8 @@ System Information -
Email Address:
- - - -PRIVACY NOTICE: Like Bugzilla, Litmus is an open system. All testing results you submit will be visible to the public, including the email addresses of those involved. Although steps are taken to hide addresses from email harvesters, the spammers are continually getting better technology and it is almost guaranteed that the address you use with Litmus will get spam. We recommend using a free web email service (such as Yahoo or Hotmail or similar) and not your primary email address if this concerns you. There are solutions being worked on to allow you to hide your email address from other users, but that option is not yet available. +PRIVACY NOTICE: Like Bugzilla, Litmus is an open system used by the Mozilla community. All testing results you submit will be visible to the public, including the email addresses of those involved and any comments you enter. Although Litmus takes steps to prevent spammers from harvesting your email address, spam cannot be eliminated entirely. We recommend using a free web email service (such as Yahoo, Gmail, or similar) and not your primary email address if this concerns you. There are solutions being worked on to allow you to hide your email address from other users, but that option is not yet available. diff --git a/webtools/litmus/templates/en/default/runtests/testdisplay.html.tmpl b/webtools/litmus/templates/en/default/runtests/testdisplay.html.tmpl index 25ecd09e04d..a8d891f0c44 100755 --- a/webtools/litmus/templates/en/default/runtests/testdisplay.html.tmpl +++ b/webtools/litmus/templates/en/default/runtests/testdisplay.html.tmpl @@ -149,8 +149,6 @@
Result:
[% INCLUDE form_widgets/radio_testresults.tmpl test_id=curtest.testid %]
-
-
@@ -169,7 +167,14 @@ - + [% IF i < tests.size - 1 %] + + [% END %] diff --git a/webtools/litmus/templates/en/default/sidebar/sidebar.tmpl b/webtools/litmus/templates/en/default/sidebar/sidebar.tmpl index 62c83232295..b127db09f9d 100644 --- a/webtools/litmus/templates/en/default/sidebar/sidebar.tmpl +++ b/webtools/litmus/templates/en/default/sidebar/sidebar.tmpl @@ -10,4 +10,6 @@ [% INCLUDE sidebar/widget_legend.tmpl %] +
Litmus - [% constants.litmus_version FILTER html %]
+ diff --git a/webtools/litmus/testlist.cgi b/webtools/litmus/testlist.cgi index 57962e08391..92a2ecdb82e 100755 --- a/webtools/litmus/testlist.cgi +++ b/webtools/litmus/testlist.cgi @@ -37,7 +37,7 @@ use Litmus::DB::Product; use CGI; use Time::Piece::MySQL; -my $c = new CGI; +my $c = Litmus->cgi(); print $c->header();