Compare commits

..

1 Commits

Author SHA1 Message Date
(no author)
258dc9fead This commit was manufactured by cvs2svn to create branch 'src'.
git-svn-id: svn://10.0.0.236/branches/src@33658 18797224-902f-48f8-a5cc-f745e15eee43
1999-06-03 23:10:01 +00:00
327 changed files with 18627 additions and 27716 deletions

View File

@@ -1,3 +0,0 @@
<FilesMatch ^(.*localconfig.*)$>
deny from all
</FilesMatch>

View File

@@ -1,44 +0,0 @@
===Litmus Installation Instructions===
First of all, let me convince you that you in fact probbaly do not want
to install Litmus. Litmus is not 1.0 software. Litmus is not even 0.5
software. In fact, Litmus doesn't really do any of the things you would
expect it to do yet.
In summary, if you're not looking to install Litmus because you are or
want to be a Litmus developer, you'd best turn around and go back from
whence you came.
If at any point you find that you don't understand these installation
instructions, it's a good sign you want to turn back as well.
Required Perl Modules:
Class::DBI
Class::DBI::mysql
Template
Time::Piece
Time::Piece::mysql
Time::Seconds
Date::Manip
HTML::StripScripts
HTML::StripScripts::Parser
Text::Markdown
XML::XPath
Once you've got everything installed, run: mysql < createdb.sql to
create the Litmus database.
Then edit Litmus/Config.pm to give it the information it needs to
connect to the database.
Run ./populatedb.pl to create products, testgroups, subgroups, etc...
There is no UI at present for doing this.
Edit the newly created 'localconfig' file and provide your database
configuration.
Then just pop the whole thing into a directory where your web server can
get at it. Have fun!
Note: After upgrading Litmus, it's a good idea to run populatedb.pl
again to pick up any schema changes that may have occured.

View File

@@ -1,109 +0,0 @@
# -*- 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) 2006
# the Initial Developer. All Rights Reserved.
#
# Contributor(s):
# Chris Cooper <ccooper@deadsquid.com>
# Zach Lipton <zach@zachlipton.com>
# Max Kanat-Alexander <mkanat@bugzilla.org>
#
# ***** END LICENSE BLOCK *****
=cut
# Global object store and function library for Litmus
package Litmus;
use strict;
use Litmus::Template;
use Litmus::Config;
use Litmus::Error;
use Litmus::Auth;
use Litmus::CGI;
our $_request_cache = {};
# each cgi _MUST_ call Litmus->init() prior to doing anything else.
# init() ensures that the installation has not been disabled, deals with pending
# login requests, and other essential tasks.
sub init() {
if ($Litmus::Config::disabled) {
my $c = new CGI();
print $c->header();
print "Litmus has been shutdown by the administrator. Please try again later.";
exit;
}
# check for pending logins:
my $c = cgi();
if ($c->param("login_type")) {
Litmus::Auth::processLoginForm();
}
}
# Global Template object
sub template() {
my $class = shift;
request_cache()->{template} ||= Litmus::Template->create();
return request_cache()->{template};
}
# Global CGI object
sub cgi() {
my $class = shift;
request_cache()->{cgi} ||= new Litmus::CGI();
return request_cache()->{cgi};
}
sub getCurrentUser {
return Litmus::Auth::getCurrentUser();
}
# cache of global variables for a single request only
# use me like: Litmus->request_cache->{'var'} = 'foo';
# entries here are guarenteed to get flushed when the request ends,
# even when running under mod_perl
# from Bugzilla.pm:
sub request_cache {
if ($ENV{MOD_PERL}) {
my $request = Apache->request();
my $cache = $request->pnotes();
# Sometimes mod_perl doesn't properly call DESTROY on all
# the objects in pnotes(), so we register a cleanup handler
# to make sure that this happens.
if (!$cache->{cleanup_registered}) {
$request->push_handlers(PerlCleanupHandler => sub {
my $r = shift;
foreach my $key (keys %{$r->pnotes}) {
delete $r->pnotes->{$key};
}
});
$cache->{cleanup_registered} = 1;
}
return $cache;
}
return $_request_cache;
}
1;

View File

@@ -1,555 +0,0 @@
# -*- 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) 2006
# the Initial Developer. All Rights Reserved.
#
# Contributor(s):
# Chris Cooper <ccooper@deadsquid.com>
# Zach Lipton <zach@zachlipton.com>
#
# ***** END LICENSE BLOCK *****
=cut
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::Error;
use Time::Piece;
use Time::Seconds;
use Litmus::DB::User;
use CGI;
our @ISA = qw(Exporter);
our @EXPORT = qw();
my $logincookiename = $Litmus::Config::user_cookiename;
my $cookie_expire_days = 7;
# Given a username and password, validate the login. Returns the
# Litmus::DB::User object associated with the username if the login
# is sucuessful. Returns false otherwise.
sub validate_login($$) {
my $username = shift;
my $password = shift;
return 0 if (!$username or $username eq '' or
!$password or $password eq '');
my ($userobj) = Litmus::DB::User->search(email => $username);
if (!$userobj) {
return 0;
}
if (!$userobj->enabled() || $userobj->enabled() == 0) {
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();
return 0 if (!$realPasswordCrypted or $realPasswordCrypted eq '');
my $enteredPasswordCrypted = crypt($password, $realPasswordCrypted);
if ($enteredPasswordCrypted eq $realPasswordCrypted) {
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 $admin_login_required = 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 = {
title => "Login",
return_to => $return_to,
adminrequired => $admin_login_required,
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($return_to, 1);
if (!$user || !$user->is_admin()) {
print $cgi->header();
basicError("You must be a Litmus administrator to perform this function.");
}
return $user;
}
# Returns the current Litmus::DB::Session object corresponding to the current
# logged-in user, or 0 if no valid session exists
sub getCurrentSession() {
my $c = Litmus->cgi();
# we're actually processing the login form right now, so the cookie hasn't
# been sent yet...
if (Litmus->request_cache->{'curSession'}) {
return Litmus->request_cache->{'curSession'};
}
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;
}
# Returns the Litmus::User object corresponding to the current logged-in
# user, or 0 if no valid login cookie exists
sub getCurrentUser() {
my $session = getCurrentSession();
if ($session) {
return $session->user_id();
} else {
return 0;
}
}
#
# 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");
my $nickname = $c->param("irc_nickname");
# 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.");
}
my @users = Litmus::DB::User->search(email => $email);
if ($users[0]) {
loginError($c, "User ".$users[0]->email() ." already exists.");
}
if ($nickname and $nickname ne '') {
@users = Litmus::DB::User->search(irc_nickname => $nickname);
if ($users[0]) {
loginError($c, "An account with that IRC nickname already exists.");
}
} else {
$nickname = undef;
}
my $userobj =
Litmus::DB::User->create({email => $email,
password => bz_crypt($password),
bugzilla_uid => 0,
realname => $name,
enabled => 1,
is_admin => 0,
irc_nickname => $nickname
});
my $session = makeSession($userobj);
$c->storeCookie(makeCookie($session));
my $vars = {
title => "Account Created",
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");
} elsif ($type eq "convert") {
# convert an old-school Litmus account (pre authentication system)
# to a new one with a password:
my $username = $c->param("email");
my @userobjs = Litmus::DB::User->search(email => $username);
my $userobj = $userobjs[0];
if (! $userobj || $userobj->email() ne $username) {
loginError($c, "User $username does not exist.");
}
if ($userobj->password() ne "") {
# already a new-style account
loginError($c, "User $username has already been updated.");
}
# display a "convert login" form to get the rest of the information
print $c->header();
my $return_to = $c->param("login_loc") || "";
unsetFields();
my $vars = {
title => "Update Login",
email => $username,
return_to => $return_to,
params => $c,
};
Litmus->template()->process("auth/convertaccount.html.tmpl", $vars) ||
internalError(Litmus->template()->error());
exit;
} elsif ($type eq "reallyconvert") {
my $username = $c->param("email");
my $realname = $c->param("realname");
my $password = $c->param("password");
my $password_confirm = $c->param("password_confirm");
my $nickname = $c->param("irc_nickname");
if (! $password eq $password_confirm) {
loginError($c, "Passwords do not match. Please try again.");
}
my @userobjs = Litmus::DB::User->search(email => $username);
my $userobj = $userobjs[0];
# just to be safe:
if (! $userobj || $userobj->email() ne $username) {
loginError($c, "User $username does not exist.");
}
if ($userobj->password() ne "" && ($userobj->bugzilla_uid() == 0 ||
!$userobj->bugzilla_uid())) {
# already a new-style account
loginError($c, "User $username has already been updated.");
}
my ($nickname_exists) =
Litmus::DB::User->search(irc_nickname => $nickname);
if ($nickname_exists) {
loginError($c,
"An account with that IRC nickname already exists.",
"auth/convertaccount.html.tmpl",
"Update Login");
}
# do the upgrade:
$userobj->password(bz_crypt($password));
$userobj->bugzilla_uid("0");
$userobj->realname($realname);
$userobj->enabled(1);
# $userobj->is_admin(0);
$userobj->irc_nickname($nickname);
$userobj->update();
my $session = makeSession($userobj);
$c->storeCookie(makeCookie($session));
my $vars = {
title => "Account Created",
email => $username,
realname => $realname,
return_to => $c->param("login_loc"),
params => $c
};
print $c->header();
Litmus->template()->process("auth/accountcreated.html.tmpl", $vars) ||
internalError(Litmus->template()->error());
exit;
} else {
internalError("Unknown login scheme attempted");
}
}
sub changePassword {
my $userobj = shift;
my $password = shift;
$userobj->password(bz_crypt($password));
$userobj->update();
my @sessions = $userobj->sessions();
foreach my $session (@sessions) {
$session->makeExpire();
}
}
# Given a userobj, process the login and return a session object
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});
Litmus->request_cache->{'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;
my $template = shift;
my $title = shift;
if (!$template) {
$template = "auth/login.html.tmpl";
}
if (!$title) {
$title = "Login";
}
print $c->header();
my $return_to = $c->param("login_loc") || "";
my $email = $c->param("email") || "";
unsetFields();
my $vars = {
title => $title,
return_to => $return_to,
email => $email,
params => $c,
onload => "toggleMessage('failure','$message')",
};
Litmus->template()->process($template, $vars) ||
internalError(Litmus->template()->error());
exit;
}
sub unsetFields() {
my $c = Litmus->cgi();
# 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('username', '');
$c->param('login_type', '');
$c->param('login_loc', '');
$c->param('realname', '');
$c->param('password', '');
$c->param('password_confirm', '');
}
# 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;
my $user_id = 0;
if ($user) {
$user_id = $user->user_id();
}
if (!$expires or $expires eq '') {
$expires = '+3d';
}
my $c = Litmus->cgi();
my $cookie = $c->cookie(
-name => $logincookiename,
-value => $user_id,
-domain => $main::ENV{"HTTP_HOST"},
-expires => $expires,
);
return $cookie;
}
# Deprecated:
sub getCookie() {
return getCurrentUser();
}
sub istrusted($) {
my $userobj = shift;
return 0 if (!$userobj);
if ($userobj->istrusted()) {
return 1;
} else {
return 0;
}
}
sub canEdit($) {
my $userobj = shift;
return $userobj->istrusted();
}
#########################################################################
# logout()
#
# Unset the user's cookie
#########################################################################
sub logout() {
my $c = Litmus->cgi();
my $cookie = $c->cookie(
-name => $logincookiename,
-value => '',
-domain => $main::ENV{"HTTP_HOST"},
-expires => '-1d'
);
$c->storeCookie($cookie);
# invalidate the session behind the cookie as well:
my $session = getCurrentSession();
if ($session) { $session->makeExpire() }
}
1;

View File

@@ -1,59 +0,0 @@
# -*- 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) 2006
# the Initial Developer. All Rights Reserved.
#
# Contributor(s):
# Chris Cooper <ccooper@deadsquid.com>
# Zach Lipton <zach@zachlipton.com>
#
# ***** END LICENSE BLOCK *****
=cut
package Litmus::BugzillaDBI;
use strict;
use warnings;
use Litmus::Config;
use Litmus::Error;
use Memoize;
use base 'Litmus::DBI';
BEGIN {
unless ($Litmus::Config::bugzilla_auth_enabled) {
return 1;
}
}
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;

View File

@@ -1,72 +0,0 @@
# -*- 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) 2006
# the Initial Developer. All Rights Reserved.
#
# Contributor(s):
# Zach Lipton <zach@zachlipton.com>
#
# ***** 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;

View File

@@ -1,125 +0,0 @@
# -*- 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) 2006
# the Initial Developer. All Rights Reserved.
#
# Contributor(s):
# Chris Cooper <ccooper@deadsquid.com>
# Zach Lipton <zach@zachlipton.com>
#
# ***** END LICENSE BLOCK *****
=cut
package Litmus::Cache;
use strict;
use Litmus;
use Data::JavaScript;
use Litmus::DB::Product;
our @ISA = qw(Exporter);
@Litmus::Cache::EXPORT = qw(
rebuildCache
);
# generate a new litmusconfig.js file because something has updated:
sub rebuildCache {
unless (-e "data") { system("mkdir", "data") }
open(CACHE, ">data/litmusconfig.js.new");
print CACHE "// Litmus configuration information\n";
print CACHE "// Do not edit this file directly. It is autogenerated from the database\n";
print CACHE "\n";
# we build up @litmusconfig, a big perl data structure, and spit the
# 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 => 1);
my $prodcount = 0;
foreach my $curproduct (@products) {
my $prodrow = \%{$litmusconfig[$prodcount]};
$prodrow->{"name"} = $curproduct->name();
$prodrow->{"id"} = $curproduct->product_id();
my $brancharray = \@{$prodrow->{"branches"}};
my $branchcount = 0;
foreach my $curbranch ($curproduct->branches(enabled => 1)) {
my $branchrow = \%{$brancharray->[$branchcount]};
$branchrow->{"name"} = $curbranch->name();
$branchrow->{"id"} = $curbranch->branch_id();
$branchcount++;
}
my $platformarray = \@{$prodrow->{"platforms"}};
my $platformcount = 0;
foreach my $curplat (Litmus::DB::Platform->search_ByProduct($curproduct->product_id())) {
my $platrow = \%{$platformarray->[$platformcount]};
$platrow->{"name"} = $curplat->name();
$platrow->{"id"} = $curplat->platform_id();
my $opsysarray = \@{$platrow->{"opsyses"}};
my $opsyscount = 0;
foreach my $curopsys ($curplat->opsyses()) {
my $opsysrow = \%{$opsysarray->[$opsyscount]};
$opsysrow->{"name"} = $curopsys->name();
$opsysrow->{"id"} = $curopsys->opsys_id();
$opsyscount++;
}
$platformcount++;
}
my $grouparray = \@{$prodrow->{"testgroups"}};
my $groupcount = 0;
foreach my $curgroup ($curproduct->testgroups()) {
next if (!$curgroup->enabled);
my $grouprow = \%{$grouparray->[$groupcount]};
$grouprow->{"name"} = $curgroup->name();
$grouprow->{"id"} = $curgroup->testgroup_id();
$groupcount++;
my $subgrouparray = \@{$grouprow->{"subgroups"}};
my $subgroupcount = 0;
foreach my $cursubgroup (Litmus::DB::Subgroup->search_EnabledByTestgroup($curgroup->testgroup_id())) {
next if (!$cursubgroup->enabled);
my $subgrouprow = \%{$subgrouparray->[$subgroupcount]};
$subgrouprow->{"name"} = $cursubgroup->name();
$subgrouprow->{"id"} = $cursubgroup->subgroup_id();
$subgroupcount++;
}
}
$prodcount++;
}
my $data = jsdump('litmusconfig', \@litmusconfig);
$data =~ s/new Object;/new Array\(\);/g;
print CACHE $data;
close(CACHE);
system("mv", "data/litmusconfig.js.new", "data/litmusconfig.js");
#system("chmod", "-R", "755", "data/");
}
1;

View File

@@ -1,49 +0,0 @@
# -*- 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) 2006
# the Initial Developer. All Rights Reserved.
#
# Contributor(s):
# Chris Cooper <ccooper@deadsquid.com>
# Zach Lipton <zach@zachlipton.com>
#
# ***** END LICENSE BLOCK *****
=cut
package Litmus::Config;
use strict;
do 'localconfig';
our $version = "0.6";
# if true, then Litmus will not accept any requests
our $disabled = 0;
our $datadir = "data/";
# Set/unset this to display inline debugging value/code.
our $DEBUG = 0;
1;

View File

@@ -1,48 +0,0 @@
# -*- 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) 2006
# the Initial Developer. All Rights Reserved.
#
# Contributor(s):
# Chris Cooper <ccooper@deadsquid.com>
# Zach Lipton <zach@zachlipton.com>
#
# ***** END LICENSE BLOCK *****
=cut
package Litmus::DB::Branch;
use strict;
use base 'Litmus::DBI';
Litmus::DB::Branch->table('branches');
Litmus::DB::Branch->columns(All => qw/branch_id product_id name detect_regexp enabled/);
Litmus::DB::Branch->columns(Essential => qw/branch_id product_id name detect_regexp enabled/);
Litmus::DB::Branch->column_alias("product_id", "product");
Litmus::DB::Branch->has_many(test_results => "Litmus::DB::Testresult");
Litmus::DB::Branch->has_a(product => "Litmus::DB::Product");
1;

View File

@@ -1,44 +0,0 @@
# -*- 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) 2006
# the Initial Developer. All Rights Reserved.
#
# Contributor(s):
# Chris Cooper <ccooper@deadsquid.com>
# Zach Lipton <zach@zachlipton.com>
#
# ***** 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;

View File

@@ -1,44 +0,0 @@
# -*- 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) 2006
# the Initial Developer. All Rights Reserved.
#
# Contributor(s):
# Chris Cooper <ccooper@deadsquid.com>
# Zach Lipton <zach@zachlipton.com>
#
# ***** END LICENSE BLOCK *****
=cut
package Litmus::DB::BuildType;
use strict;
use base 'Litmus::DBI';
Litmus::DB::BuildType->table('build_type_lookup');
Litmus::DB::BuildType->columns(All => qw/build_type_id name/);
Litmus::DB::BuildType->has_many(test_results => "Litmus::DB::Testresult");
1;

View File

@@ -1,53 +0,0 @@
# -*- 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) 2006
# the Initial Developer. All Rights Reserved.
#
# Contributor(s):
# Chris Cooper <ccooper@deadsquid.com>
# Zach Lipton <zach@zachlipton.com>
#
# ***** END LICENSE BLOCK *****
=cut
package Litmus::DB::Comment;
use strict;
use base 'Litmus::DBI';
use Time::Piece;
Litmus::DB::Comment->table('test_result_comments');
Litmus::DB::Comment->columns(All => qw/comment_id test_result_id last_updated submission_time user_id comment/);
Litmus::DB::Comment->column_alias("test_result_id", "test_result");
Litmus::DB::Comment->column_alias("user_id", "user");
Litmus::DB::Comment->has_a(test_result => "Litmus::DB::Testresult");
Litmus::DB::Comment->has_a(user => "Litmus::DB::User");
Litmus::DB::Comment->autoinflate(dates => 'Time::Piece');
1;

View File

@@ -1,44 +0,0 @@
# -*- 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) 2006
# the Initial Developer. All Rights Reserved.
#
# Contributor(s):
# Chris Cooper <ccooper@deadsquid.com>
# Zach Lipton <zach@zachlipton.com>
#
# ***** END LICENSE BLOCK *****
=cut
package Litmus::DB::ExitStatus;
use strict;
use base 'Litmus::DBI';
Litmus::DB::ExitStatus->table('exit_status_lookup');
Litmus::DB::ExitStatus->columns(All => qw/exit_status_id name/);
Litmus::DB::ExitStatus->has_many(test_results => "Litmus::DB::Testresult");
1;

View File

@@ -1,46 +0,0 @@
# -*- 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) 2006
# the Initial Developer. All Rights Reserved.
#
# Contributor(s):
# Chris Cooper <ccooper@deadsquid.com>
# Zach Lipton <zach@zachlipton.com>
#
# ***** END LICENSE BLOCK *****
=cut
package Litmus::DB::Format;
use strict;
use base 'Litmus::DBI';
Litmus::DB::Format->table('test_format_lookup');
Litmus::DB::Format->columns(All => qw/format_id name/);
Litmus::DB::Format->column_alias("format_id", "formatid");
Litmus::DB::Format->has_many(testcases => "Litmus::DB::Testcase");
1;

View File

@@ -1,52 +0,0 @@
# -*- 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) 2006
# the Initial Developer. All Rights Reserved.
#
# Contributor(s):
# Chris Cooper <ccooper@deadsquid.com>
# Zach Lipton <zach@zachlipton.com>
#
# ***** END LICENSE BLOCK *****
=cut
package Litmus::DB::Locale;
use strict;
use base 'Litmus::DBI';
Litmus::DB::Locale->table('locale_lookup');
Litmus::DB::Locale->columns(All => qw/abbrev name/);
Litmus::DB::Locale->column_alias("abbrev", "locale");
Litmus::DB::Locale->has_many(test_results => "Litmus::DB::Testresult");
__PACKAGE__->set_sql(RetrieveAll => qq{
SELECT __ESSENTIAL__
FROM __TABLE__
ORDER BY abbrev ASC
});
1;

View File

@@ -1,50 +0,0 @@
# -*- 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) 2006
# the Initial Developer. All Rights Reserved.
#
# Contributor(s):
# Chris Cooper <ccooper@deadsquid.com>
# Zach Lipton <zach@zachlipton.com>
#
# ***** END LICENSE BLOCK *****
=cut
package Litmus::DB::Log;
use strict;
use base 'Litmus::DBI';
Litmus::DB::Log->table('test_result_logs');
Litmus::DB::Log->columns(All => qw/log_id last_updated submission_time log_type_id log_text/);
Litmus::DB::Log->column_alias("test_results", "testresults");
Litmus::DB::Log->column_alias("log_type_id", "log_type");
Litmus::DB::Log->has_a(log_type => "Litmus::DB::LogType");
Litmus::DB::Log->has_many(test_results => ["Litmus::DB::LogTestresult" => 'test_result']);
Litmus::DB::Testresult->autoinflate(dates => 'Time::Piece');
1;

View File

@@ -1,47 +0,0 @@
# -*- 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) 2006
# the Initial Developer. All Rights Reserved.
#
# Contributor(s):
# Chris Cooper <ccooper@deadsquid.com>
# Zach Lipton <zach@zachlipton.com>
#
# ***** END LICENSE BLOCK *****
=cut
package Litmus::DB::LogTestresult;
use strict;
use base 'Litmus::DBI';
Litmus::DB::LogTestresult->table('testresult_logs_join');
Litmus::DB::LogTestresult->columns(Primary => qw/test_result_id log_id/);
Litmus::DB::LogTestresult->column_alias("test_result_id", "test_result");
Litmus::DB::LogTestresult->has_a(test_result => "Litmus::DB::Testresult");
Litmus::DB::LogTestresult->has_a(log_id => "Litmus::DB::Log");
1;

View File

@@ -1,44 +0,0 @@
# -*- 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) 2006
# the Initial Developer. All Rights Reserved.
#
# Contributor(s):
# Chris Cooper <ccooper@deadsquid.com>
# Zach Lipton <zach@zachlipton.com>
#
# ***** END LICENSE BLOCK *****
=cut
package Litmus::DB::LogType;
use strict;
use base 'Litmus::DBI';
Litmus::DB::LogType->table('log_type_lookup');
Litmus::DB::LogType->columns(All => qw/log_type_id name/);
Litmus::DB::LogType->has_many(test_result_logs => "Litmus::DB::Log");
1;

View File

@@ -1,48 +0,0 @@
# -*- 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) 2006
# the Initial Developer. All Rights Reserved.
#
# Contributor(s):
# Chris Cooper <ccooper@deadsquid.com>
# Zach Lipton <zach@zachlipton.com>
#
# ***** END LICENSE BLOCK *****
=cut
package Litmus::DB::Opsys;
use strict;
use base 'Litmus::DBI';
Litmus::DB::Opsys->table('opsyses');
Litmus::DB::Opsys->columns(All => qw/opsys_id platform_id name detect_regexp/);
Litmus::DB::Opsys->columns(Essential => qw/opsys_id platform_id name detect_regexp/);
Litmus::DB::Opsys->column_alias("platform_id", "platform");
Litmus::DB::Opsys->has_many(test_results => "Litmus::DB::Testresult");
Litmus::DB::Opsys->has_a(platform => "Litmus::DB::Platform");
1;

View File

@@ -1,105 +0,0 @@
# -*- 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) 2006
# the Initial Developer. All Rights Reserved.
#
# Contributor(s):
# Chris Cooper <ccooper@deadsquid.com>
# Zach Lipton <zach@zachlipton.com>
#
# ***** END LICENSE BLOCK *****
=cut
package Litmus::DB::Platform;
use strict;
use base 'Litmus::DBI';
use CGI;
Litmus::DB::Platform->table('platforms');
Litmus::DB::Platform->columns(All => qw/platform_id name detect_regexp iconpath/);
Litmus::DB::Platform->columns(Essential => qw/platform_id name detect_regexp iconpath/);
Litmus::DB::Platform->column_alias("platform_id", "platformid");
Litmus::DB::Platform->has_many(opsyses => "Litmus::DB::Opsys");
Litmus::DB::Platform->set_sql(ByProduct => qq{
SELECT pl.*
FROM platforms pl, platform_products plpr
WHERE plpr.product_id=? AND plpr.platform_id=pl.platform_id
});
Litmus::DB::Platform->set_sql(ByProductAndName => qq{
SELECT pl.*
FROM platforms pl, platform_products plpr
WHERE plpr.product_id=? AND plpr.platform_id=pl.platform_id
AND pl.name=?
});
#########################################################################
sub delete_from_products() {
my $self = shift;
my $dbh = __PACKAGE__->db_Main();
my $sql = "DELETE from platform_products WHERE platform_id=?";
my $rows = $dbh->do($sql,
undef,
$self->platform_id
);
}
#########################################################################
sub delete_with_refs() {
my $self = shift;
$self->delete_from_products();
# XXX: How to handle opsyses?
return $self->delete;
}
#########################################################################
sub update_products() {
my $self = shift;
my $new_product_ids = shift;
if (scalar @$new_product_ids) {
# Failing to delete products is _not_ fatal when adding a new subgroup.
my $rv = $self->delete_from_products();
my $dbh = __PACKAGE__->db_Main();
my $sql = "INSERT INTO platform_products (platform_id,product_id) VALUES (?,?)";
foreach my $new_product_id (@$new_product_ids) {
my $rows = $dbh->do($sql,
undef,
$self->platform_id,
$new_product_id
);
}
}
}
1;

View File

@@ -1,108 +0,0 @@
# -*- 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) 2006
# the Initial Developer. All Rights Reserved.
#
# Contributor(s):
# Chris Cooper <ccooper@deadsquid.com>
# Zach Lipton <zach@zachlipton.com>
#
# ***** END LICENSE BLOCK *****
=cut
package Litmus::DB::Product;
use strict;
use base 'Litmus::DBI';
Litmus::DB::Product->table('products');
Litmus::DB::Product->columns(All => qw/product_id name iconpath enabled/);
Litmus::DB::Product->columns(Essential => qw/product_id name iconpath enabled/);
Litmus::DB::Product->column_alias("product_id", "productid");
Litmus::DB::Product->has_many(testcases => "Litmus::DB::Testcase",
{ order_by => 'testcase_id' });
Litmus::DB::Product->has_many(subgroups => "Litmus::DB::Subgroup",
{ order_by => 'name' });
Litmus::DB::Product->has_many(testgroups => "Litmus::DB::Testgroup",
{ order_by => 'name' });
Litmus::DB::Product->has_many(branches => "Litmus::DB::Branch",
{ order_by => 'name' });
__PACKAGE__->set_sql(ByPlatform => qq{
SELECT pr.*
FROM products pr, platform_products plpr
WHERE plpr.platform_id=? AND plpr.product_id=pr.product_id
ORDER BY pr.name ASC
});
#########################################################################
sub delete_from_platforms() {
my $self = shift;
my $dbh = __PACKAGE__->db_Main();
my $sql = "DELETE from platform_products WHERE product_id=?";
my $rows = $dbh->do($sql,
undef,
$self->product_id
);
}
#########################################################################
sub delete_with_refs() {
my $self = shift;
$self->delete_from_platforms();
my $dbh = __PACKAGE__->db_Main();
my $sql = "UPDATE testgroups SET product_id=0,enabled=0 WHERE product_id=?";
my $rows = $dbh->do($sql,
undef,
$self->product_id
);
# Remove references to product in other entities.
# Disable those entities for good measure.
$sql = "UPDATE subgroups SET product_id=0,enabled=0 WHERE product_id=?";
$rows = $dbh->do($sql,
undef,
$self->product_id
);
$sql = "UPDATE testcases SET product_id=0,enabled=0,community_enabled=0 WHERE product_id=?";
$rows = $dbh->do($sql,
undef,
$self->product_id
);
$sql = "UPDATE branches SET product_id=0,enabled=0 WHERE product_id=?";
$rows = $dbh->do($sql,
undef,
$self->product_id
);
return $self->delete;
}
1;

View File

@@ -1,44 +0,0 @@
# -*- 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) 2006
# the Initial Developer. All Rights Reserved.
#
# Contributor(s):
# Chris Cooper <ccooper@deadsquid.com>
# Zach Lipton <zach@zachlipton.com>
#
# ***** END LICENSE BLOCK *****
=cut
package Litmus::DB::ResultStatus;
use strict;
use base 'Litmus::DBI';
Litmus::DB::ResultStatus->table('test_result_status_lookup');
Litmus::DB::ResultStatus->columns(All => qw/result_status_id name class_name/);
Litmus::DB::ResultStatus->has_many(test_results => "Litmus::DB::Testresult");
1;

View File

@@ -1,54 +0,0 @@
# -*- 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) 2006
# the Initial Developer. All Rights Reserved.
#
# Contributor(s):
# Chris Cooper <ccooper@deadsquid.com>
# Zach Lipton <zach@zachlipton.com>
#
# ***** END LICENSE BLOCK *****
=cut
package Litmus::DB::Resultbug;
use strict;
use base 'Litmus::DBI';
use Time::Piece;
Litmus::DB::Resultbug->table('test_result_bugs');
Litmus::DB::Resultbug->columns(Primary => qw/test_result_id bug_id/);
Litmus::DB::Resultbug->columns(All => qw/last_updated submission_time user_id/);
Litmus::DB::Resultbug->column_alias("test_result_id", "test_result");
Litmus::DB::Resultbug->column_alias("test_result_id", "testresult");
Litmus::DB::Resultbug->column_alias("user_id", "user");
Litmus::DB::Resultbug->has_a(test_result => "Litmus::DB::Testresult");
Litmus::DB::Resultbug->has_a(user => "Litmus::DB::User");
Litmus::DB::Resultbug->autoinflate(dates => 'Time::Piece');
1;

View File

@@ -1,69 +0,0 @@
# -*- 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) 2006
# the Initial Developer. All Rights Reserved.
#
# Contributor(s):
# Chris Cooper <ccooper@deadsquid.com>
# Zach Lipton <zach@zachlipton.com>
#
# ***** 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()->enabled() || $self->user_id()->enabled() == 0) {
$self->makeExpire();
return 0;
}
return 1;
}
1;

View File

@@ -1,306 +0,0 @@
# -*- 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) 2006
# the Initial Developer. All Rights Reserved.
#
# Contributor(s):
# Chris Cooper <ccooper@deadsquid.com>
# Zach Lipton <zach@zachlipton.com>
#
# ***** END LICENSE BLOCK *****
=cut
package Litmus::DB::Subgroup;
use strict;
use base 'Litmus::DBI';
use Time::Piece::MySQL;
#use Litmus::DB::Testresult;
Litmus::DB::Subgroup->table('subgroups');
Litmus::DB::Subgroup->columns(All => qw/subgroup_id name testrunner_group_id enabled product_id/);
Litmus::DB::Subgroup->columns(Essential => qw/subgroup_id name testrunner_group_id enabled product_id/);
Litmus::DB::Subgroup->column_alias("subgroup_id", "subgroupid");
Litmus::DB::Subgroup->has_a(product => "Litmus::DB::Product");
__PACKAGE__->set_sql(EnabledByTestgroup => qq{
SELECT sg.*
FROM subgroups sg, subgroup_testgroups sgtg
WHERE sgtg.testgroup_id=? AND sgtg.subgroup_id=sg.subgroup_id AND sg.enabled=1
ORDER BY sgtg.sort_order ASC
});
__PACKAGE__->set_sql(ByTestgroup => qq{
SELECT sg.*
FROM subgroups sg, subgroup_testgroups sgtg
WHERE sgtg.testgroup_id=? AND sgtg.subgroup_id=sg.subgroup_id
ORDER BY sgtg.sort_order ASC
});
__PACKAGE__->set_sql(NumEnabledTestcases => qq{
SELECT count(tc.testcase_id) as num_testcases
FROM testcases tc, testcase_subgroups tcsg
WHERE tcsg.subgroup_id=? AND tcsg.testcase_id=tc.testcase_id AND tc.enabled=1 AND tc.community_enabled=1
});
__PACKAGE__->set_sql(EnabledByTestcase => qq{
SELECT sg.*
FROM subgroups sg, testcase_subgroups tcsg
WHERE tcsg.testcase_id=? AND tcsg.subgroup_id=sg.subgroup_id AND sg.enabled=1
ORDER by sg.name ASC
});
__PACKAGE__->set_sql(ByTestcase => qq{
SELECT sg.*
FROM subgroups sg, testcase_subgroups tcsg
WHERE tcsg.testcase_id=? AND tcsg.subgroup_id=sg.subgroup_id
ORDER by sg.name ASC
});
#########################################################################
sub coverage() {
my $self = shift;
my $platform = shift;
my $build_id = shift;
my $locale = shift;
my $community_only = shift;
my $user = shift;
my $sql = "SELECT COUNT(t.testcase_id) FROM testcase_subgroups tsg, testcases t WHERE tsg.subgroup_id=? AND tsg.testcase_id=t.testcase_id AND t.enabled=1";
if ($community_only) {
$sql .= " AND t.community_enabled=1";
}
my $dbh = $self->db_Main();
my $sth = $dbh->prepare_cached($sql);
$sth->execute(
$self->{'subgroup_id'},
);
my ($num_testcases) = $sth->fetchrow_array;
$sth->finish;
if (!$num_testcases or
$num_testcases == 0) { return "N/A" }
$sql = "SELECT t.testcase_id, count(tr.testresult_id) AS num_results
FROM testcase_subgroups tsg JOIN testcases t ON (tsg.testcase_id=t.testcase_id) LEFT JOIN test_results tr ON (tr.testcase_id=t.testcase_id) JOIN opsyses o ON (tr.opsys_id=o.opsys_id)
WHERE tsg.subgroup_id=? AND tr.build_id=? AND tr.locale_abbrev=? AND o.platform_id=?";
if ($community_only) {
$sql .= " AND t.community_enabled=1";
}
if ($user) {
$sql .= " AND tr.user_id=" . $user->{'user_id'};
}
$sql .= " GROUP BY tr.testcase_id";
$sth = $dbh->prepare_cached($sql);
$sth->execute(
$self->{'subgroup_id'},
$build_id,
$locale,
$platform->{'platform_id'}
);
my @test_results = $self->sth_to_objects($sth);
$sth->finish;
if (@test_results == 0) { return "0" }
my $num_completed = 0;
foreach my $curtest (@test_results) {
if ($curtest->{'num_results'} > 0) {
$num_completed++;
}
}
my $result = $num_completed/($num_testcases) * 100;
unless ($result) {
return "0";
}
return sprintf("%d",$result);
}
#########################################################################
sub clone() {
my $self = shift;
my $new_subgroup = $self->copy;
if (!$new_subgroup) {
return undef;
}
# Propagate testgroup membership;
my $dbh = __PACKAGE__->db_Main();
my $sql = "INSERT INTO subgroup_testgroups (subgroup_id,testgroup_id,sort_order) SELECT ?,testgroup_id,sort_order FROM subgroup_testgroups WHERE subgroup_id=?";
my $rows = $dbh->do($sql,
undef,
$new_subgroup->subgroup_id,
$self->subgroup_id
);
if (! $rows) {
# XXX: Do we need to throw a warning here?
# What happens when we clone a subgroup that doesn't belong to
# any testgroups?
}
$sql = "INSERT INTO testcase_subgroups (testcase_id,subgroup_id,sort_order) SELECT testcase_id,?,sort_order FROM testcase_subgroups WHERE subgroup_id=?";
$rows = $dbh->do($sql,
undef,
$new_subgroup->subgroup_id,
$self->subgroup_id
);
if (! $rows) {
# XXX: Do we need to throw a warning here?
}
return $new_subgroup;
}
#########################################################################
sub delete_from_testgroups() {
my $self = shift;
my $dbh = __PACKAGE__->db_Main();
my $sql = "DELETE from subgroup_testgroups WHERE subgroup_id=?";
return $dbh->do($sql,
undef,
$self->subgroup_id
);
}
#########################################################################
sub delete_from_testgroup() {
my $self = shift;
my $testgroup_id = shift;
my $dbh = __PACKAGE__->db_Main();
my $sql = "DELETE from subgroup_testgroups WHERE subgroup_id=? AND testgroup_id=?";
return $dbh->do($sql,
undef,
$self->subgroup_id,
$testgroup_id
);
}
#########################################################################
sub delete_from_testcases() {
my $self = shift;
my $dbh = __PACKAGE__->db_Main();
my $sql = "DELETE from testcase_subgroups WHERE subgroup_id=?";
return $dbh->do($sql,
undef,
$self->subgroup_id
);
}
#########################################################################
sub delete_with_refs() {
my $self = shift;
$self->delete_from_testgroups();
$self->delete_from_testcases();
return $self->delete;
}
#########################################################################
sub update_testgroups() {
my $self = shift;
my $new_testgroup_ids = shift;
if (scalar @$new_testgroup_ids) {
# Failing to delete testgroups is _not_ fatal when adding a new subgroup.
my $rv = $self->delete_from_testgroups();
my $dbh = __PACKAGE__->db_Main();
my $sql = "INSERT INTO subgroup_testgroups (subgroup_id,testgroup_id,sort_order) VALUES (?,?,1)";
foreach my $new_testgroup_id (@$new_testgroup_ids) {
my $rows = $dbh->do($sql,
undef,
$self->subgroup_id,
$new_testgroup_id
);
}
}
}
#########################################################################
sub update_testgroup() {
my $self = shift;
my $testgroup_id = shift;
my $sort_order = shift;
# Sort order defaults to 1.
if (!$sort_order) {
$sort_order = 1;
}
my $rv = $self->delete_from_testgroup($testgroup_id);
my $dbh = __PACKAGE__->db_Main();
my $sql = "INSERT INTO subgroup_testgroups (subgroup_id,testgroup_id,sort_order) VALUES (?,?,?)";
return $dbh->do($sql,
undef,
$self->subgroup_id,
$testgroup_id,
$sort_order
);
}
#########################################################################
sub update_testcases() {
my $self = shift;
my $new_testcase_ids = shift;
if (scalar @$new_testcase_ids) {
# Failing to delete testcases is _not_ fatal when adding a new subgroup.
my $rv = $self->delete_from_testcases();
my $dbh = __PACKAGE__->db_Main();
my $sql = "INSERT INTO testcase_subgroups (testcase_id,subgroup_id,sort_order) VALUES (?,?,?)";
my $sort_order = 1;
foreach my $new_testcase_id (@$new_testcase_ids) {
next if (!$new_testcase_id);
# Log any failures/duplicate keys to STDERR.
eval {
my $rows = $dbh->do($sql,
undef,
$new_testcase_id,
$self->subgroup_id,
$sort_order
);
};
if ($@) {
print STDERR $@;
}
$sort_order++;
}
}
}
1;

View File

@@ -1,61 +0,0 @@
# -*- 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) 2006
# the Initial Developer. All Rights Reserved.
#
# Contributor(s):
# Chris Cooper <ccooper@deadsquid.com>
# Zach Lipton <zach@zachlipton.com>
#
# ***** END LICENSE BLOCK *****
=cut
package Litmus::DB::TestRun;
use strict;
use base 'Litmus::DBI';
use Time::Piece;
use Time::Seconds;
Litmus::DB::TestRun->table('test_runs');
Litmus::DB::TestRun->columns(All => qw/test_run_id testgroup_id name description start_timestamp finish_timestamp enabled/);
Litmus::DB::TestRun->column_alias("testgroup_id", "testgroup");
Litmus::DB::TestRun->has_a(testgroup => "Litmus::DB::Testgroup");
Litmus::DB::TestRun->has_many(subgroups =>
[ "Litmus::DB::SubgroupTestgroup" => "testgroup" ]);
Litmus::DB::TestRun->autoinflate(dates => 'Time::Piece');
1;

View File

@@ -1,377 +0,0 @@
# -*- 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) 2006
# the Initial Developer. All Rights Reserved.
#
# Contributor(s):
# Chris Cooper <ccooper@deadsquid.com>
# Zach Lipton <zach@zachlipton.com>
#
# ***** END LICENSE BLOCK *****
=cut
package Litmus::DB::Testcase;
use strict;
use base 'Litmus::DBI';
use Date::Manip;
#use Litmus::DB::Testresult;
use Memoize;
#use Litmus::Error;
our $default_relevance_threshold = 1.0;
our $default_match_limit = 25;
our $default_num_days = 7;
Litmus::DB::Testcase->table('testcases');
Litmus::DB::Testcase->columns(Primary => qw/testcase_id/);
Litmus::DB::Testcase->columns(Essential => qw/summary details enabled community_enabled format_id regression_bug_id product_id steps expected_results author_id creation_date last_updated version testrunner_case_id testrunner_case_version/);
Litmus::DB::Testcase->column_alias("testcase_id", "testid");
Litmus::DB::Testcase->column_alias("testcase_id", "test_id");
Litmus::DB::Testcase->column_alias("testcase_id", "id");
Litmus::DB::Testcase->column_alias("community_enabled", "communityenabled");
Litmus::DB::Testcase->column_alias("format_id", "format");
Litmus::DB::Testcase->column_alias("author_id", "author");
Litmus::DB::Testcase->column_alias("product_id", "product");
Litmus::DB::Testcase->has_a("format" => "Litmus::DB::Format");
Litmus::DB::Testcase->has_a("author" => "Litmus::DB::User");
Litmus::DB::Testcase->has_a("product" => "Litmus::DB::Product");
__PACKAGE__->set_sql(EnabledBySubgroup => qq{
SELECT t.*
FROM testcases t, testcase_subgroups tsg
WHERE tsg.subgroup_id=? AND tsg.testcase_id=t.testcase_id AND t.enabled=1
ORDER BY tsg.sort_order ASC
});
__PACKAGE__->set_sql(BySubgroup => qq{
SELECT t.*
FROM testcases t, testcase_subgroups tsg
WHERE
tsg.subgroup_id=? AND
tsg.testcase_id=t.testcase_id
ORDER BY tsg.sort_order ASC
});
__PACKAGE__->set_sql(ByTestgroup => qq{
SELECT t.*
FROM testcases t, testcase_subgroups tsg, subgroup_testgroups sgtg
WHERE
tsg.testcase_id=t.testcase_id AND
tsg.subgroup_id=sgtg.subgroup_id AND
sgtg.testgroup_id = ?
ORDER BY tsg.sort_order ASC
});
__PACKAGE__->set_sql(CommunityEnabledBySubgroup => qq{
SELECT t.*
FROM testcases t, testcase_subgroups tsg
WHERE tsg.subgroup_id=? AND tsg.testcase_id=t.testcase_id AND t.enabled=1 AND t.community_enabled=1
ORDER BY tsg.sort_order ASC, t.testcase_id ASC
});
Litmus::DB::Testcase->has_many(test_results => "Litmus::DB::Testresult", {order_by => 'submission_time DESC'});
Litmus::DB::Testcase->has_many(subgroups =>
["Litmus::DB::TestcaseSubgroup" => 'subgroup']);
#########################################################################
# is_completed($$$$$)
#
# Check whether we have test results for the current test that correspond
# to the provided platform, build_id, and user(optional).
#########################################################################
memoize('is_completed');
sub is_completed {
my $self = shift;
my $platform = shift;
my $build_id = shift;
my $locale = shift;
my $user = shift; # optional
my @results;
if ($user) {
@results = Litmus::DB::Testresult->search_CompletedByUser(
$self->{'testcase_id'},
$build_id,
$locale->{'abbrev'},
$platform->{'platform_id'},
$user->{'user_id'},
);
} else {
@results = Litmus::DB::Testresult->search_Completed(
$self->{'testcase_id'},
$build_id,
$locale->{'abbrev'},
$platform->{'platform_id'},
);
}
return @results;
}
#########################################################################
sub getFullTextMatches() {
my $self = shift;
my $text_snippet = shift;
my $match_limit = shift;
my $relevance_threshold = shift;
if (!$match_limit) {
$match_limit = $default_match_limit;
}
if (!$relevance_threshold) {
$relevance_threshold = $default_relevance_threshold
}
__PACKAGE__->set_sql(FullTextMatches => qq{
SELECT testcase_id, summary, creation_date, last_updated, MATCH (summary,steps,expected_results) AGAINST (?) AS relevance
FROM testcases
WHERE MATCH (summary,steps,expected_results) AGAINST (?) HAVING relevance > ?
ORDER BY relevance DESC, summary ASC
LIMIT $match_limit
});
return $self->search_FullTextMatches(
$text_snippet,
$text_snippet,
$relevance_threshold
);
}
#########################################################################
sub getNewTestcases() {
my $self = shift;
my $num_days = shift;
my $match_limit = shift;
if (!$num_days) {
$num_days = $default_num_days;
}
if (!$match_limit) {
$match_limit = $default_match_limit;
}
__PACKAGE__->set_sql(NewTestcases => qq{
SELECT testcase_id, summary, creation_date, last_updated
FROM testcases
WHERE creation_date>=?
ORDER BY creation_date DESC
LIMIT $match_limit
});
my $err;
my $new_datestamp=&UnixDate(DateCalc("now","- $num_days days"),"%q");
return $self->search_NewTestcases($new_datestamp);
}
#########################################################################
sub getRecentlyUpdated() {
my $self = shift;
my $num_days = shift;
my $match_limit = shift;
if (!$num_days) {
$num_days = $default_num_days;
}
if (!$match_limit) {
$match_limit = $default_match_limit;
}
__PACKAGE__->set_sql(RecentlyUpdated => qq{
SELECT testcase_id, summary, creation_date, last_updated
FROM testcases
WHERE last_updated>=? AND last_updated>creation_date
ORDER BY last_updated DESC
LIMIT $match_limit
});
my $err;
my $new_datestamp=&UnixDate(DateCalc("now","- $num_days days"),"%q");
return $self->search_RecentlyUpdated($new_datestamp);
}
#########################################################################
sub getDefaultMatchLimit() {
return $default_match_limit;
}
#########################################################################
sub getDefaultRelevanceThreshold() {
return $default_relevance_threshold;
}
#########################################################################
sub getDefaultNumDays() {
return $default_num_days;
}
#########################################################################
sub clone() {
my $self = shift;
my $new_testcase = $self->copy;
if (!$new_testcase) {
return undef;
}
# Update dates to now.
my $now = &UnixDate("today","%q");
$new_testcase->creation_date($now);
$new_testcase->last_updated($now);
$new_testcase->update();
# Propagate subgroup membership;
my $dbh = __PACKAGE__->db_Main();
my $sql = "INSERT INTO testcase_subgroups (testcase_id,subgroup_id,sort_order) SELECT ?,subgroup_id,sort_order FROM testcase_subgroups WHERE testcase_id=?";
my $rows = $dbh->do($sql,
undef,
$new_testcase->testcase_id,
$self->testcase_id
);
if (! $rows) {
# XXX: Do we need to throw a warning here?
# What happens when we clone a testcase that doesn't belong to
# any subgroups?
}
$sql = "INSERT INTO related_testcases (testcase_id, related_testcase_id) VALUES (?,?)";
$rows = $dbh->do($sql,
undef,
$self->testcase_id,
$new_testcase->testcase_id
);
if (! $rows) {
# XXX: Do we need to throw a warning here?
}
return $new_testcase;
}
#########################################################################
sub delete_from_subgroups() {
my $self = shift;
my $dbh = __PACKAGE__->db_Main();
my $sql = "DELETE from testcase_subgroups WHERE testcase_id=?";
return $dbh->do($sql,
undef,
$self->testcase_id
);
}
#########################################################################
sub delete_from_subgroup() {
my $self = shift;
my $subgroup_id = shift;
my $dbh = __PACKAGE__->db_Main();
my $sql = "DELETE from testcase_subgroups WHERE testcase_id=? AND subgroup_id=?";
return $dbh->do($sql,
undef,
$self->testcase_id,
$subgroup_id
);
}
#########################################################################
sub delete_from_related() {
my $self = shift;
my $dbh = __PACKAGE__->db_Main();
my $sql = "DELETE from related_testcases WHERE testcase_id=? OR related_testcase_id=?";
return $dbh->do($sql,
undef,
$self->testcase_id,
$self->testcase_id
);
}
#########################################################################
sub delete_with_refs() {
my $self = shift;
$self->delete_from_subgroups();
$self->delete_from_related();
return $self->delete;
}
#########################################################################
sub update_subgroups() {
my $self = shift;
my $new_subgroup_ids = shift;
if (scalar @$new_subgroup_ids) {
# Failing to delete subgroups is _not_ fatal when adding a new testcase.
my $rv = $self->delete_from_subgroups();
my $dbh = __PACKAGE__->db_Main();
my $sql = "INSERT INTO testcase_subgroups (testcase_id,subgroup_id,sort_order) VALUES (?,?,1)";
foreach my $new_subgroup_id (@$new_subgroup_ids) {
my $rows = $dbh->do($sql,
undef,
$self->testcase_id,
$new_subgroup_id
);
}
}
}
#########################################################################
sub update_subgroup() {
my $self = shift;
my $subgroup_id = shift;
my $sort_order = shift;
# Sort order defaults to 1.
if (!$sort_order) {
$sort_order = 1;
}
my $rv = $self->delete_from_subgroup($subgroup_id);
my $dbh = __PACKAGE__->db_Main();
my $sql = "INSERT INTO testcase_subgroups (testcase_id,subgroup_id,sort_order) VALUES (?,?,?)";
return $dbh->do($sql,
undef,
$self->testcase_id,
$subgroup_id,
$sort_order
);
}
1;

View File

@@ -1,49 +0,0 @@
# -*- 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) 2006
# the Initial Developer. All Rights Reserved.
#
# Contributor(s):
# Chris Cooper <ccooper@deadsquid.com>
# Zach Lipton <zach@zachlipton.com>
#
# ***** END LICENSE BLOCK *****
=cut
package Litmus::DB::TestcaseSubgroup;
use strict;
use base 'Litmus::DBI';
Litmus::DB::TestcaseSubgroup->table('testcase_subgroups');
Litmus::DB::TestcaseSubgroup->columns(All => qw/testcase_id subgroup_id/);
Litmus::DB::TestcaseSubgroup->has_a(testcase_id => "Litmus::DB::Testcase");
Litmus::DB::TestcaseSubgroup->has_a(subgroup_id => "Litmus::DB::Subgroup");
Litmus::DB::TestcaseSubgroup->column_alias("testcase_id", "testcase");
Litmus::DB::TestcaseSubgroup->column_alias("testcase_id", "test");
Litmus::DB::TestcaseSubgroup->column_alias("subgroup_id", "subgroup");
1;

View File

@@ -1,260 +0,0 @@
# -*- 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) 2006
# the Initial Developer. All Rights Reserved.
#
# Contributor(s):
# Chris Cooper <ccooper@deadsquid.com>
# Zach Lipton <zach@zachlipton.com>
#
# ***** END LICENSE BLOCK *****
=cut
package Litmus::DB::Testgroup;
use strict;
use base 'Litmus::DBI';
Litmus::DB::Testgroup->table('testgroups');
Litmus::DB::Testgroup->columns(All => qw/testgroup_id product_id name enabled testrunner_plan_id/);
Litmus::DB::Testgroup->columns(Essential => qw/testgroup_id product_id name enabled testrunner_plan_id/);
Litmus::DB::Testgroup->column_alias("product_id", "product");
Litmus::DB::Testgroup->has_a(product => "Litmus::DB::Product");
__PACKAGE__->set_sql(EnabledByBranch => qq{
SELECT tg.*
FROM testgroups tg, testgroup_branches tgb
WHERE tgb.branch_id=? AND tgb.testgroup_id=tg.testgroup_id AND tg.enabled=1 ORDER by tg.name ASC
});
__PACKAGE__->set_sql(ByBranch => qq{
SELECT tg.*
FROM testgroups tg, testgroup_branches tgb
WHERE tgb.branch_id=? AND tgb.testgroup_id=tg.testgroup_id ORDER by tg.name ASC
});
__PACKAGE__->set_sql(EnabledBySubgroup => qq{
SELECT tg.*
FROM testgroups tg, subgroup_testgroups sgtg
WHERE sgtg.subgroup_id=? AND sgtg.testgroup_id=tg.testgroup_id AND tg.enabled=1 ORDER by tg.name ASC
});
__PACKAGE__->set_sql(BySubgroup => qq{
SELECT tg.*
FROM testgroups tg, subgroup_testgroups sgtg
WHERE sgtg.subgroup_id=? AND sgtg.testgroup_id=tg.testgroup_id ORDER by tg.name ASC
});
__PACKAGE__->set_sql(EnabledByTestcase => qq{
SELECT tg.*
FROM testgroups tg, subgroup_testgroups sgtg, testcase_subgroups tcsg
WHERE tcsg.testcase_id=? AND tcsg.subgroup_id=sgtg.subgroup_id AND sgtg.testgroup_id=tg.testgroup_id AND tg.enabled=1 ORDER by tg.name ASC
});
__PACKAGE__->set_sql(ByTestcase => qq{
SELECT tg.*
FROM testgroups tg, subgroup_testgroups sgtg, testcase_subgroups tcsg
WHERE tcsg.testcase_id=? AND tcsg.subgroup_id=sgtg.subgroup_id AND sgtg.testgroup_id=tg.testgroup_id ORDER by tg.name ASC
});
#########################################################################
sub coverage {
my $self = shift;
my $platform = shift;
my $build_id = shift;
my $locale = shift;
my $community_only = shift;
my $user = shift;
my $percent_completed = 0;
my @subgroups = Litmus::DB::Subgroup->search_EnabledByTestgroup($self->testgroup_id);
my $num_empty_subgroups = 0;
foreach my $subgroup (@subgroups) {
my $subgroup_percent = $subgroup->coverage(
$platform,
$build_id,
$locale,
$community_only,
$user,
);
if ($subgroup_percent eq "N/A") {
$num_empty_subgroups++;
} else {
$percent_completed += $subgroup_percent;
}
}
if (scalar(@subgroups) - $num_empty_subgroups == 0) {
return "N/A"
}
my $total_percentage = $percent_completed /
(scalar @subgroups - $num_empty_subgroups);
return sprintf("%d",$total_percentage);
}
#########################################################################
sub clone() {
my $self = shift;
my $new_testgroup = $self->copy;
if (!$new_testgroup) {
return undef;
}
# Propagate testgroup membership;
my $dbh = __PACKAGE__->db_Main();
my $sql = "INSERT INTO subgroup_testgroups (subgroup_id,testgroup_id,sort_order) SELECT subgroup_id,?,sort_order FROM subgroup_testgroups WHERE testgroup_id=?";
my $rows = $dbh->do($sql,
undef,
$new_testgroup->testgroup_id,
$self->testgroup_id
);
if (! $rows) {
# XXX: Do we need to throw a warning here?
}
return $new_testgroup;
}
#########################################################################
sub delete_from_subgroups() {
my $self = shift;
my $dbh = __PACKAGE__->db_Main();
my $sql = "DELETE from subgroup_testgroups WHERE testgroup_id=?";
my $rows = $dbh->do($sql,
undef,
$self->testgroup_id
);
}
#########################################################################
sub delete_from_test_runs() {
my $self = shift;
# XXX: Placeholder for test runs.
return;
}
#########################################################################
sub delete_with_refs() {
my $self = shift;
$self->delete_from_subgroups();
$self->delete_from_test_runs();
return $self->delete;
}
#########################################################################
sub update_subgroups() {
my $self = shift;
my $new_subgroup_ids = shift;
if (scalar @$new_subgroup_ids) {
# Failing to delete subgroups is _not_ fatal when adding a new testgroup.
my $rv = $self->delete_from_subgroups();
my $dbh = __PACKAGE__->db_Main();
my $sql = "INSERT INTO subgroup_testgroups (subgroup_id,testgroup_id,sort_order) VALUES (?,?,?)";
my $sort_order = 1;
foreach my $new_subgroup_id (@$new_subgroup_ids) {
next if (!$new_subgroup_id);
# Log any failures/duplicate keys to STDERR.
eval {
my $rows = $dbh->do($sql,
undef,
$new_subgroup_id,
$self->testgroup_id,
$sort_order
);
};
if ($@) {
print STDERR $@;
}
$sort_order++;
}
}
}
#########################################################################
sub update_branches() {
my $self = shift;
my $new_branch_ids = shift;
if (scalar @$new_branch_ids) {
# Failing to delete branches is _not_ fatal when adding a new testgroup.
my $rv = $self->delete_from_branches();
my $dbh = __PACKAGE__->db_Main();
my $sql = "INSERT INTO testgroup_branches (testgroup_id,branch_id) VALUES (?,?)";
foreach my $new_branch_id (@$new_branch_ids) {
next if (!$new_branch_id);
# Log any failures/duplicate keys to STDERR.
eval {
my $rows = $dbh->do($sql,
undef,
$self->testgroup_id,
$new_branch_id,
);
};
if ($@) {
print STDERR $@;
}
}
}
}
#########################################################################
sub add_branch() {
my $self = shift;
my $new_branch_id = shift;
# Failure to insert isn't fatal in the case of a collision, but we do want
# to log it.
my $dbh = __PACKAGE__->db_Main();
my $sql = "INSERT INTO testgroup_branches (testgroup_id,branch_id) VALUES (?,?)";
# Log any failures/duplicate keys to STDERR.
eval {
my $rows = $dbh->do($sql,
undef,
$self->testgroup_id,
$new_branch_id,
);
};
if ($@) {
print STDERR $@;
}
}
1;

View File

@@ -1,390 +0,0 @@
# -*- 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) 2006
# the Initial Developer. All Rights Reserved.
#
# Contributor(s):
# Chris Cooper <ccooper@deadsquid.com>
# Zach Lipton <zach@zachlipton.com>
#
# ***** END LICENSE BLOCK *****
=cut
package Litmus::DB::Testresult;
use strict;
use base 'Litmus::DBI';
use Date::Manip;
use Time::Piece;
use Time::Seconds;
use Memoize;
our $_num_results_default = 15;
Litmus::DB::Testresult->table('test_results');
Litmus::DB::Testresult->columns(All => qw/testresult_id testcase_id last_updated submission_time user_id opsys_id branch_id build_id user_agent result_status_id build_type_id machine_name exit_status_id duration_ms talkback_id valid vetted validated_by_user_id vetted_by_user_id validated_timestamp vetted_timestamp locale_abbrev is_automated_result/);
Litmus::DB::Testresult->column_alias("testcase_id", "testcase");
Litmus::DB::Testresult->column_alias("submission_time", "timestamp");
Litmus::DB::Testresult->column_alias("user_id", "user");
Litmus::DB::Testresult->column_alias("opsys_id", "opsys");
Litmus::DB::Testresult->column_alias("branch_id", "branch");
Litmus::DB::Testresult->column_alias("user_agent", "useragent");
Litmus::DB::Testresult->column_alias("result_status_id", "result_status");
Litmus::DB::Testresult->column_alias("build_type_id", "build_type");
Litmus::DB::Testresult->column_alias("exit_status_id", "exit_status");
Litmus::DB::Testresult->column_alias("validity_id", "validity");
Litmus::DB::Testresult->column_alias("vetting_status_id", "vetting_status");
Litmus::DB::Testresult->column_alias("locale_abbrev", "locale");
Litmus::DB::Testresult->column_alias("is_automated_result", "isAutomated");
Litmus::DB::Testresult->has_a(opsys => "Litmus::DB::Opsys");
Litmus::DB::Testresult->has_a(branch => "Litmus::DB::Branch");
Litmus::DB::Testresult->has_a(testcase => "Litmus::DB::Testcase");
Litmus::DB::Testresult->has_a(result_status => "Litmus::DB::ResultStatus");
Litmus::DB::Testresult->has_a(user => "Litmus::DB::User");
Litmus::DB::Testresult->has_a(useragent => "Litmus::UserAgentDetect");
Litmus::DB::Testresult->has_a(build_type => "Litmus::DB::BuildType");
Litmus::DB::Testresult->has_a(exit_status => "Litmus::DB::ExitStatus");
Litmus::DB::Testresult->has_a(locale => "Litmus::DB::Locale");
Litmus::DB::Testresult->has_a(platform =>
[ "Litmus::DB::Opsys" => "platform" ]);
Litmus::DB::Testresult->has_many(logs =>
["Litmus::DB::LogTestresult" => 'log_id']);
Litmus::DB::Testresult->has_many(comments => "Litmus::DB::Comment", {order_by => 'comment_id ASC, submission_time ASC'});
Litmus::DB::Testresult->has_many(bugs => "Litmus::DB::Resultbug", {order_by => 'bug_id ASC, submission_time DESC'});
Litmus::DB::Testresult->autoinflate(dates => 'Time::Piece');
Litmus::DB::Testresult->set_sql(DefaultTestResults => qq{
SELECT tr.testresult_id,tr.testcase_id,t.summary,tr.submission_time AS created,p.name AS platform_name,pr.name as product_name,trsl.name AS result_status,trsl.class_name result_status_class,b.name AS branch_name,tg.name AS test_group_name, tr.locale_abbrev, u.email
FROM test_results tr, testcases t, platforms p, opsyses o, branches b, products pr, test_result_status_lookup trsl, testgroups tg, subgroups sg, users u, testcase_subgroups tcsg, subgroup_testgroups sgtg
WHERE tr.testcase_id=t.testcase_id AND tr.opsys_id=o.opsys_id AND o.platform_id=p.platform_id AND tr.branch_id=b.branch_id AND b.product_id=pr.product_id AND tr.result_status_id=trsl.result_status_id AND tcsg.testcase_id=tr.testcase_id AND tcsg.subgroup_id=sg.subgroup_id AND sg.subgroup_id=sgtg.subgroup_id AND sgtg.testgroup_id=tg.testgroup_id AND tr.user_id=u.user_id AND tr.valid=1
ORDER BY tr.submission_time DESC, t.testcase_id DESC
LIMIT $_num_results_default
});
Litmus::DB::Testresult->set_sql(CommonResults => qq{
SELECT COUNT(tr.testcase_id) AS num_results, tr.testcase_id, t.summary, MAX(tr.submission_time) AS most_recent, MAX(tr.testresult_id) AS max_id
FROM test_results tr, testcases t, test_result_status_lookup trsl
WHERE tr.testcase_id=t.testcase_id AND tr.result_status_id=trsl.result_status_id AND trsl.class_name=?
GROUP BY tr.testcase_id
ORDER BY num_results DESC, tr.testresult_id DESC
LIMIT 15
});
Litmus::DB::Testresult->set_sql(Completed => qq{
SELECT tr.*
FROM test_results tr, opsyses o
WHERE tr.testcase_id=? AND
tr.build_id=? AND
tr.locale_abbrev=? AND
tr.opsys_id=o.opsys_id AND
o.platform_id=?
ORDER BY tr.submission_time DESC
});
Litmus::DB::Testresult->set_sql(CompletedByUser => qq{
SELECT tr.*
FROM test_results tr, opsyses o
WHERE tr.testcase_id=? AND
tr.build_id=? AND
tr.locale_abbrev=? AND
tr.opsys_id=o.opsys_id AND
o.platform_id=? AND
tr.user_id=?
ORDER BY tr.submission_time DESC
});
#########################################################################
# for historical reasons, note() is a shorthand way of saying "the text of
# the first comment on this result if that comment was submitted by the
# result submitter"
#########################################################################
sub note {
my $self = shift;
my @comments = $self->comments();
if (@comments && $comments[0] &&
$comments[0]->user() == $self->user()) {
return $comments[0]->comment();
} else {
return undef;
}
}
#########################################################################
# is this test result from a trusted user?
#########################################################################
sub istrusted {
my $self = shift;
if ($self->user()->istrusted()) {
return 1;
} else {
return 0;
}
}
#########################################################################
# &getDefaultTestResults($)
#
#########################################################################
sub getDefaultTestResults($) {
my $self = shift;
my @rows = $self->search_DefaultTestResults();
my $criteria = "Default<br/>Ordered by Created<br/>Limit to $_num_results_default results";
return $criteria, \@rows;
}
#########################################################################
# &getTestResults($\@\@$)
#
#########################################################################
sub getTestResults($\@\@$) {
my ($self,$where_criteria,$order_by_criteria,$limit_value) = @_;
my $select = 'SELECT tr.testresult_id,tr.testcase_id,t.summary,tr.submission_time AS created,p.name AS platform_name,pr.name as product_name,trsl.name AS result_status,trsl.class_name AS result_status_class,b.name AS branch_name,tg.name AS test_group_name, tr.locale_abbrev, u.email';
my $from = 'FROM test_results tr, testcases t, platforms p, opsyses o, branches b, products pr, test_result_status_lookup trsl, testgroups tg, subgroups sg, users u, testcase_subgroups tcsg, subgroup_testgroups sgtg';
my $where = 'WHERE tr.testcase_id=t.testcase_id AND tr.opsys_id=o.opsys_id AND o.platform_id=p.platform_id AND tr.branch_id=b.branch_id AND b.product_id=pr.product_id AND tr.result_status_id=trsl.result_status_id AND tcsg.testcase_id=tr.testcase_id AND tcsg.subgroup_id=sg.subgroup_id AND sg.subgroup_id=sgtg.subgroup_id AND sgtg.testgroup_id=tg.testgroup_id AND tr.user_id=u.user_id AND tr.valid=1';
my $limit = 'LIMIT ';
foreach my $criterion (@$where_criteria) {
$criterion->{'value'} =~ s/'/\'/g;
if ($criterion->{'field'} eq 'branch') {
$where .= " AND b.name='" . $criterion->{'value'} . "'";
} elsif ($criterion->{'field'} eq 'locale') {
$where .= " AND tr.locale_abbrev='" . $criterion->{'value'} . "'";
} elsif ($criterion->{'field'} eq 'product') {
$where .= " AND pr.name='" . $criterion->{'value'} . "'";
} elsif ($criterion->{'field'} eq 'platform') {
$where .= " AND p.name='" . $criterion->{'value'} . "'";
} elsif ($criterion->{'field'} eq 'test_group') {
$where .= " AND tg.name='" . $criterion->{'value'} . "'";
} elsif ($criterion->{'field'} eq 'testcase_id') {
$where .= " AND tr.testcase_id='" . $criterion->{'value'} . "'";
} elsif ($criterion->{'field'} eq 'summary') {
$where .= ' AND t.summary LIKE \'%%' . $criterion->{'value'} . '%%\'';
} elsif ($criterion->{'field'} eq 'email') {
$where .= ' AND u.email LIKE \'%%' . $criterion->{'value'} . '%%\'';
} elsif ($criterion->{'field'} eq 'result_status') {
$where .= " AND trsl.class_name='" . $criterion->{'value'} . "'";
} elsif ($criterion->{'field'} eq 'trusted_only') {
if ($from !~ /users u/) {
$from .= ", users u";
}
$where .= " AND u.user_id=tr.user_id AND u.is_admin=1";
} elsif ($criterion->{'field'} eq 'start_date') {
my $start_timestamp = &Date::Manip::UnixDate(&Date::Manip::ParseDateString($criterion->{'value'}),"%q");
if ($start_timestamp !~ /^\d\d\d\d\d\d\d\d\d\d\d\d\d\d$/) {
print STDERR "Unable to parse a valid start date from '$criterion->{'value'},' ignoring.\n";
} else {
$where .= " AND tr.submission_time>=$start_timestamp";
}
} elsif ($criterion->{'field'} eq 'end_date') {
my $end_timestamp = &Date::Manip::UnixDate(&Date::Manip::ParseDateString($criterion->{'value'}),"%q");
if ($end_timestamp !~ /^\d\d\d\d\d\d\d\d\d\d\d\d\d\d$/) {
print STDERR "Unable to parse a valid end date from '$criterion->{'value'},' ignoring.\n";
} else {
$where .= " AND tr.submission_time<=$end_timestamp";
}
} elsif ($criterion->{'field'} eq 'timespan') {
next if ($criterion->{'value'} eq 'all');
my $day_delta = $criterion->{'value'};
my $err;
my $timestamp =
&Date::Manip::UnixDate(&Date::Manip::DateCalc("now",
"$day_delta days",
\$err),
"%q");
$where .= " AND tr.submission_time>=$timestamp";
} elsif ($criterion->{'field'} eq 'search_field') {
($from,$where) = &_processSearchField($criterion,$from,$where);
} else {
# Skip unknown field
}
}
my $order_by = 'ORDER BY ';
foreach my $criterion (@$order_by_criteria) {
# Skip empty fields.
next if (!$criterion or !$criterion->{'field'});
if ($criterion->{'field'} eq 'created') {
$order_by .= "tr.submission_time $criterion->{'direction'},";
} elsif ($criterion->{'field'} eq 'product') {
$order_by .= "pr.name $criterion->{'direction'},";
} elsif ($criterion->{'field'} eq 'platform') {
$order_by .= "p.name $criterion->{'direction'},";
} elsif ($criterion->{'field'} eq 'test_group') {
$order_by .= "tg.name $criterion->{'direction'},";
} elsif ($criterion->{'field'} eq 'testcase_id') {
$order_by .= "tr.testcase_id $criterion->{'direction'},";
} elsif ($criterion->{'field'} eq 'summary') {
$order_by .= "t.summary $criterion->{'direction'},";
} elsif ($criterion->{'field'} eq 'result_status') {
$order_by .= "trsl.class_name $criterion->{'direction'},";
} elsif ($criterion->{'field'} eq 'branch') {
$order_by .= "b.name $criterion->{'direction'},";
} elsif ($criterion->{'field'} eq 'locale') {
$order_by .= "tr.locale_abbrev $criterion->{'direction'},";
} elsif ($criterion->{'field'} eq 'email') {
$order_by .= "u.email $criterion->{'direction'},";
} else {
# Skip unknown field
}
}
if ($order_by eq 'ORDER BY ') {
$order_by .= 'tr.submission_time DESC';
} else {
chop($order_by);
}
if ($limit_value and $limit_value ne '') {
$limit .= "$limit_value";
} else {
$limit .= "$_num_results_default";
}
my $sql = "$select $from $where $order_by $limit";
#print $sql,"<br/>\n";
Litmus::DB::Testresult->set_sql(TestResults => qq{
$sql
});
my @rows = $self->search_TestResults();
return \@rows;
}
#########################################################################
# &_processSearchField(\%\$\$)
#
#########################################################################
sub _processSearchField(\%) {
my ($search_field,$from,$where) = @_;
my $table_field = "";
if ($search_field->{'search_field'} eq 'build_id') {
$table_field='tr.build_id';
} elsif ($search_field->{'search_field'} eq 'comments') {
$table_field='c.comment';
} elsif ($search_field->{'search_field'} eq 'locale') {
$table_field='tr.locale_abbrev';
} elsif ($search_field->{'search_field'} eq 'opsys') {
$table_field='o.name';
} elsif ($search_field->{'search_field'} eq 'platform') {
$table_field='p.name';
} elsif ($search_field->{'search_field'} eq 'product') {
$table_field='pr.name';
} elsif ($search_field->{'search_field'} eq 'result_status') {
$table_field='trsl.name';
} elsif ($search_field->{'search_field'} eq 'subgroup') {
$table_field='sg.name';
} elsif ($search_field->{'search_field'} eq 'email') {
if ($from !~ /users u/) {
$from .= ", users u";
$where .= " AND tr.user_id=u.user_id";
}
$table_field='u.email';
} elsif ($search_field->{'search_field'} eq 'summary') {
$table_field='t.summary';
} elsif ($search_field->{'search_field'} eq 'test_group') {
$table_field='tg.name';
} elsif ($search_field->{'search_field'} eq 'user_agent') {
$table_field='tr.user_agent';
} else {
return ($from,$where);
}
if ($search_field->{'match_criteria'} eq 'contains_all' or
$search_field->{'match_criteria'} eq 'contains_any' or
$search_field->{'match_criteria'} eq 'not_contain_any') {
my $join = "";
if ($search_field->{'match_criteria'} eq 'contains_all') {
$join = 'AND';
} else {
$join = 'OR';
}
my @words = split(/ /,$search_field->{'value'});
if ($search_field->{'match_criteria'} eq 'not_contain_any') {
$where .= " AND NOT (";
} else {
$where .= " AND (";
}
my $first_pass = 1;
foreach my $word (@words) {
if ( $first_pass ) {
$where .= "UPPER($table_field) LIKE UPPER('%%" . $word . "%%')";
$first_pass = 0;
} else {
$where .= " $join UPPER($table_field) LIKE UPPER('%%" . $word . "%%')";
}
}
$where .= ")";
} elsif ($search_field->{'match_criteria'} eq 'contains') {
$where .= " AND UPPER($table_field) LIKE UPPER('%%" . $search_field->{'value'} . "%%')";
} elsif ($search_field->{'match_criteria'} eq 'contains_case') {
$where .= " AND $table_field LIKE '%%" . $search_field->{'value'} . "%%'";
} elsif ($search_field->{'match_criteria'} eq 'not_contain') {
$where .= " AND UPPER($table_field) NOT LIKE UPPER('%%" . $search_field->{'value'} . "%%')";
} elsif ($search_field->{'match_criteria'} eq 'regexp') {
$where .= " AND $table_field REGEXP '" . $search_field->{'value'} . "'";
} elsif ($search_field->{'match_criteria'} eq 'not_regexp') {
$where .= " AND $table_field NOT REGEXP '" . $search_field->{'value'} . "'";
} else {
# Ignore unknown match criteria.
return ($from,$where);
}
return ($from,$where);
}
#########################################################################
#########################################################################
sub getCommonResults($$) {
my ($self,$status,$limit_value) = @_;
if (!$status) {
return undef;
}
if (!$limit_value) {
$limit_value = $_num_results_default;
}
my @rows = $self->search_CommonResults($status);
return \@rows;
}
1;

View File

@@ -1,119 +0,0 @@
# -*- 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) 2006
# the Initial Developer. All Rights Reserved.
#
# Contributor(s):
# Chris Cooper <ccooper@deadsquid.com>
# Zach Lipton <zach@zachlipton.com>
#
# ***** END LICENSE BLOCK *****
=cut
package Litmus::DB::User;
use strict;
use Litmus::Config;
use base 'Litmus::DBI';
Litmus::DB::User->table('users');
Litmus::DB::User->columns(All => qw/user_id bugzilla_uid email password realname irc_nickname enabled is_admin authtoken/);
Litmus::DB::User->column_alias("is_trusted", "istrusted");
Litmus::DB::User->column_alias("is_admin", "is_trusted");
Litmus::DB::User->has_many(test_results => "Litmus::DB::Testresult");
Litmus::DB::User->has_many(sessions => "Litmus::DB::Session");
# ZLL: only load BugzillaUser if Bugzilla Auth is actually enabled
if ($Litmus::Config::bugzilla_auth_enabled) {
Litmus::DB::User->has_a(bugzilla_uid => "Litmus::DB::BugzillaUser");
}
__PACKAGE__->set_sql(RetrieveAll => qq{
SELECT __ESSENTIAL__
FROM __TABLE__
ORDER BY email ASC
});
__PACKAGE__->set_sql(TopTesters => qq{
SELECT users.user_id, users.email, count(*) AS num_results
FROM users, test_results
WHERE users.user_id=test_results.user_id
GROUP BY user_id
ORDER BY num_results DESC
LIMIT 15
});
# the COLLATE latin1_general_ci sillyness forces a case-insensitive match
# removed a LIMIT 300 to work around a mysql bug in the ancient version
# on rodan
__PACKAGE__->set_sql(FullTextMatches => q{
SELECT *
FROM __TABLE__
WHERE
email COLLATE latin1_general_ci like concat('%%',?,'%%') OR
irc_nickname COLLATE latin1_general_ci like concat('%%',?,'%%') OR
realname COLLATE latin1_general_ci like concat('%%',?,'%%')
ORDER BY email ASC
});
#########################################################################
# 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();
}
}
#########################################################################
sub getDisplayName() {
my $self = shift;
return $self->irc_nickname if ($self->irc_nickname and
$self->irc_nickname ne '');
return $self->realname if ($self->realname and
$self->realname ne '');
if ($self->email and
$self->email ne '') {
my $display_name = $self->email;
$display_name =~ s/\@.*$//g;
return $display_name
}
return undef;
}
1;

View File

@@ -1,130 +0,0 @@
# -*- 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) 2006
# the Initial Developer. All Rights Reserved.
#
# Contributor(s):
# Chris Cooper <ccooper@deadsquid.com>
# Zach Lipton <zach@zachlipton.com>
#
# ***** END LICENSE BLOCK *****
=cut
package Litmus::DBI;
require Apache::DBI;
use strict;
use warnings;
use Litmus::Config;
use Memoize;
use base 'Class::DBI::mysql';
our $dsn = "dbi:mysql:database=$Litmus::Config::db_name;host=$Litmus::Config::db_host;port=3306";
our %column_aliases;
Litmus::DBI->connection( $dsn,
$Litmus::Config::db_user,
$Litmus::Config::db_pass,
{AutoCommit=>1}
);
Litmus::DBI->autoupdate(1);
# In some cases, we have column names that make sense from a database perspective
# (i.e. subgroup_id), but that don't make sense from a class/object perspective
# (where subgroup would be more appropriate). To handle this, we allow for
# Litmus::DBI's subclasses to set column aliases with the column_alias() sub.
# Takes the database column name and the alias name.
sub column_alias {
my ($self, $db_name, $alias_name) = @_;
$column_aliases{$alias_name} = $db_name;
}
# here's where the actual work happens. We consult our alias list
# (as created by calls to column_alias()) and substitute the
# database column if we find a match
memoize('find_column');
sub find_column {
my $self = shift;
my $wanted = shift;
if (ref $self) {
$wanted =~ s/^.*::(\w+)$/$1/;
}
if ($column_aliases{$wanted}) {
return $column_aliases{$wanted};
} else {
# not an alias, so we use the normal
# find_column() from Class::DBI
$self->SUPER::find_column($wanted);
}
}
sub AUTOLOAD {
my $self = shift;
my @args = @_;
my $name = our $AUTOLOAD;
my $col = $self->find_column($name);
if (!$col) {
internalError("tried to call Litmus::DBI method $name which does not exist");
}
return $self->$col(@args);
}
sub _croak {
my ($self, $message, %info) = @_;
internalError($message);
return;
}
# Get Class::DBI's default dbh options
my $db_options = { __PACKAGE__->_default_attributes };
__PACKAGE__->_remember_handle('Main'); # so dbi_commit works
# override default to avoid using Ima::DBI closure
sub db_Main {
my $dbh;
if ( $ENV{'MOD_PERL'} and !$Apache::ServerStarting ) {
$dbh = Apache->request()->pnotes('dbh');
}
if ( !$dbh ) {
$dbh = DBI->connect(
$dsn, $Litmus::Config::db_user,
$Litmus::Config::db_pass, $db_options
);
if ( $ENV{'MOD_PERL'} and !$Apache::ServerStarting ) {
Apache->request()->pnotes( 'dbh', $dbh );
}
}
return $dbh;
}
1;

View File

@@ -1,275 +0,0 @@
# 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) 2006
# the Initial Developer. All Rights Reserved.
#
# Contributor(s):
# Chris Cooper <ccooper@deadsquid.com>
# Zach Lipton <zach@zachlipton.com>
# 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 = $self->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 RenameTable {
my ($self, $table, $newname) = @_;
my $ref = $self->TableExists($table);
return unless $ref; # already renamed?
$self->{'dbh'}->do("ALTER TABLE $table
RENAME TO $newname");
}
#########################################################################
sub RenameField {
my ($self, $table, $field, $newname) = @_;
my $ref = $self->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 = $self->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 AddKey {
my ($self, $table, $field, $definition) = @_;
my $ref = $self->GetIndexDef($table, $field);
return if $ref; # already added?
print "Adding new key $field to table $table ...\n";
$self->{'dbh'}->do("ALTER TABLE $table
ADD KEY $field $definition");
}
#########################################################################
sub AddUniqueKey {
my ($self, $table, $field, $definition) = @_;
my $ref = $self->GetIndexDef($table, $field);
return if $ref; # already added?
print "Adding new key $field to table $table ...\n";
$self->{'dbh'}->do("ALTER TABLE $table
ADD UNIQUE KEY $field $definition");
}
#########################################################################
sub AddFullText {
my ($self, $table, $index, $definition) = @_;
my $ref = $self->GetIndexDef($table, $index);
return if $ref; # already added?
print "Adding new fulltext $index to table $table ...\n";
$self->{'dbh'}->do("ALTER TABLE $table
ADD FULLTEXT $index $definition");
}
#########################################################################
sub DropField {
my ($self, $table, $field) = @_;
my $ref = $self->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");
}
#########################################################################
sub DropTable {
my ($self, $table, $field) = @_;
my $ref = $self->TableExists($table);
return unless $ref; # already dropped?
print "Deleting unused table $table ...\n";
$self->{'dbh'}->do("DROP TABLE $table");
}
#########################################################################
# 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;
}
}
$sth->finish;
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;
$sth->finish;
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;
$sth->finish;
return $ref;
}
}
#########################################################################
sub CountIndexes {
my ($self, $table) = @_;
my $sth = $self->{'dbh'}->prepare("SHOW INDEX FROM $table");
$sth->execute;
if ( $sth->rows == -1 ) {
$sth->finish;
die ("Unexpected response while counting indexes in $table:" .
" \$sth->rows == -1");
}
my $rows = $sth->rows;
$sth->finish;
return ($rows);
}
#########################################################################
sub DropIndex {
my ($self, $table, $index) = @_;
my $ref = $self->GetIndexDef($table, $index);
return unless $ref; # no matching index?
print "Removing index $index from table $table ...\n";
$self->{'dbh'}->do("ALTER TABLE $table
DROP INDEX $index");
}
#########################################################################
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;
}
$sth->finish;
}
1;

View File

@@ -1,84 +0,0 @@
# -*- 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) 2006
# the Initial Developer. All Rights Reserved.
#
# Contributor(s):
# Chris Cooper <ccooper@deadsquid.com>
# Zach Lipton <zach@zachlipton.com>
#
# ***** END LICENSE BLOCK *****
=cut
# General error reporting
package Litmus::Error;
use strict;
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;
_doError("Invalid Input - $message");
exit;
}
sub internalError($) {
my $message = shift;
_doError("Litmus has suffered an internal error - $message");
exit;
}
# an error type that does not use a template error message. Used if we
# can't even process the error template.
sub lastDitchError($) {
my $message = shift;
print "Error - Litmus has suffered a serious fatal internal error - $message";
exit;
}
sub _doError($) {
my $message = shift;
my $vars = {
message => $message,
};
Litmus->template()->process("error/error.html.tmpl", $vars) ||
lastDitchError(Litmus->template()->error());
}
1;

View File

@@ -1,342 +0,0 @@
# -*- 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) 2006
# the Initial Developer. All Rights Reserved.
#
# Contributor(s):
# Chris Cooper <ccooper@deadsquid.com>
# Zach Lipton <zach@zachlipton.com>
#
# ***** END LICENSE BLOCK *****
=cut
package Litmus::FormWidget;
use strict;
BEGIN {
use Exporter ();
use vars qw ($VERSION @ISA @EXPORT @EXPORT_OK %EXPORT_TAGS);
$VERSION = 0.01;
@ISA = qw (Exporter);
#Give a hoot don't pollute, do not export more than needed by default
@EXPORT = qw ( getProducts );
@EXPORT_OK = qw ();
%EXPORT_TAGS = ();
}
use DBI;
use Litmus::DBI;
our $_dbh = Litmus::DBI->db_Main();
#########################################################################
=head1 NAME
Litmus::FormWidget - Create value lists to be used in HTML forms
=head1 SYNOPSIS
use Litmus::FormWidget
=head1 DESCRIPTION
Litmus::FormWidget creates value lists to be used in HTML forms.
=head1 USAGE
=head1 BUGS
=head1 SUPPORT
=head1 AUTHOR
Chris Cooper
CPAN ID: CCOOPER
Mozilla Corporation
ccooper@deadsquid.com
http://litmus.mozilla.org/
=head1 SEE ALSO
perl(1).
=cut
#########################################################################
#sub new
#{
# my ($class, %parameters) = @_;
# my $self = bless ({}, ref ($class) || $class);
# return ($self);
#}
#########################################################################
=head2 getProducts
Usage : How to use this function/method
Purpose : What it does
Returns : What it returns
Argument : What it wants to know
Throws : Exceptions and other anomolies
Comments : This is a sample subroutine header.
: It is polite to include more pod and fewer comments.
See Also :
=cut
#########################################################################
sub getProducts()
{
my $sql = "SELECT name, product_id FROM products ORDER BY name";
return _getValues($sql);
}
#########################################################################
sub getUniquePlatforms()
{
my $sql = "SELECT DISTINCT(name), platform_id FROM platforms ORDER BY name";
return _getValues($sql);
}
#########################################################################
sub getPlatforms()
{
my $sql = "SELECT platform_id, name from platforms ORDER BY name ASC";
return _getValues($sql);
}
#########################################################################
sub getBranches()
{
my $sql = "SELECT name, branch_id FROM branches ORDER BY name ASC";
return _getValues($sql);
}
#########################################################################
sub getUniqueBranches()
{
my $sql = "SELECT DISTINCT(name) FROM branches ORDER BY name ASC";
return _getValues($sql);
}
#########################################################################
sub getOpsyses()
{
my $sql = "SELECT name, opsys_id FROM opsyses ORDER BY name ASC";
return _getValues($sql);
}
#########################################################################
sub getUniqueOpsyses()
{
my $sql = "SELECT DISTINCT(name) FROM opsyses ORDER BY name ASC";
return _getValues($sql);
}
#########################################################################
sub getLogTypes()
{
my $sql = "SELECT DISTINCT(name) FROM log_type_lookup ORDER BY name";
return _getValues($sql);
}
#########################################################################
sub getTestStatuses()
{
my @TestStatuses = ({name => 'Enabled'},
{name => 'Disabled'});
return \@TestStatuses;
}
#########################################################################
sub getResultStatuses()
{
my $sql = "SELECT result_status_id,class_name FROM test_result_status_lookup ORDER BY result_status_id";
return _getValues($sql);
}
#########################################################################
sub getTestcaseIDs()
{
my $sql = "SELECT testcase_id FROM testcases ORDER BY testcase_id";
return _getValues($sql);
}
#########################################################################
sub getTestcases()
{
my $sql = "SELECT testcase_id, summary, product_id FROM testcases ORDER BY testcase_id";
return _getValues($sql);
}
#########################################################################
sub getSubgroups()
{
my $sql = "SELECT subgroup_id, name, product_id FROM subgroups ORDER BY name, subgroup_id";
return _getValues($sql);
}
#########################################################################
sub getTestgroups()
{
my $sql = "SELECT testgroup_id, name, product_id FROM testgroups ORDER BY name, testgroup_id";
return _getValues($sql);
}
#########################################################################
sub getLocales()
{
my @locales = Litmus::DB::Locale->retrieve_all();
return \@locales;
}
#########################################################################
sub getUsers()
{
my @users = Litmus::DB::User->retrieve_all();
return \@users;
}
#########################################################################
sub getAuthors()
{
my $sql = "SELECT user_id, email FROM users WHERE is_admin=1 ORDER BY email";
return _getValues($sql);
}
#########################################################################
sub getFields()
{
my @fields = (
{ name => 'build_id',
display_string => "Build ID", },
{ name => 'comment',
display_string => "Comments", },
{ name => 'locale',
display_string => "Locale", },
{ name => 'opsys',
display_string => "Operating System", },
{ name => 'platform',
display_string => "Platform", },
{ name => 'product',
display_string => "Product", },
{ name => 'result_status',
display_string => "Result Status", },
{ name => 'subgroup',
display_string => "Subgroup", },
{ name => 'email',
display_string => "Submitted By", },
{ name => 'summary',
display_string => "Summary", },
{ name => 'testgroup',
display_string => "Testgroup", },
{ name => 'user_agent',
display_string => "User Agent", },
);
return \@fields;
}
#########################################################################
sub getMatchCriteria()
{
my @match_criteria = (
{ name => "contains_all",
display_string => "contains all of the words/strings" },
{ name => "contains_any",
display_string => "contains any of the words/strings" },
{ name => "contains",
display_string => "contains the word/string" },
{ name => "contains_case",
display_string => "contains the word/string (exact case)" },
{ name => "not_contain",
display_string => "does not contains the word/string" },
{ name => "not_contain_any",
display_string => "does not contains any of the words/string" },
{ name => "regexp",
display_string => "matches the regexp" },
{ name => "not_regexp",
display_string => "does not match the regexp" },
);
return \@match_criteria;
}
#########################################################################
sub getSortFields()
{
my @sort_fields = (
{ name => "branch",
display_string => "Branch"},
{ name => "created",
display_string => "Date"},
{ name => "locale",
display_string => "Locale"},
{ name => "platform",
display_string => "Platform"},
{ name => "product",
display_string => "Product"},
{ name => "email",
display_string => "Submitted By"},
{ name => "summary",
display_string => "Summary"},
{ name => "result_status",
display_string => "Status"},
{ name => "testcase_id",
display_string => "Testcase ID#"},
{ name => "testgroup",
display_string => "Testgroup"},
);
return \@sort_fields;
}
#########################################################################
sub _getValues($)
{
my ($sql) = @_;
my $sth = $_dbh->prepare_cached($sql);
$sth->execute();
my @rows;
while (my $data = $sth->fetchrow_hashref) {
push @rows, $data;
}
return \@rows;
$sth->finish();
}
1;

View File

@@ -1,43 +0,0 @@
# -*- 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) 2006
# the Initial Developer. All Rights Reserved.
#
# Contributor(s):
# Chris Cooper <ccooper@deadsquid.com>
# Zach Lipton <zach@zachlipton.com>
#
# ***** END LICENSE BLOCK *****
=cut
package Litmus::StripScripts;
use base qw(HTML::StripScripts::Parser);
# Override broken href validation code.
sub validate_href_attribute {
my ($self, $text) = @_;
$self->SUPER::validate_href_attribute or $text =~ m<^((https?|ftp|mailto)://[\w\-\.]{1,100}(?:\:\d{1,5})?(?:/(?:[\w\-.!~*|;:/?=+\$\,%#]|&amp;){0,100})?)$>x ? $1 : undef;
}
1;

View File

@@ -1,263 +0,0 @@
# -*- 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) 2006
# the Initial Developer. All Rights Reserved.
#
# Contributor(s):
# Chris Cooper <ccooper@deadsquid.com>
# Zach Lipton <zach@zachlipton.com>
#
# ***** END LICENSE BLOCK *****
=cut
package Litmus::SysConfig;
use strict;
require Exporter;
use Litmus;
use Litmus::DB::Locale;
use Litmus::DB::Product;
use Litmus::Error;
use Litmus::Utils;
use CGI;
our @ISA = qw(Exporter);
our @EXPORT = qw();
my $configcookiename = $Litmus::Config::sysconfig_cookiename;
sub new {
my ($class, $product, $platform, $opsys, $branch, $build_id, $locale) = @_;
my $self = {};
bless($self);
$self->{"product"} = $product;
$self->{"platform"} = $platform;
$self->{"opsys"} = $opsys;
$self->{"branch"} = $branch;
$self->{"build_id"} = $build_id;
$self->{"locale"} = $locale;
return $self;
}
sub setCookie {
my $self = shift;
my %cookiedata;
my $c = Litmus->cgi();
my $cookie = $c->cookie(
-name => $configcookiename.'_'.$self->{"product"}->product_id(),
-value => join('|', $self->{"product"}->product_id(), $self->{"platform"}->platform_id(),
$self->{"opsys"}->opsys_id(), $self->{"branch"}->branch_id(), $self->{"build_id"}, $self->{"locale"}->abbrev()),
-domain => $main::ENV{"HTTP_HOST"},
);
return $cookie;
}
sub getCookie {
my $self = shift;
my $c = Litmus->cgi();
my $product = shift;
return Litmus::SysConfig->
realGetCookie($configcookiename.'_'.$product->product_id());
}
# returns sysconfig objects corresponding to all sysconfig cookies the user
# has set
sub getAllCookies {
my $self = shift;
my $c = Litmus->cgi();
my @cookies = ();
my @names = $c->cookie();
foreach my $cur (@names) {
if ($cur =~ /^\Q$configcookiename\E_/) {
push(@cookies, Litmus::SysConfig->realGetCookie($cur));
}
}
if (@cookies == 0) { push(@cookies, undef) }
return @cookies;
}
sub realGetCookie {
my $self = shift;
my $cookiename = shift;
my $c = Litmus->cgi();
my $cookie = $c->cookie($cookiename);
if (! $cookie) {
return;
}
my @sysconfig = split(/\|/, $cookie);
return new(undef,
Litmus::DB::Product->retrieve($sysconfig[0]),
Litmus::DB::Platform->retrieve($sysconfig[1]),
Litmus::DB::Opsys->retrieve($sysconfig[2]),
Litmus::DB::Branch->retrieve($sysconfig[3]),
$sysconfig[4],
Litmus::DB::Locale->retrieve($sysconfig[5])
);
}
sub product() {
my $self = shift;
return $self->{"product"};
}
sub platform() {
my $self = shift;
return $self->{"platform"};
}
sub opsys() {
my $self = shift;
return $self->{"opsys"};
}
sub branch() {
my $self = shift;
return $self->{"branch"};
}
sub build_id() {
my $self = shift;
return $self->{"build_id"};
}
sub locale() {
my $self = shift;
return $self->{"locale"};
}
# display the system configuration form
# optionally takes the product to configure for
# and requires a url to load when done. this
# url should call processForm() to
# set the sysconfig cookie and do
# error handling.
# optionaly, pass a CGI object and its
# data will be stored in the form so
# the receiving script can access it.
sub displayForm {
my $self = shift;
my $product = shift;
my $goto = shift;
my $c = shift;
my @products;
# if we already know the product, then just send it on:
if ($product) {
$products[0] = $product;
} else {
# we need to ask the user for the product then
@products = Litmus::DB::Product->retrieve_all();
}
my @locales = Litmus::DB::Locale->retrieve_all(
{ order_by => 'abbrev' }
);
my $vars = {
locales => \@locales,
products => \@products,
ua => Litmus::UserAgentDetect->new(),
"goto" => $goto,
cgidata => $c,
};
# if the user already has a cookie set for this product, then
# load those values as defaults:
if ($product && Litmus::SysConfig->getCookie($product)) {
my $sysconfig = Litmus::SysConfig->getCookie($product);
$vars->{"defaultplatform"} = $sysconfig->platform();
$vars->{"defaultopsys"} = $sysconfig->opsys();
$vars->{"defaultbranch"} = $sysconfig->branch();
$vars->{"defaultlocale"} = $sysconfig->locale();
}
# send a default build id if we have one:
my @cookies = Litmus::SysConfig->getAllCookies();
if ($cookies[0]) { $vars->{"defaultbuildid"} = $cookies[0]->build_id() }
my $cookie = Litmus::Auth::getCurrentUser();
$vars->{"defaultemail"} = $cookie;
$vars->{"show_admin"} = Litmus::Auth::istrusted($cookie);
$vars->{"title"} = "Run Tests";
Litmus->template()->process("runtests/sysconfig.html.tmpl", $vars) ||
internalError(Litmus->template()->error());
}
# process a form containing sysconfig information.
# takes a CGI object containing param data
sub processForm {
my $self = shift;
my $c = shift;
my $product = Litmus::DB::Product->retrieve($c->param("product"));
my $platform = Litmus::DB::Platform->retrieve($c->param("platform"));
my $opsys = Litmus::DB::Opsys->retrieve($c->param("opsys"));
my $branch = Litmus::DB::Branch->retrieve($c->param("branch"));
my $build_id = $c->param("build_id");
my $locale = Litmus::DB::Locale->retrieve($c->param("locale"));
requireField("product", $product);
requireField("platform", $platform);
requireField("opsys", $opsys);
requireField("branch", $branch);
requireField("build_id", $build_id);
requireField("locale", $locale);
# set a cookie with the user's testing details:
my $prod = Litmus::DB::Product->retrieve($c->param("product"));
my $sysconfig = Litmus::SysConfig->new(
$product,
$platform,
$opsys,
$branch,
$build_id,
$locale
);
return $sysconfig;
}
1;

View File

@@ -1,205 +0,0 @@
# -*- 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 the Bugzilla Bug Tracking System.
#
# The Initial Developer of the Original Code is Netscape Communications
# Corporation. Portions created by Netscape are
# Copyright (C) 1998 Netscape Communications Corporation. All
# Rights Reserved.
#
# Contributor(s): Terry Weissman <terry@mozilla.org>
# Dan Mosedale <dmose@mozilla.org>
# Jacob Steenhagen <jake@bugzilla.org>
# Bradley Baetz <bbaetz@student.usyd.edu.au>
# Christopher Aillon <christopher@aillon.com>
# Tobias Burnus <burnus@net-b.de>
# Myk Melez <myk@mozilla.org>
# Max Kanat-Alexander <mkanat@bugzilla.org>
# Zach Lipton <zach@zachlipton.com>
# Chris Cooper <ccooper@deadsquid.com>
#
# ***** END LICENSE BLOCK *****
=cut
# This is mostly a placeholder. At some point in the future, we might
# want to be more like Bugzilla and support multiple languages and
# other fine features, so we keep this around now so that adding new
# things later won't require changing every source file.
package Litmus::Template;
use strict;
use Litmus::Config;
use Litmus::StripScripts;
use Text::Markdown;
use base qw(Template);
my $template_include_path;
$Template::Directive::WHILE_MAX = 30000;
# Returns the path to the templates based on the Accept-Language
# settings of the user and of the available languages
# If no Accept-Language is present it uses the defined default
sub getTemplateIncludePath () {
return "templates/en/default";
}
# Constants:
my %constants = {};
$constants{litmus_version} = $Litmus::Config::version;
# html tag stripper:
my $strip = Litmus::StripScripts->new(
{
AllowHref => 1,
AllowSrc => 1,
Context => 'Document'
},
strict_names => 1,
);
###############################################################################
# Templatization Code
# Use the Toolkit Template's Stash module to add utility pseudo-methods
# to template variables.
use Template::Stash;
# Add "contains***" methods to list variables that search for one or more
# items in a list and return boolean values representing whether or not
# one/all/any item(s) were found.
$Template::Stash::LIST_OPS->{ contains } =
sub {
my ($list, $item) = @_;
return grep($_ eq $item, @$list);
};
$Template::Stash::LIST_OPS->{ containsany } =
sub {
my ($list, $items) = @_;
foreach my $item (@$items) {
return 1 if grep($_ eq $item, @$list);
}
return 0;
};
# Allow us to still get the scalar if we use the list operation ".0" on it
$Template::Stash::SCALAR_OPS->{ 0 } =
sub {
return $_[0];
};
# Add a "substr" method to the Template Toolkit's "scalar" object
# that returns a substring of a string.
$Template::Stash::SCALAR_OPS->{ substr } =
sub {
my ($scalar, $offset, $length) = @_;
return substr($scalar, $offset, $length);
};
# Add a "truncate" method to the Template Toolkit's "scalar" object
# that truncates a string to a certain length.
$Template::Stash::SCALAR_OPS->{ truncate } =
sub {
my ($string, $length, $ellipsis) = @_;
$ellipsis ||= "";
return $string if !$length || length($string) <= $length;
my $strlen = $length - length($ellipsis);
my $newstr = substr($string, 0, $strlen) . $ellipsis;
return $newstr;
};
# Create the template object that processes templates and specify
# configuration parameters that apply to all templates.
sub create {
my $class = shift;
return $class->new({
INCLUDE_PATH => &getTemplateIncludePath,
CONSTANTS => \%constants,
PRE_PROCESS => "variables.none.tmpl",
POST_CHOMP => 1,
EVAL_PERL => 1,
COMPILE_DIR => $Litmus::Config::datadir,
FILTERS => {
# disallow all html in testcase data except for non-evil tags
testdata => sub {
my ($data) = @_;
$strip->parse($data);
$strip->eof();
return $strip->filtered_document;
},
# process the text with the markdown text processor
markdown => sub {
my ($data) = @_;
$data = Text::Markdown::markdown($data);
return $data;
},
# Returns the text with backslashes, single/double quotes,
# and newlines/carriage returns escaped for use in JS strings.
# thanks to bugzilla!
js => sub {
my ($var) = @_;
$var =~ s/([\\\'\"\/])/\\$1/g;
$var =~ s/\n/\\n/g;
$var =~ s/\r/\\r/g;
$var =~ s/\@/\\x40/g; # anti-spam for email addresses
return $var;
},
# anti-spam filtering of email addresses
email => sub {
my ($var) = @_;
$var =~ s/\@/\&#64;/g;
return $var;
},
# dummy filter when we don't actually need to filter anything
none => sub {
my ($var) = @_;
return $var;
},
},
});
}
# override the process() method to sneak defaultemail into all template
# variable spaces
sub process {
my ($self, $template, $vars, $outstream, @opts) = @_;
my %vars = %$vars;
$vars{defaultemail} = $vars{defaultemail} ? $vars{defaultemail} :
Litmus->getCurrentUser();
$vars{show_admin} = Litmus->getCurrentUser() ?
Litmus->getCurrentUser()->is_admin() : 0;
$self->SUPER::process($template, \%vars, $outstream, @opts);
}

View File

@@ -1,66 +0,0 @@
# -*- 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) 2006
# the Initial Developer. All Rights Reserved.
#
# Contributor(s):
# Chris Cooper <ccooper@deadsquid.com>
# Zach Lipton <zach@zachlipton.com>
#
# ***** END LICENSE BLOCK *****
=cut
package Litmus::Testlist;
use strict;
use base qw(Exporter);
@Litmus::Testlist::EXPORT = qw(
makeHotlist
);
sub makeHotlist {
my $numtests = shift;
my $state = shift;
my @tests = @_;
my @potentialtests;
foreach my $curtest (@tests) {
if ($curtest->isrecent()) {
foreach my $curplat ($curtest->subgroup()->testgroup()->product()->platforms()) {
my $found;
my $curstate = $curtest->state($curplat);
if ($curstate && $curstate->resultid() == $state->resultid()) {
push(@potentialtests, $curtest);
$found++;
}
if ($found) {next}
}
}
}
@potentialtests = sort{$b->num_recent_results() <=> $a->num_recent_results()}
@potentialtests;
return @potentialtests;
}

View File

@@ -1,147 +0,0 @@
# -*- 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) 2006
# the Initial Developer. All Rights Reserved.
#
# Contributor(s):
# Chris Cooper <ccooper@deadsquid.com>
# Zach Lipton <zach@zachlipton.com>
#
# ***** END LICENSE BLOCK *****
=cut
# Handle detection of system information from the UA string
package Litmus::UserAgentDetect;
use strict;
require Exporter;
use Litmus;
use Litmus::DB::Platform;
use Litmus::DB::Opsys;
use Litmus::DB::Branch;
our @ISA = qw(Exporter);
our @EXPORT = qw(detectBuildID);
# define some SQL queries we will use:
Litmus::DB::Platform->set_sql(detectplatform => qq{
SELECT p.platform_id
FROM platforms p, platform_products pp
WHERE
? REGEXP detect_regexp AND
p.platform_id=pp.platform_id AND
pp.product_id LIKE ?
});
Litmus::DB::Branch->set_sql(detectbranch => qq{
SELECT __ESSENTIAL__
FROM __TABLE__
WHERE
? REGEXP detect_regexp AND
product_id LIKE ?
});
# constructor. Optionally you can pass a UA string
# and it will be used. Otherwise the default is the
# current useragent.
sub new {
my $self = {};
my $class = shift;
my $ua = shift;
bless($self);
$self->{ua} = $main::ENV{"HTTP_USER_AGENT"};
if ($ua) { $self->{ua} = $ua }
return $self;
}
# default stringification is to return the ua:
use overload
'""' => \&ua;
sub ua {
my $self = shift;
# we pad the UA with a space since some of our regexp matches expect
# to match things at the end of the string. This is quite possibly
# a bug.
return $self->{ua}." ";
}
sub build_id {
my $self = shift;
my $ua = $self->{ua};
# mozilla products only
unless ($ua =~ /Mozilla\/5\.0/) {
return undef;
}
$ua =~ /(200\d*)/;
return $1;
}
sub locale {
my $self = shift;
my $ua = $self->{ua};
# mozilla products only
unless ($ua =~ /Mozilla\/5\.0/) {
return undef;
}
# Format (e.g.):
# Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8) Gecko/20051111 Firefox/1.5
$ua =~ /Mozilla\/5\.0 \([^;]*; [^;]*; [^;]*; ([^;]*); [^;]*\)/;
return $1;
}
sub platform {
my $self = shift;
my $product = shift; # optionally, just lookup for one product
if (! $product) { $product = '%' }
my @platforms = Litmus::DB::Platform->search_detectplatform($self->ua, $product);
return @platforms;
}
sub branch {
my $self = shift;
my $product = shift; # optionally, just lookup for one branch
if (! $product) { $product = '%' }
my @branches = Litmus::DB::Branch->search_detectbranch($self->ua, $product);
return @branches;
}
# from the legacy API before we had an OO interface:
sub detectBuildId() {
my $self = Litmus::UserAgentDetect->new($main::ENV{"HTTP_USER_AGENT"});
return $self->build_id();
}
1;

View File

@@ -1,61 +0,0 @@
# -*- 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) 2006
# the Initial Developer. All Rights Reserved.
#
# Contributor(s):
# Chris Cooper <ccooper@deadsquid.com>
# Zach Lipton <zach@zachlipton.com>
#
# ***** END LICENSE BLOCK *****
=cut
# General utility functions
package Litmus::Utils;
use strict;
use Litmus;
use Litmus::Error;
use CGI;
our @ISA = qw(Exporter);
@Litmus::Utils::EXPORT = qw(
requireField
);
# requireField - checks that $field contains data (other than ---) and throws
# an invalidInputError if it does not.
sub requireField {
my ($fieldname, $field) = @_;
unless($field && $field ne "---") {
my $c = Litmus->cgi();
print $c->header();
invalidInputError("You must make a valid selection for field ".$fieldname.".");
}
}
1;

View File

@@ -1,419 +0,0 @@
# -*- 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) 2006
# the Initial Developer. All Rights Reserved.
#
# Contributor(s):
# Zach Lipton <zach@zachlipton.com>
#
# ***** END LICENSE BLOCK *****
=cut
package Litmus::XML;
# Litmus XML Interface
# For further details, see the web services specification at
# http://wiki.mozilla.org/Litmus:Web_Services
use strict;
use XML::XPath;
use XML::XPath::XMLParser;
use Litmus::DB::User;
use Litmus::UserAgentDetect;
use Date::Manip;
use CGI::Carp qw(set_message fatalsToBrowser);
# if we die for some reason, make sure we give a fatal error per spec
BEGIN {
set_message(sub {
print "Fatal error: internal server error\n";
});
}
no warnings;
no diagnostics;
sub new {
my $self = {};
bless($self);
return $self;
}
# process XML test result data as described by
# the spec at http://wiki.mozilla.org/Litmus:Web_Services
sub processResults {
my $self = shift;
my $data = shift;
$self->parseResultFile($data) ? 1 : return 0;
unless ($self->authenticate()) { return 0} # login failure
$self->validateResults() ? 1 : return 0;
# at this point, everything is valid, so if we're just validating the
# results, we can return an ok:
if ($self->{'action'} eq 'validate') {
unless ($self->{'response'}) { $self->respOk() }
return 1;
}
# add so-called 'global logs' that apply to all the results
# we save them in @globallogs so we can map them to the results later
my @globallogs;
foreach my $log (@{$self->{'logs'}}) {
# the submission time is the timestamp of the first testresult:
my $newlog = Litmus::DB::Log->create({
submission_time => $self->{'results'}->[0]->{'timestamp'},
log_type => $log->{'type'},
log_text => $log->{'data'},
});
push(@globallogs, $newlog);
}
# now actually add the new results to the db:
foreach my $result (@{$self->{'results'}}) {
my $newres = Litmus::DB::Testresult->create({
testcase => $result->{'testid'},
user_agent => new Litmus::UserAgentDetect($self->{'useragent'}),
user => $self->{'user'},
opsys => $self->{'sysconfig'}->{'opsys'},
branch => $self->{'sysconfig'}->{'branch'},
locale => $self->{'sysconfig'}->{'locale'},
build_id => $self->{'sysconfig'}->{'buildid'},
machine_name => $self->{'machinename'},
result_status => $result->{'resultstatus'},
timestamp => $result->{'timestamp'},
exit_status => $result->{'exitstatus'},
duration_ms => $result->{'duration'},
valid => 1,
isAutomated => $result->{'isAutomated'},
});
if (!$newres) { $self->respErrResult($result->{'testid'}); next; }
# add any bug ids:
foreach my $bug (@{$result->{'bugs'}}) {
my $newbug = Litmus::DB::Resultbug->create({
test_result_id => $newres,
bug_id => $bug,
submission_time => $result->{'timestamp'},
user => $self->{'user'},
});
}
# add any comments:
foreach my $comment (@{$result->{'comments'}}) {
my $newcomment = Litmus::DB::Comment->create({
test_result => $newres,
submission_time => $result->{'timestamp'},
user => $self->{'user'},
comment => $comment,
});
}
# add logs:
my @resultlogs;
push(@resultlogs, @globallogs); # all results get the global logs
foreach my $log (@{$result->{'logs'}}) {
my $newlog = Litmus::DB::Log->create({
submission_time => $result->{'timestamp'},
log_type => $log->{'type'},
log_text => $log->{'data'},
});
push(@resultlogs, $newlog);
}
# now we map the logs to the current result:
foreach my $log (@resultlogs) {
Litmus::DB::LogTestresult->create({
test_result => $newres,
log_id => $log,
});
}
}
unless ($self->{'response'}) { $self->respOk() }
#$self->{'response'} = $self->{'results'}->[0]->{'resultstatus'};
}
sub parseResultFile {
my $self = shift;
my $data = shift;
my $x = XML::XPath->new(xml => $data, standalone => 1);
$self->{'useragent'} = $x->findvalue('/litmusresults/@useragent');
$self->{'machinename'} = $x->findvalue('litmusresults/@machinename');
$self->{'action'} = $x->findvalue('/litmusresults/@action');
$self->{'user'}->{'username'} = $x->findvalue(
'/litmusresults/testresults/@username');
$self->{'user'}->{'token'} = $x->findvalue(
'/litmusresults/testresults/@authtoken');
$self->{'sysconfig'}->{'product'} = $x->findvalue('/litmusresults/testresults/@product');
$self->{'sysconfig'}->{'platform'} = $x->findvalue('/litmusresults/testresults/@platform');
$self->{'sysconfig'}->{'opsys'} = $x->findvalue('/litmusresults/testresults/@opsys');
$self->{'sysconfig'}->{'branch'} = $x->findvalue('/litmusresults/testresults/@branch');
$self->{'sysconfig'}->{'buildid'} = $x->findvalue('/litmusresults/testresults/@buildid');
$self->{'sysconfig'}->{'locale'} = $x->findvalue('/litmusresults/testresults/@locale');
my @glogs = $x->find('/litmusresults/testresults/log')->get_nodelist();
my $l_ct = 0;
foreach my $log (@glogs) {
my $type = $x->findvalue('@logtype', $log);
my $logdata = stripWhitespace($log->string_value());
$self->{'logs'}->[$l_ct]->{'type'} = $type;
$self->{'logs'}->[$l_ct]->{'data'} = $logdata;
$l_ct++;
}
my @results = $x->find('/litmusresults/testresults/result')->get_nodelist();
my $c = 0;
foreach my $result (@results) {
$self->{'results'}->[$c]->{'testid'} = $x->findvalue('@testid', $result);
$self->{'results'}->[$c]->{'isAutomated'} = $x->findvalue('@is_automated_result', $result);
$self->{'results'}->[$c]->{'resultstatus'} = $x->findvalue('@resultstatus', $result);
$self->{'results'}->[$c]->{'exitstatus'} = $x->findvalue('@exitstatus', $result);
$self->{'results'}->[$c]->{'duration'} = $x->findvalue('@duration', $result);
$self->{'results'}->[$c]->{'timestamp'} =
&Date::Manip::UnixDate($x->findvalue('@timestamp', $result), "%q");
my @comments = $x->find('comment', $result)->get_nodelist();
my $com_ct = 0;
foreach my $comment (@comments) {
$comment = stripWhitespace($comment->string_value());
$self->{'results'}->[$c]->{'comments'}->[$com_ct] = $comment;
$com_ct++;
}
my @bugs = $x->find('bugnumber', $result)->get_nodelist();
my $bug_ct = 0;
foreach my $bug (@bugs) {
$bug = stripWhitespace($bug->string_value());
$self->{'results'}->[$c]->{'bugs'}->[$bug_ct];
$bug_ct++;
}
my @logs = $x->find('log', $result)->get_nodelist();
my $log_ct = 0;
foreach my $log (@logs) {
my $type = $x->findvalue('@logtype', $log);
my $logdata = stripWhitespace($log->string_value());
$self->{'results'}->[$c]->{'logs'}->[$log_ct]->{'type'} = $type;
$self->{'results'}->[$c]->{'logs'}->[$log_ct]->{'data'} = $logdata;
$log_ct++;
}
$c++;
}
$self->{'x'} = $x;
}
# validate the result data, and resolve references to various tables
# the correct objects, looking up id numbers as needed
sub validateResults {
my $self = shift;
my $action = $self->{'action'};
if ($action ne 'submit' && $action ne 'validate') {
$self->respErrFatal("Action must be either 'submit' or 'validate'");
return 0;
}
my @users = Litmus::DB::User->search(email => $self->{'user'}->{'username'});
$self->{'user'} = $users[0];
unless ($self->{'useragent'}) {
$self->respErrFatal("You must specify a useragent");
return 0;
}
my @prods = Litmus::DB::Product->search(name => $self->{'sysconfig'}->{'product'});
unless ($prods[0]) {
$self->respErrFatal("Invalid product: ".$self->{'sysconfig'}->{'product'});
return 0;
}
$self->{'sysconfig'}->{'product'} = $prods[0];
my @platforms = Litmus::DB::Platform->search_ByProductAndName(
$self->{'sysconfig'}->{'product'},
$self->{'sysconfig'}->{'platform'});
unless ($platforms[0]) {
$self->respErrFatal("Invalid platform: ".$self->{'sysconfig'}->{'platform'});
return 0;
}
$self->{'sysconfig'}->{'platform'} = $platforms[0];
my @opsyses = Litmus::DB::Opsys->search(
name => $self->{'sysconfig'}->{'opsys'},
platform => $self->{'sysconfig'}->{'platform'});
unless ($opsyses[0]) {
$self->respErrFatal("Invalid opsys: ".$self->{'sysconfig'}->{'opsys'});
return 0;
}
$self->{'sysconfig'}->{'opsys'} = $opsyses[0];
my @branches = Litmus::DB::Branch->search(
name => $self->{'sysconfig'}->{'branch'},
product => $self->{'sysconfig'}->{'product'});
unless ($branches[0]) {
$self->respErrFatal("Invalid branch: ".$self->{'sysconfig'}->{'branch'});
return 0;
}
$self->{'sysconfig'}->{'branch'} = $branches[0];
unless ($self->{'sysconfig'}->{'buildid'}) {
$self->respErrFatal("Invalid build id: ".$self->{'sysconfig'}->{'buildid'});
return 0;
}
my @locales = Litmus::DB::Locale->search(
locale => $self->{'sysconfig'}->{'locale'});
unless ($locales[0]) {
$self->respErrFatal("Invalid locale: ".$self->{'sysconfig'}->{'locale'});
return 0;
}
$self->{'sysconfig'}->{'locale'} = $locales[0];
foreach my $log (@{$self->{'logs'}}) {
my @types = Litmus::DB::LogType->search(name => $log->{'type'});
unless ($types[0]) {
$self->respErrFatal("Invalid log type: ".$log->{'type'});
return 0;
}
$log->{'type'} = $types[0];
}
foreach my $result (@{$self->{'results'}}) {
my @tests = Litmus::DB::Testcase->search(
test_id => $result->{'testid'});
unless ($tests[0]) {
$self->respErrResult('unknown', "Invalid test id");
next;
}
$result->{'testid'} = $tests[0];
# assume it's an automated test result if not specified
($result->{'isAutomated'} eq '0' || $result->{'isAutomated'} ne undef) ?
$result->{'isAutomated'} = 0 : $result->{'isAutomated'} = 1;
my @results = Litmus::DB::ResultStatus->search(
name => $result->{'resultstatus'});
unless ($results[0]) {
$self->respErrResult($result->{'testid'}, "Invalid resultstatus");
next;
}
$result->{'resultstatus'} = $results[0];
my @es = Litmus::DB::ExitStatus->search(
name => $result->{'exitstatus'});
unless ($es[0]) {
$self->respErrResult($result->{'testid'}, "Invalid exitstatus");
next;
}
$result->{'exitstatus'} = $es[0];
# if there's no duration, then it's just 0:
unless ($result->{'duration'}) {
$result->{'duration'} = 0;
}
# if there's no timestamp, then it's now:
unless ($result->{'timestamp'}) {
$result->{'timestamp'} = &Date::Manip::UnixDate("now","%q");
}
foreach my $log (@{$result->{'logs'}}) {
my @types = Litmus::DB::LogType->search(name => $log->{'type'});
unless ($types[0]) {
$self->respErrResult($result->{'testid'},
"Invalid log type: ".$log->{'type'});
next;
}
$log->{'type'} = $types[0];
}
}
return 1;
}
sub response {
my $self = shift;
return $self->{'response'};
}
# ONLY NON-PUBLIC API BELOW THIS POINT
sub authenticate {
my $self = shift;
my @users = Litmus::DB::User->search(email => $self->{'user'}->{'username'});
my $user = $users[0];
unless ($user) { $self->respErrFatal("User does not exist"); return 0 }
unless ($user->enabled()) { $self->respErrFatal("User disabled"); return 0 }
if ($user->authtoken() ne $self->{'user'}->{'token'}) {
respErrFatal("Invalid authentication token for user ".
$self->{'user'}->{'username'});
return 0;
}
return 1;
}
sub respOk {
my $self = shift;
$self->{'response'} = 'ok';
}
sub respErrFatal {
my $self = shift;
my $error = shift;
$self->{'response'} = "Fatal error: $error\n";
}
sub respErrResult {
my $self = shift;
my $testid = shift;
my $error = shift;
$self->{'response'} .= "Error processing result for test $testid: $error\n";
}
# remove leading and trailing whitespace from logs and comments
sub stripWhitespace {
my $txt = shift;
$txt =~ s/^\s+//;
$txt =~ s/\s+$//;
return $txt;
}
1;

View File

@@ -1,56 +0,0 @@
# Litmus Makefile
PERL=perl
install: templates
$(PERL) populatedb.pl
# precompile all templates with the Template Toolkit
# to speed things up a good bit.
# This ought to be done in a more "makelike" way, but
# various difficulties prevent that unless we use a configure
# script to generate the Makefile, at which point we could have
# been done already...
%.tmpl:
$(PERL) -e " \
eval('use CGI qw(-no_debug)'); \
use Litmus::Template;use diagnostics; \
\$$template = Litmus::Template->create(); \
\$$template->context()->template('$@'); \
"
templates: index.html.tmpl
$(PERL) -e " \
use File::Find; \
find({ wanted => sub { \
\$$name = \$$File::Find::name; \
return if (-d \$$name); \
return if (\$$name =~ /\/CVS\//); \
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 \
|| -M 'Litmus/Template.pm' < -M 'data/templates/en/default/'.\$$name) { \
system("make", "\$$name"); \
} \
}, no_chdir => 1 }, 'templates/en/default'); \
"
# tags: generate ctags style hints for ease of editing
# 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
cache:
$(PERL) -MLitmus -MLitmus::Cache -e "Litmus::Cache::rebuildCache();"
@echo "Done";
clean:
rm -rf data
make install

View File

@@ -1,47 +0,0 @@
===Litmus===
If you're reading this, you've downloaded, received, or simply conjured
out of thin air, a copy of the Litmus testcase management system.
Presumably, you're reading this file because you have some sort of
question about Litmus. Hopefully, if we've done our job right, this file
ought to answer your questions.
Q: What is Litmus?
A: Litmus is a testcase management system. Its goal is to allow users to
enter software tests, run them, and view and manage the results. Along
the way, users can expect to be able to do queries and reports and have
access all the usual features they expect from a first-class web
application. The reality may be somewhat different than this goal.
Litmus is developed by mozilla.org.
Q: How do I install this dang thing?
A: You probably want the file called INSTALL.
Q: Where is the real documentation?
A: Hahahaha. What is this "documentation" you speak of? You might want
to check out the Litmus Wiki, which may or may not contain useful
information. See http://wiki.mozilla.org/Litmus.
Q: What needs to be done?
A: See http://wiki.mozilla.org/Litmus:Todo
Q: How much does it cost?
A: Nothing. Litmus is Free Software, licensed under the Mozilla Public
License.
Q: Wait. Isn't "testcase" two words?
A: Not here it isn't.
Q: Waaaaaaah. Why is Litmus written in Perl and not
PHP/Python/Java/Objective Pascal/Latin?
A: Because I know Perl. Duh. Also because Litmus uses some code from
Bugzilla, and it wouldn't be able to do this if it was written in some
other language. Camels are also some of the least buggy animals around,
as they swat flies away with their tails.
Q: I'm still confused. You didn't answer my question. I don't know what
to do. Help!
A: First of all, that's not a question. In any case, your best bet is
probably to email Zach Lipton <zach@zachlipton.com>, and if you ask
nicely and don't make too much of a pest of yourself, he'd be glad to
get you on the right track.

View File

@@ -1,246 +0,0 @@
#!/usr/bin/perl -w
# -*- mode: cperl; c-basic-offset: 8; indent-tabs-mode: nil; -*-
# ***** 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) 2006
# the Initial Developer. All Rights Reserved.
#
# Contributor(s):
# Chris Cooper <ccooper@deadsquid.com>
# Zach Lipton <zach@zachlipton.com>
#
# ***** END LICENSE BLOCK *****
use strict;
use Litmus;
use Litmus::Auth;
use Litmus::Error;
use Litmus::DB::Testresult;
use Litmus::FormWidget;
use CGI;
use Time::Piece::MySQL;
Litmus->init();
my $c = Litmus->cgi();
print $c->header();
# Hash refs for maintaining state in the search form.
my $defaults = undef;
my $order_bys = undef;
my $MAX_SORT_FIELDS = 10;
my $MAX_SEARCH_FIELDS = 10;
my $criteria = "Custom<br/>";
my $results;
my @where;
my @order_by;
my $limit;
my $where_criteria = "";
my $order_by_criteria = "";
my $limit_criteria = "";
if ($c->param) {
foreach my $param ($c->param) {
next if ($c->param($param) eq '');
if ($param =~ /sort_field(\d+)/) {
# We slot sort fields into the @order_by array based on their
# field_num. Empty array slots will be ignored when the SQL
# is built. We set an upper limit on the number of sort fields
# we can handle to prevent abuse.
my $field_num = $1;
next if ($field_num > $MAX_SORT_FIELDS);
my $sort_field = $c->param($param);
my $sort_order = 'ASC';
if ($c->param("sort_order$field_num")) {
$sort_order = $c->param("sort_order$field_num");
}
$order_by[$field_num] = { field => $sort_field,
direction => $sort_order};
} elsif ($param =~ /search_field(\d+)/) {
# We set an upper limit on the number of search fields
# we can handle to prevent abuse.
my $field_num = $1;
next if ($field_num > $MAX_SEARCH_FIELDS);
my $search_field = $c->param($param);
my $match_criteria = $c->param("match_criteria$field_num");
my $value = $c->param("search_value$field_num");
push @where, { 'field' => 'search_field',
'search_field' => $search_field,
'match_criteria' => $match_criteria,
'value' => $value};
$where_criteria .= "$search_field $match_criteria '$value'<br/>";
} elsif ($param eq 'start_date') {
my $start_date = $c->param($param);
$start_date =~ s/[^0-9A-Za-z ]/ /g;
my $end_date;
# Use 'now' as the default end date.
if ($c->param('end_date') and $c->param('end_date') ne '') {
$end_date = $c->param('end_date');
$end_date =~ s/[^0-9A-Za-z ]/ /g;
} else {
$end_date = 'Now';
}
push @where, { field => 'start_date',
value => $start_date};
push @where, { field => 'end_date',
value => $end_date};
$where_criteria .= "Date between '$start_date' and '$end_date'<br/>";
} elsif ($param eq 'trusted_only') {
push @where, {field => 'trusted_only',
value => 1};
$limit_criteria .= "Display trusted results only<br/>";
} elsif ($param eq "limit") {
$limit = $c->param($param);
next if ($limit == $Litmus::DB::Testresult::_num_results_default);
$limit_criteria .= "Limit to $limit results<br/>";
} elsif ($param eq 'branch') {
my $value = $c->param($param);
push @where, {field => $param,
value => $value};
$where_criteria .= "Branch is \'".$c->param($param)."\'<br/>";
$defaults->{branch} = $c->param($param);
} elsif ($param eq 'locale') {
my $value = $c->param($param);
push @where, {field => 'locale',
value => $value};
$where_criteria .= "Locale is \'".$c->param($param)."\'<br/>";
$defaults->{locale} = $c->param($param);
} elsif ($param eq 'email') {
my $value = $c->param($param);
push @where, {field => 'email',
value => $value};
$where_criteria .= "Submitted By is \'".$c->param($param)."\'<br/>";
$defaults->{locale} = $c->param($param);
} elsif ($param eq 'product') {
my $value = $c->param($param);
push @where, {field => $param,
value => $value};
$where_criteria .= "Product is \'".$c->param($param)."\'<br/>";
$defaults->{product} = $c->param($param);
} elsif ($param eq 'platform') {
my $value = $c->param($param);
push @where, {field => $param,
value => $value};
$where_criteria .= "Platform is \'".$c->param($param)."\'<br/>";
$defaults->{platform} = $c->param($param);
} elsif ($param eq 'test_group') {
my $value = $c->param($param);
push @where, {field => $param,
value => $value};
$where_criteria .= "Test group is \'".$c->param($param)."\'<br/>";
$defaults->{test_group} = $c->param($param);
} elsif ($param eq 'test_id') {
my $value = $c->param($param);
push @where, {field => $param,
value => $value};
$where_criteria .= "Testcase ID# is \'".$c->param($param)."\'<br/>";
$defaults->{test_id} = $c->param($param);
} elsif ($param eq 'summary') {
my $value = $c->param($param);
push @where, {field => $param,
value => $value};
$where_criteria .= "Summary like \'".$c->param($param)."\'<br/>";
$defaults->{summary} = $c->param($param);
} elsif ($param eq 'result_status') {
my $value = $c->param($param);
push @where, {field => $param,
value => $value};
$where_criteria .= "Status is \'".$c->param($param)."\'<br/>";
$defaults->{result_status} = $c->param($param);
} else {
# Skip unknown field
}
}
if ($where_criteria eq '' and
scalar(@order_by) == 0 and
$limit_criteria eq '') {
($criteria,$results) =
Litmus::DB::Testresult->getDefaultTestResults;
} else {
foreach my $order_by_field (@order_by) {
next if (!$order_by_field);
$order_by_criteria .= "Order by $order_by_field->{field} $order_by_field->{direction}<br/>";
}
$criteria .= $where_criteria . $order_by_criteria . $limit_criteria;
$criteria =~ s/_/ /g;
$results = Litmus::DB::Testresult->getTestResults(\@where,
\@order_by,
$limit);
}
} else {
($criteria,$results) =
Litmus::DB::Testresult->getDefaultTestResults;
}
# Populate each of our form widgets for select/input.
# Set a default value as appropriate.
my $products = Litmus::FormWidget->getProducts;
my $platforms = Litmus::FormWidget->getUniquePlatforms;
my $test_groups = Litmus::FormWidget->getTestgroups;
my $testcases = Litmus::FormWidget->getTestcaseIDs;
my $result_statuses = Litmus::FormWidget->getResultStatuses;
my $branches = Litmus::FormWidget->getBranches;
my $locales = Litmus::FormWidget->getLocales;
my $users = Litmus::FormWidget->getUsers;
my $fields = Litmus::FormWidget->getFields;
my $match_criteria = Litmus::FormWidget->getMatchCriteria;
my $sort_fields = Litmus::FormWidget->getSortFields;
my $title = 'Advanced Search';
my $vars = {
title => $title,
criteria => $criteria,
products => $products,
platforms => $platforms,
test_groups => $test_groups,
testcases => $testcases,
result_statuses => $result_statuses,
branches => $branches,
locales => $locales,
users => $users,
fields => $fields,
match_criteria => $match_criteria,
sort_fields => $sort_fields,
};
# Only include results if we have them.
if ($results and scalar @$results > 0) {
$vars->{results} = $results;
}
my $cookie = Litmus::Auth::getCookie();
$vars->{"defaultemail"} = $cookie;
$vars->{"show_admin"} = Litmus::Auth::istrusted($cookie);
Litmus->template()->process("reporting/advanced_search.tmpl", $vars) ||
internalError(Litmus->template()->error());
exit 0;

View File

@@ -1,92 +0,0 @@
#!/usr/bin/perl -w
# -*- mode: cperl; c-basic-offset: 8; indent-tabs-mode: nil; -*-
# ***** 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) 2006
# the Initial Developer. All Rights Reserved.
#
# Contributor(s):
# Chris Cooper <ccooper@deadsquid.com>
# Zach Lipton <zach@zachlipton.com>
#
# ***** END LICENSE BLOCK *****
use strict;
$|++;
use Litmus;
use Litmus::Auth;
use Litmus::Error;
use Litmus::DB::Testresult;
use Litmus::FormWidget;
use CGI;
use Time::Piece::MySQL;
Litmus->init();
my $c = Litmus->cgi();
print $c->header();
my $results;
if ($c->param and $c->param('status')) {
if ($c->param('status') =~ /pass/i or
$c->param('status') =~ /fail/i or
$c->param('status') =~ /unclear/i) {
$results = Litmus::DB::Testresult->getCommonResults($c->param('status'));
} else {
internalError("You must provide a valid status type: pass|fail|unclear");
exit 1;
}
} else {
internalError("You must provide a status type: pass|fail|unclear");
exit 1;
}
my $title;
if ($c->param('status') eq 'pass') {
$title = "Most Commonly Passed Testcases";
} elsif ($c->param('status') eq 'fail') {
$title = "Most Common Failures";
} elsif ($c->param('status') eq 'unclear') {
$title = "Testcases Most Frequently Marked As Unclear";
}
my $vars = {
title => $title,
status => $c->param('status'),
};
# Only include results if we have them.
if ($results and scalar @$results > 0) {
$vars->{results} = $results;
}
$vars->{"defaultemail"} = Litmus::Auth::getCookie();
Litmus->template()->process("reporting/common_results.tmpl", $vars) ||
internalError(Litmus->template()->error());
exit 0;

Binary file not shown.

Before

Width:  |  Height:  |  Size: 791 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 261 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 249 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 396 B

File diff suppressed because it is too large Load Diff

View File

@@ -1,105 +0,0 @@
#!/usr/bin/perl -w
# -*- Mode: perl; indent-tabs-mode: nil -*-
#
# 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 Netscape Communications
# Corporation. Portions created by Netscape are
# Copyright (C) 1998 Netscape Communications Corporation. All
# Rights Reserved.
#
# Contributor(s): Zach Lipton <zach@zachlipton.com>
use strict;
use Litmus;
use Litmus::Error;
use Litmus::DB::Product;
use Litmus::DB::TestcaseSubgroup;
use Litmus::Auth;
use Litmus::Utils;
use CGI;
use Time::Piece::MySQL;
Litmus->init();
my $c = Litmus->cgi();
# obviously, you need to be an admin to edit users...
Litmus::Auth::requireAdmin('edit_users.cgi');
if ($c->param('search_string')) {
# search for users:
my $users = Litmus::DB::User->search_FullTextMatches(
$c->param('search_string'),
$c->param('search_string'),
$c->param('search_string'));
my $vars = {
users => $users,
};
print $c->header();
Litmus->template()->process("admin/edit_users/search_results.html.tmpl", $vars) ||
internalError(Litmus->template()->error());
} elsif ($c->param('id')) {
# lookup a given user
my $uid = $c->param('id');
my $user = Litmus::DB::User->retrieve($uid);
print $c->header();
if (! $user) {
invalidInputError("Invalid user id: $uid");
}
my $vars = {
user => $user,
};
Litmus->template()->process("admin/edit_users/edit_user.html.tmpl", $vars) ||
internalError(Litmus->template()->error());
} elsif ($c->param('user_id')) {
# process changes to a user:
my $user = Litmus::DB::User->retrieve($c->param('user_id'));
print $c->header();
if (! $user) {
invalidInputError("Invalid user id: " . $c->param('user_id'));
}
$user->bugzilla_uid($c->param('bugzilla_uid'));
$user->email($c->param('edit_email'));
if ($c->param('edit_password') ne 'unchanged') {
# they changed the password, so let the auth folks know:
Litmus::Auth::changePassword($user, $c->param('edit_password'));
}
$user->realname($c->param('realname'));
$user->irc_nickname($c->param('irc_nickname'));
if ($c->param('enabled')) {
$user->enabled(1);
}
if ($c->param('is_admin')) {
$user->is_admin(1);
}
$user->authtoken($c->param('authtoken'));
$user->update();
my $vars = {
user => $user,
};
Litmus->template()->process("admin/edit_users/user_edited.html.tmpl", $vars) ||
internalError(Litmus->template()->error());
} else {
# we're here for the first time, so display the search form
my $vars = {
};
print $c->header();
Litmus->template()->process("admin/edit_users/search_users.html.tmpl", $vars) ||
internalError(Litmus->template()->error());
}

View File

@@ -1,82 +0,0 @@
#!/usr/bin/perl -w
# -*- Mode: perl; indent-tabs-mode: nil -*-
#
# 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 Netscape Communications
# Corporation. Portions created by Netscape are
# Copyright (C) 1998 Netscape Communications Corporation. All
# Rights Reserved.
#
# Contributor(s): Zach Lipton <zach@zachlipton.com>
use strict;
use Litmus;
use Litmus::Error;
use Litmus::DB::Product;
use Litmus::DB::TestcaseSubgroup;
use Litmus::Auth;
use Litmus::Utils;
use CGI;
use Time::Piece::MySQL;
use Date::Manip;
Litmus->init();
my $c = Litmus->cgi();
# for the moment, you must be an admin to enter tests:
Litmus::Auth::requireAdmin('enter_test.cgi');
# if we're here for the first time, display the enter testcase form,
# otherwise, process the results:
if (! $c->param('enteringTestcase')) {
my $vars = {
};
print $c->header();
Litmus->template()->process("enter/enter.html.tmpl", $vars) ||
internalError(Litmus->template()->error());
} else {
requireField('product', $c->param('product'));
requireField('test group', $c->param('testgroup'));
requireField('subgroup', $c->param('subgroup'));
requireField('summary', $c->param('summary'));
my $newtest = Litmus::DB::Testcase->create({
product => $c->param('product'),
summary => $c->param('summary'),
steps => $c->param('steps') ? $c->param('steps') : '',
expected_results => $c->param('expectedResults') ?
$c->param('expectedResults') : '',
author => Litmus::Auth::getCurrentUser(),
creation_date => &Date::Manip::UnixDate("now","%q"),
version => 1,
});
my $newtsg = Litmus::DB::TestcaseSubgroup->create({
test => $newtest,
subgroup => $c->param('subgroup'),
});
my $vars = {
test => $newtest,
};
print $c->header();
Litmus->template()->process("enter/enterComplete.html.tmpl", $vars) ||
internalError(Litmus->template()->error());
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 580 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 332 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

View File

@@ -1,92 +0,0 @@
#!/usr/bin/perl -w
# -*- mode: cperl; c-basic-offset: 8; indent-tabs-mode: nil; -*-
# ***** 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) 2006
# the Initial Developer. All Rights Reserved.
#
# Contributor(s):
# Chris Cooper <ccooper@deadsquid.com>
# Zach Lipton <zach@zachlipton.com>
#
# ***** END LICENSE BLOCK *****
use strict;
$|++;
#use Time::HiRes qw( gettimeofday tv_interval );
#my $t0 = [gettimeofday];
use Litmus;
use Litmus::Auth;
use Litmus::Error;
use Litmus::DB::Testresult;
use Litmus::FormWidget;
use Time::Piece::MySQL;
Litmus->init();
my ($criteria,$results) = Litmus::DB::Testresult->getDefaultTestResults;
my $products = Litmus::FormWidget->getProducts();
my $platforms = Litmus::FormWidget->getUniquePlatforms();
my $test_groups = Litmus::FormWidget->getTestgroups();
my $result_statuses = Litmus::FormWidget->getResultStatuses;
my $branches = Litmus::FormWidget->getBranches();
my $c = Litmus->cgi();
print $c->header();
my $vars = {
title => 'Main Page',
products => $products,
platforms => $platforms,
test_groups => $test_groups,
result_statuses => $result_statuses,
branches => $branches,
limit => $Litmus::DB::Testresult::_num_results_default,
};
# Only include results if we have them.
if ($results and scalar @$results > 0) {
$vars->{results} = $results;
}
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());
#my $elapsed = tv_interval ( $t0 );
#printf "<div id='pageload'>Page took %f seconds to load.</div>", $elapsed;
exit 0;

View File

@@ -1,4 +0,0 @@
function adv_init() {
advSearchFormHeight = new fx.Combo('advSearchForm', {opacity: true, height: true, duration: 1000});
advSearchFormHeight.toggle();
}

View File

@@ -1,144 +0,0 @@
var noDHTML = false;
if (parseInt(navigator.appVersion) < 4) {
window.event = 0;
noDHTML = true;
} else if (navigator.userAgent.indexOf("MSIE") > 0 ) {
noDHTML = true;
}
if (document.body && document.body.addEventListener) {
document.body.addEventListener("click",maybeclosepopup,false);
}
setTimeout('location.reload()',900000);
function closepopup() {
var p = document.getElementById("popup");
if (p && p.parentNode) {
p.parentNode.removeChild(p);
}
}
function maybeclosepopup(e) {
var n = e.target;
var close = true;
while(close && n && (n != document)) {
close = (n.id != "popup") && !(n.tagName && (n.tagName.toLowerCase() == "a"));
n = n.parentNode;
}
if (close) closepopup();
}
function who(d) {
if (noDHTML) {
return true;
}
if (typeof document.layers != 'undefined') {
var l = document.layers['popup'];
l.src = d.target.href;
l.top = d.target.y - 6;
l.left = d.target.x - 6;
if (l.left + l.clipWidth > window.width) {
l.left = window.width - l.clipWidth;
}
l.visibility="show";
} else {
var t = d.target;
while (t.nodeType != 1) {
t = t.parentNode;
}
closepopup()
l = document.createElement("iframe");
l.setAttribute("src", t.href);
l.setAttribute("id", "popup");
l.className = "who";
t.appendChild(l);
}
return false;
}
function log_url(report_id) {
return "display_report.pl?report_id=" + report_id;
}
function comment(d,commentid,logfile) {
if (noDHTML) {
document.location = log_url(logfile);
return false;
}
if (typeof document.layers != 'undefined') {
var l = document.layers['popup'];
l.document.write("<table border=1 cellspacing=1><tr><td>"
+ comments[commentid] + "</tr></table>");
l.document.close();
l.top = d.y-10;
var zz = d.x;
if (zz + l.clip.right > window.innerWidth) {
zz = (window.innerWidth-30) - l.clip.right;
if (zz < 0) { zz = 0; }
}
l.left = zz;
l.visibility="show";
} else {
var t = d.target;
while (t.nodeType != 1) {
t = t.parentNode;
}
closepopup()
l = document.createElement("div");
l.innerHTML = comments[commentid];
l.setAttribute("id", "popup");
l.style.position = "absolute";
l.className = "comment";
t.parentNode.parentNode.appendChild(l);
}
return false;
}
function log(e,buildindex,logfile) {
var logurl = log_url(logfile);
var commenturl = "add_comment.pl?log=" + buildtree + "/" + logfile;
if (noDHTML) {
document.location = logurl;
return false;
}
if (typeof document.layers != 'undefined') {
var q = document.layers["logpopup"];
q.top = e.target.y - 6;
var yy = e.target.x;
if ( yy + q.clip.right > window.innerWidth) {
yy = (window.innerWidth-30) - q.clip.right;
if (yy < 0) { yy = 0; }
}
q.left = yy;
q.visibility="show";
q.document.write("<TABLE BORDER=1><TR><TD><B>"
+ builds[buildindex] + "</B><BR>"
+ "<A HREF=" + logurl + ">View Brief Log</A><BR>"
+ "<A HREF=" + logurl + "&fulltext=1"+">View Full Log</A><BR>"
+ "<A HREF=" + commenturl + ">Add a Comment</A>"
+ "</TD></TR></TABLE>");
q.document.close();
} else {
var t = e.target;
while (t.nodeType != 1) {
t = t.parentNode;
}
closepopup();
var l = document.createElement("div");
l.innerHTML = "<B>" + builds[buildindex] + "</B><BR>"
+ "<A HREF=" + logurl + ">View Brief Log</A><BR>"
+ "<A HREF=" + logurl + "&fulltext=1"+">View Full Log</A><BR>"
+ "<A HREF=" + commenturl + ">Add a Comment</A><BR>";
l.setAttribute("id", "popup");
l.className = "log";
t.parentNode.appendChild(l);
}
return false;
}
function empty_comparison_text() {
if (document.buffalo_search.comparison_text.value == "Enter comparison text") {
document.buffalo_search.comparison_text.value = "";
}
}

View File

@@ -1,11 +0,0 @@
//the main function, call to the effect object
function ec_init(){
var myDivs = document.getElementsByClassName("collapsable");
var myLinks = document.getElementsByClassName('collapse-link');
//then we create the effect.
var myAccordion = new fx.Accordion(myLinks, myDivs, {opacity: true});
myAccordion.fxa[0].toggle();
}

View File

@@ -1,71 +0,0 @@
var editedtests = new Array();
var fields = ["product", "summary", "testgroup", "subgroup",
"steps", "results", "admin", "formatting"];
function MM_findObj(n) {
var x = document.getElementById(n);
return x;
}
function showEdit(testid) {
for (var i=0; i<fields.length; i++) {
show(getField(fields[i]+"_edit",testid));
hide(getField(fields[i]+"_text",testid));
}
hide(getField("editlink", testid));
show(getField("canceleditlink", testid));
document.getElementById("show_test_form").action = "show_test.cgi";
editedtests.push(testid);
}
function findEdited() {
MM_findObj("editingTestcases").value = editedtests.toString();
}
function cancelEdit(testid) {
for (var i=0; i<fields.length; i++) {
hide(getField(fields[i]+"_edit",testid));
show(getField(fields[i]+"_text",testid));
}
show(getField("editlink", testid));
hide(getField("canceleditlink", testid));
// remove testid from the editedtests array:
var newarray = new Array();
for (var i=0; i<editedtests.length; i++) {
if (editedtests[i] != testid) {
newarray.push(testid);
}
}
editedtests=newarray;
document.getElementById("show_test_form").action = "process_test.cgi";
}
// fields are in the format fieldname_testid
function getField(fieldname, testid) {
return MM_findObj(fieldname+"_"+testid);
}
function show(obj) {
if (obj) {
obj.style.display = "";
}
}
function hide(obj) {
if (obj) {
obj.style.display = "none";
}
}
function tc_init() {
if (document.getElementById("testconfig")) {
testConfigHeight = new fx.Height('testconfig', {duration: 400});
testConfigHeight.toggle();
}
}

View File

@@ -1,228 +0,0 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/*
* FormPersist.js derived from CFormData.
* See <http://devedge-temp.mozilla.org/toolbox/examples/2003/CFormData/>
*/
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.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 Netscape code.
*
* The Initial Developer of the Original Code is
* Netscape Corporation.
* Portions created by the Initial Developer are Copyright (C) 2003
* the Initial Developer. All Rights Reserved.
*
* Contributor(s): Bob Clary <bclary@netscape.com>
* Bob Clary <http://bclary.com/>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
function FormInit(/*HTMLFormElement */ aForm, /* String */ aQueryString)
{
var type;
var options;
if (!aForm)
{
return;
}
if (!aQueryString)
{
return;
}
// empty out the form's values.
var elements = aForm.elements;
for (var iElm = 0; iElm < elements.length; iElm++)
{
var element = elements[iElm];
var nodeName = element.nodeName.toLowerCase();
switch(nodeName)
{
case 'input':
type = element.type.toLowerCase();
switch(type)
{
case 'text':
element.value = '';
break;
case 'radio':
case 'checkbox':
element.checked = false;
break;
}
break;
case 'textarea':
element.value = '';
break;
case 'select':
options = element.options;
for (iOpt = 0; iOpt < options.length; iOpt++)
{
options[iOpt].selected = false;
}
break;
}
}
// fill in form from the query string
if (aQueryString.indexOf('?') == 0);
{
aQueryString = aQueryString.substring(1);
}
aQueryString = decodeURIComponent(aQueryString);
aQueryString = aQueryString.replace(/[\&]amp;/g, '&');
var parmList = aQueryString.split('&');
for (var iParm = 0; iParm < parmList.length; iParm++)
{
var parms = parmList[iParm].split('=');
var name = parms[0];
var value;
if (parms.length == 1)
{
value = true;
}
else
{
var tempValue = parms[1];
value = tempValue.replace(/\+/g,' ');
}
elements = aForm[name];
if (!elements) {
return;
}
if (typeof elements.nodeName != 'undefined')
{
elements = [elements];
}
for (iElm = 0; iElm < elements.length; iElm++)
{
element = elements[iElm];
nodeName = element.nodeName.toLowerCase();
switch(nodeName)
{
case 'input':
type = element.type.toLowerCase();
switch(type)
{
case 'text':
element.value = value;
break;
case 'radio':
case 'checkbox':
if (element.value == value)
{
element.checked = true;
}
}
break;
case 'textarea':
element.value = value;
break;
case 'select':
options = element.options;
for (iOpt = 0; iOpt < options.length; iOpt++)
{
if (options[iOpt].value == value)
{
options[iOpt].selected = true;;
}
}
break;
}
}
}
}
function FormDump(aForm)
{
var type;
var s = '';
var elements = aForm.elements;
for (var iElm = 0; iElm < elements.length; iElm++)
{
var element = elements[iElm];
var nodeName = element.nodeName.toLowerCase();
switch(nodeName)
{
case 'input':
type = element.type.toLowerCase();
switch(type)
{
case 'text':
if (element.value)
{
s += '&' + element.name + '=' + element.value;
}
break;
case 'radio':
case 'checkbox':
if (element.checked)
{
s += '&' + element.name + '=' + element.value;
}
break;
}
break;
case 'textarea':
if (element.value)
{
s += '&' + element.name + '=' + element.value;
}
break;
case 'select':
var options = element.options;
for (iOpt = 0; iOpt < options.length; iOpt++)
{
if (options[iOpt].selected)
{
s += '&' + element.name + '=' + options[iOpt].value;
}
}
break;
}
}
s = '?' + encodeURIComponent(s.slice(1));
return s;
};

View File

@@ -1,469 +0,0 @@
var iBugNumber = "This field must be a valid, positive integer (>0). Please re-enter it now.";
var iNumber = iBugNumber;
var iEmail = "This field must be a valid email address (like foo@bar.com). Please re-enter it now.";
var iBuildId = "This field must be a valid build ID, which is a non-zero string of 10 digits. Please follow the 'How do I determine the build ID?' link for more information.";
var iPasswordMismatch = "The passwords you entered did not match.";
var iPasswordLength = "Your password must be longer than 4 characters.";
var defaultEmptyOK = false;
var mPrefix = "You did not enter a value into the ";
var mSuffix = " field. This is a required field. Please enter it now.";
var whitespace = " \t\n\r";
// Check whether string s is empty.
function isEmpty(s)
{
return ((s == null) || (s.length == 0));
}
// Returns true if string s is empty or
// whitespace characters only.
function isWhitespace (s)
{
var i;
// Is s empty?
if (isEmpty(s)) return true;
// Search through string's characters one by one
// until we find a non-whitespace character.
// When we do, return false; if we don't, return true.
for (i = 0; i < s.length; i++) {
// Check that current character isn't whitespace.
var c = s.charAt(i);
if (whitespace.indexOf(c) == -1) return false;
}
// All characters are whitespace.
return true;
}
// Returns true if character c is a digit
// (0 .. 9).
function isDigit (c)
{
return ((c >= "0") && (c <= "9"));
}
// Notify user that required field theField is empty.
// String s describes expected contents of theField.value.
// Put focus in theField and return false.
function warnEmpty (theField, s)
{
theField.focus();
toggleMessage('failure',mPrefix + s + mSuffix);
return false;
}
// Notify user that contents of field theField are invalid.
// String s describes expected contents of theField.value.
// Put select theField, put focus in it, and return false.
function warnInvalid (theField, s)
{
theField.focus();
if (!/select/.test(theField.type)) {
theField.select();
}
toggleMessage('failure',s);
return false;
}
// isEmail (STRING s [, BOOLEAN emptyOK])
//
// Email address must be of form a@b.c -- in other words:
// * there must be at least one character before the @
// * there must be at least one character before and after the .
// * the characters @ and . are both required
//
// For explanation of optional argument emptyOK,
// see comments of function isInteger.
function isEmail (s)
{
if (isEmpty(s)) {
if (isEmail.arguments.length == 1) {
return defaultEmptyOK;
} else {
return (isEmail.arguments[1] == true);
}
}
// is s whitespace?
if (isWhitespace(s)) {
return false;
}
// there must be >= 1 character before @, so we
// start looking at character position 1
// (i.e. second character)
var i = 1;
var sLength = s.length;
// look for @
while ((i < sLength) && (s.charAt(i) != "@")) {
i++;
}
if ((i >= sLength) || (s.charAt(i) != "@")) {
return false;
} else {
i += 2;
}
// look for .
while ((i < sLength) && (s.charAt(i) != ".")) {
i++;
}
// there must be at least one character after the .
if ((i >= sLength - 1) || (s.charAt(i) != ".")) {
return false;
} else {
return true;
}
}
// checkString (TEXTFIELD theField, STRING s, [, BOOLEAN emptyOK==false])
//
// Check that string theField.value is not all whitespace.
//
// For explanation of optional argument emptyOK,
// see comments of function isInteger.
function checkString (theField, s, emptyOK)
{
// Next line is needed on NN3 to avoid "undefined is not a number" error
// in equality comparison below.
if (checkString.arguments.length == 2) {
emptyOK = defaultEmptyOK;
}
if ((emptyOK == true) && (isEmpty(theField.value))) {
return true;
}
if (isWhitespace(theField.value)) {
return warnEmpty(theField, s);
} else {
return true;
}
}
// checkEmail (TEXTFIELD theField [, BOOLEAN emptyOK==false])
//
// Check that string theField.value is a valid Email.
//
// For explanation of optional argument emptyOK,
// see comments of function isInteger.
function checkEmail (theField, emptyOK)
{
if (checkEmail.arguments.length == 1) {
emptyOK = defaultEmptyOK;
}
if ((emptyOK == true) && (isEmpty(theField.value))) {
return true;
} else {
if (!isEmail(theField.value, false)) {
return warnInvalid (theField, iEmail);
} else {
return true;
}
}
}
function comparePasswords(password1, password2)
{
if (isWhitespace(password1.value)) {
return warnEmpty(password1, "Password");
}
if (isWhitespace(password2.value)) {
return warnEmpty(password2, "Confirm Password");
}
if (password1.value.length < 5) {
return warnInvalid (password1, iPasswordLength);
}
if (password1.value != password2.value) {
password1.value="";
password2.value="";
return warnInvalid (password1, iPasswordMismatch);
}
}
// checkBuildId (TEXTFIELD theField [, BOOLEAN emptyOK==false])
//
// Check that string theField.value is a valid build id.
//
// For explanation of optional argument emptyOK,
// see comments of function isInteger.
function checkBuildId (theField, emptyOK)
{
if (checkBuildId.arguments.length == 1) {
emptyOK = defaultEmptyOK;
}
if ((emptyOK == true) && (isEmpty(theField.value))) {
return true;
} else {
if (!/^\d{10,10}$/.test(theField.value) || theField.value == '0000000000') {
return warnInvalid (theField, iBuildId);
} else {
return true;
}
}
}
// checkNumber (TEXTFIELD theField [, BOOLEAN emptyOK==false])
//
// Check that string theField.value is a valid, positive integer.
//
// For explanation of optional argument emptyOK,
// see comments of function isInteger.
function checkNumber (theField, emptyOK)
{
if (checkNumber.arguments.length == 1) {
emptyOK = defaultEmptyOK;
}
if (isPositiveInteger(theField.value,emptyOK)) {
return true;
} else {
return warnInvalid (theField, iNumber);
}
}
// isInteger (STRING s [, BOOLEAN emptyOK])
//
// Returns true if all characters in string s are numbers.
//
// Accepts non-signed integers only. Does not accept floating
// point, exponential notation, etc.
//
// We don't use parseInt because that would accept a string
// with trailing non-numeric characters.
//
// By default, returns defaultEmptyOK if s is empty.
// There is an optional second argument called emptyOK.
// emptyOK is used to override for a single function call
// the default behavior which is specified globally by
// defaultEmptyOK.
// If emptyOK is false (or any value other than true),
// the function will return false if s is empty.
// If emptyOK is true, the function will return true if s is empty.
//
// EXAMPLE FUNCTION CALL: RESULT:
// isInteger ("5") true
// isInteger ("") defaultEmptyOK
// isInteger ("-5") false
// isInteger ("", true) true
// isInteger ("", false) false
// isInteger ("5", false) true
function isInteger (s)
{
var i;
if (isEmpty(s))
if (isInteger.arguments.length == 1) return defaultEmptyOK;
else return (isInteger.arguments[1] == true);
// Search through string's characters one by one
// until we find a non-numeric character.
// When we do, return false; if we don't, return true.
for (i = 0; i < s.length; i++)
{
// Check that current character is number.
var c = s.charAt(i);
if (!isDigit(c)) return false;
}
// All characters are numbers.
return true;
}
// isSignedInteger (STRING s [, BOOLEAN emptyOK])
//
// Returns true if all characters are numbers;
// first character is allowed to be + or - as well.
//
// Does not accept floating point, exponential notation, etc.
//
// We don't use parseInt because that would accept a string
// with trailing non-numeric characters.
//
// For explanation of optional argument emptyOK,
// see comments of function isInteger.
//
// EXAMPLE FUNCTION CALL: RESULT:
// isSignedInteger ("5") true
// isSignedInteger ("") defaultEmptyOK
// isSignedInteger ("-5") true
// isSignedInteger ("+5") true
// isSignedInteger ("", false) false
// isSignedInteger ("", true) true
function isSignedInteger (s)
{
if (isEmpty(s))
if (isSignedInteger.arguments.length == 1) return defaultEmptyOK;
else return (isSignedInteger.arguments[1] == true);
else {
var startPos = 0;
var secondArg = defaultEmptyOK;
if (isSignedInteger.arguments.length > 1)
secondArg = isSignedInteger.arguments[1];
// skip leading + or -
if ( (s.charAt(0) == "-") || (s.charAt(0) == "+") )
startPos = 1;
return (isInteger(s.substring(startPos, s.length), secondArg));
}
}
// isPositiveInteger (STRING s [, BOOLEAN emptyOK])
//
// Returns true if string s is an integer > 0.
//
// For explanation of optional argument emptyOK,
// see comments of function isInteger.
function isPositiveInteger (s)
{
var secondArg = defaultEmptyOK;
if (isPositiveInteger.arguments.length > 1)
secondArg = isPositiveInteger.arguments[1];
// The next line is a bit byzantine. What it means is:
// a) s must be a signed integer, AND
// b) one of the following must be true:
// i) s is empty and we are supposed to return true for
// empty strings
// ii) this is a positive, not negative, number
return (isSignedInteger(s, secondArg)
&& ( (isEmpty(s) && secondArg) || (parseInt (s) > 0) ) );
}
function verifySelected(theField, fieldName) {
if (theField.selectedIndex >= 0 &&
theField.options[theField.selectedIndex].value != '' &&
theField.options[theField.selectedIndex].value != '---') {
return true;
} else {
return warnInvalid (theField, 'You must select an option for ' + fieldName + '. Please make a selection now.');
}
}
function toggleMessage(msgType,msg) {
var em = document.getElementById("message");
if (toggleMessage.arguments.length < 1) {
em.innerHTML="";
em.style.display = 'none';
return;
}
switch (msgType) {
case "loading":
if (!msg || msg == '') {
msg = 'Loading...';
}
em.innerHTML = '<div class="loading">'+msg+'</div>';
em.style.display = 'block';
break;
case "info":
em.innerHTML = '<div class="info">'+msg+'</div>';
em.style.display = 'block';
setTimeout('toggleMessage()',5000);
break;
case "success":
em.innerHTML = '<div class="success">'+msg+'</div>';
em.style.display = 'block';
setTimeout('toggleMessage()',5000);
break;
case "failure":
em.innerHTML = '<div class="failure">'+msg+'</div>';
em.style.display = 'block';
setTimeout('toggleMessage()',5000);
break;
case "none":
default:
em.innerHTML="";
em.style.display = 'none';
return;
break;
}
}
function enableForm(formid) {
var f = document.getElementById(formid);
var ems = f.getElementsByTagName('input');
for (var i in ems) {
ems[i].disabled=false;
}
ems = f.getElementsByTagName('select');
for (var i in ems) {
ems[i].disabled=false;
}
ems = f.getElementsByTagName('textarea');
for (var i in ems) {
ems[i].disabled=false;
}
}
function disableForm(formid) {
var f = document.getElementById(formid);
var ems = f.getElementsByTagName('input');
for (var i in ems) {
ems[i].disabled=true;
}
ems = f.getElementsByTagName('select');
for (var i in ems) {
ems[i].disabled=true;
}
ems = f.getElementsByTagName('textarea');
for (var i in ems) {
ems[i].disabled=true;
}
}
function changeSelectedValue(selectid, optionvalue) {
var em = document.getElementById(selectid)
var options = em.getElementsByTagName('option');
var found = 0;
for (var i=0; i<options.length; i++) {
if (options[i].value == optionvalue) {
options[i].selected = true;
found=1;
} else {
options[i].selected = false;
}
}
if (found == 0) {
options[0].selected = true;
}
}
function blankForm(formid) {
var f = document.getElementById(formid);
var ems = f.getElementsByTagName('input');
for (var i in ems) {
if (ems[i].type == 'submit' ||
ems[i].value == 'Reset' ||
ems[i].type == 'radio' ||
ems[i].type == 'checkbox' ||
ems[i].type == 'button') {
continue;
}
ems[i].value='';
ems[i].checked=false;
}
ems = f.getElementsByTagName('select');
for (var i in ems) {
ems[i].selectedIndex=0;
}
ems = f.getElementsByTagName('textarea');
for (var i in ems) {
ems[i].value='';
}
}

View File

@@ -1,15 +0,0 @@
function toggleHelp(helpTitle,helpText) {
var em = document.getElementById("help");
if (toggleHelp.arguments.length < 1) {
em.innerHTML="";
em.style.display = 'none';
return;
}
var closeLink = '<div class="closeLink"><a name="closeHelp" onClick="toggleHelp();"><img class="chrome" src="images/close.png" />Close Help</a></div>'
em.innerHTML = '<div class="container"><div class="title">' + helpTitle + '</div><div class="content">' + helpText + '</div>' + closeLink + '</div>';
em.style.display = 'block';
}

View File

@@ -1,7 +0,0 @@
Copyright (c) 2005 Valerio Proietti, http://www.mad4milk.net
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

File diff suppressed because it is too large Load Diff

View File

@@ -1,2 +0,0 @@
dojo.hostenv.conditionalLoadModule({"common": ["MochiKit.MochiKit"]});
dojo.hostenv.moduleLoaded("MochiKit.*");

View File

@@ -1,16 +0,0 @@
function tc_init() {
var divs = document.getElementsByClassName("testcase-content");
allStretch = new fx.MultiFadeSize(divs, {height: true, opacity: true, duration: 400});
allStretch.hideAll();
testConfigHeight = new fx.Height('testconfig', {duration: 400});
testConfigHeight.toggle();
allStretch.fxa[0].toggle();
}
function confirmPartialSubmission() {
msg = "Did you intend to only submit a single test result? (Hint: There is a 'Submit All Results' button at the bottom of the page.)";
return confirm(msg);
}

View File

@@ -1,266 +0,0 @@
function selects_onload() {
load_products(getElementByClass("select_product"));
load_testgroups(getElementByClass("select_testgroup"));
load_subgroups(getElementByClass("select_subgroup"));
load_platforms(getElementByClass("select_platform"));
load_opsyses(getElementByClass("select_opsys"));
load_branches(getElementByClass("select_branch"));
}
function load_products(selects) {
if (!selects) { return; }
// for each select box in selects, load in the list of products
for (var select=0; select<selects.length; select++) {
var productbox = selects[select];
clearSelect(productbox);
addNullEntry(productbox);
for (var i=0; i<litmusconfig.length; i++) {
var option = makeOption(litmusconfig[i]);
productbox.add(option, null);
// handle the default selection
if (isDefault(document.getElementById(productbox.name+"_default"), litmusconfig[i]['id'])) {
productbox.selectedIndex = i+1;
}
}
}
}
function load_testgroups(selects) {
if (!selects[0]) { return; }
// load the proper list of testgroups for the
// currently selected product for each testgroup
// select:
for (var select=0; select<selects.length; select++) {
var groupbox = selects[select];
clearSelect(groupbox);
addNullEntry(groupbox);
// find the currently selected product that goes with this select
var productbox = document.getElementById("product"+groupbox.name.substr(9));
var productid = productbox.options[productbox.selectedIndex].value;
var product = getProductById(productid);
if (!product) {
return;
}
// now get the list of testgroups that goes with that product:
var testgroups = product['testgroups'];
for (var group=0; group<testgroups.length; group++) {
var option = makeOption(testgroups[group])
groupbox.add(option, null);
// handle the default selection
if (isDefault(document.getElementById(groupbox.name+"_default"), testgroups[group]['id'])) {
groupbox.selectedIndex = group+1;
}
}
}
}
function load_subgroups(selects) {
if (!selects[0]) { return; }
for (var select=0; select<selects.length; select++) {
var subgroupbox = selects[select];
clearSelect(subgroupbox);
addNullEntry(subgroupbox);
// find the currently selected testgroup that goes with this select
var testgroupbox = document.getElementById("testgroup"+subgroupbox.name.substr(8));
var testgroupid = testgroupbox.options[testgroupbox.selectedIndex].value;
var testgroup = getTestgroupById(testgroupid);
if (!testgroup) {
// no testgroup set
return;
}
// now get the list of subgroups that goes with that testgroup
var subgroups = testgroup['subgroups'];
for (var i=0; i<subgroups.length; i++) {
var option = makeOption(subgroups[i]);
subgroupbox.add(option, null);
if (isDefault(document.getElementById(subgroupbox.name+"_default"), subgroups[i]['id'])) {
subgroupbox.selectedIndex = i+1;
}
}
}
} // wow, that was fun
function load_platforms(selects) {
if (!selects[0]) { return; }
for (var select=0; select<selects.length; select++) {
var platformbox = selects[select];
clearSelect(platformbox);
addNullEntry(platformbox);
// find the currently selected product that goes with this select
var productbox = document.getElementById("product"+platformbox.name.substr(8));
var productid = productbox.options[productbox.selectedIndex].value;
var product = getProductById(productid);
if (!product) {
// no product set
return;
}
var platforms = product['platforms'];
for (var i=0; i<platforms.length; i++) {
var option = makeOption(platforms[i]);
platformbox.add(option, null);
if (isDefault(document.getElementById(platformbox.name+"_default"), platforms[i]['id'])) {
platformbox.selectedIndex = i+1;
}
}
}
}
function load_branches(selects) {
if (!selects[0]) { return; }
for (var select=0; select<selects.length; select++) {
var branchbox = selects[select];
clearSelect(branchbox);
addNullEntry(branchbox);
// find the currently selected product that goes with this select
var productbox = document.getElementById("product"+branchbox.name.substr(6));
var productid = productbox.options[productbox.selectedIndex].value;
var product = getProductById(productid);
if (!product) {
// no product set
return;
}
var branches = product['branches'];
for (var i=0; i<branches.length; i++) {
var option = makeOption(branches[i]);
branchbox.add(option, null);
if (isDefault(document.getElementById(branchbox.name+"_default"), branches[i]['id'])) {
branchbox.selectedIndex = i+1;
}
}
}
}
function load_opsyses(selects) {
if (!selects[0]) { return; }
for (var select=0; select<selects.length; select++) {
var opsysbox = selects[select];
clearSelect(opsysbox);
addNullEntry(opsysbox);
// find the currently selected platform
var platformbox = document.getElementById("platform"+opsysbox.name.substr(5));
var platformid = platformbox.options[platformbox.selectedIndex].value;
var platform = getPlatformById(platformid);
if (!platform) {
return;
}
var opsyses = platform['opsyses'];
for (var i=0; i<opsyses.length; i++) {
var option = makeOption(opsyses[i]);
opsysbox.add(option, null);
if (isDefault(document.getElementById(opsysbox.name+"_default"), opsyses[i]['id'])) {
opsysbox.selectedIndex = i+1;
}
}
}
}
function changeProduct(testid) {
var testidflag = "";
if (testid) { testidflag = "_"+testid; }
load_testgroups([document.getElementById("testgroup"+testidflag)]);
changeTestgroup(testid);
load_platforms([document.getElementById("platform"+testidflag)]);
changePlatform(testid);
load_branches([document.getElementById("branch"+testidflag)]);
}
function changeTestgroup(testid) {
var testidflag = "";
if (testid) { testidflag = "_"+testid; }
load_subgroups([document.getElementById("subgroup"+testidflag)]);
}
function changePlatform(testid) {
var testidflag = "";
if (testid) { testidflag = "_"+testid; }
load_opsyses([document.getElementById("opsys"+testidflag)]);
}
function addNullEntry(select) {
// add a blank entry to the current select
// if possible, try to make the null entry reflect the select's
// contents based on it's name:
if (select.className == 'select_product') {
select.add(new Option("-Product-", "---", false, false), null);
} else if (select.className == 'select_testgroup') {
select.add(new Option("-Testgroup-", "---", false, false), null);
} else if (select.className == 'select_subgroup') {
select.add(new Option("-Subgroup-", "---", false, false), null);
} else {
select.add(new Option("---", "---", false, false), null);
}
}
function clearSelect(select) {
// remove all options from a select:
while (select.options[0]) {
select.remove(0);
}
}
function getProductById(prodid) {
for (var i=0; i<litmusconfig.length; i++) {
if (litmusconfig[i]['id'] == prodid) {
return(litmusconfig[i]);
}
}
}
function getTestgroupById(testgroupid) {
for (var i=0; i<litmusconfig.length; i++) {
for (var j=0; j<litmusconfig[i]['testgroups'].length; j++) {
if (litmusconfig[i]['testgroups'][j]['id'] == testgroupid) {
return(litmusconfig[i]['testgroups'][j]);
}
}
}
}
function getPlatformById(platformid) {
for (var i=0; i<litmusconfig.length; i++) {
for (var j=0; j<litmusconfig[i]['platforms'].length; j++) {
if (litmusconfig[i]['platforms'][j]['id'] == platformid) {
return(litmusconfig[i]['platforms'][j]);
}
}
}
}
// pass this the <input> containing the list of possible default values
// and the current value, returns true if the current value appears in
// defaultInput, otherwise returns false
function isDefault(defaultInput, curvalue) {
if (! defaultInput) { return false; }
var defaultarray = defaultInput.value.split(',');
for (var i=0; i<defaultarray.length; i++) {
if (defaultarray[i] == curvalue) {
return true;
}
}
return false;
}
function makeOption(obj) {
return new Option(obj['name'], obj['id'], false, false)
}
function getElementByClass(theClass) {
var elements = new Array();
var all = document.getElementsByTagName("*");
for (var i=0; i<all.length; i++) {
if (all[i].className == theClass) {
elements.push(all[i]);
}
}
return elements;
}

View File

@@ -1,370 +0,0 @@
/*
Sort <SELECT> field script by Babvailiica
www.babailiica.com
version 1.3
*/
function selectAll(obj) {
obj = (typeof obj == "string") ? document.getElementById(obj) : obj;
if (obj.tagName.toLowerCase() != "select")
return;
for (var i=0; i<obj.length; i++) {
obj[i].selected = true;
}
}
function selectNone(obj) { /* NEW added from version 1.1 */
obj = (typeof obj == "string") ? document.getElementById(obj) : obj;
if (obj.tagName.toLowerCase() != "select")
return;
for (var i=0; i<obj.length; i++) {
obj[i].selected = false;
}
}
function swap(obj) { /*updated from version 1.3*/
obj = (typeof obj == "string") ? document.getElementById(obj) : obj;
if (obj.tagName.toLowerCase() != "select" && obj.length < 2)
return false;
var first_element = false;
var last_element = false;
for (var i=0; i<obj.length; i++) {
if (obj[i].selected) {
if (first_element === false) {
first_element = i;
} else {
last_element = i;
}
}
}
if (first_element === false || last_element === false)
return false;
var tmp = new Array((document.body.innerHTML ? obj[first_element].innerHTML : obj[first_element].text), obj[first_element].value, obj[first_element].style.color, obj[first_element].style.backgroundColor, obj[first_element].className, obj[first_element].id, obj[first_element].selected);
if (document.body.innerHTML) obj[first_element].innerHTML = obj[last_element].innerHTML;
else obj[first_element].text = obj[last_element].text;
obj[first_element].value = obj[last_element].value;
obj[first_element].style.color = obj[last_element].style.color;
obj[first_element].style.backgroundColor = obj[last_element].style.backgroundColor;
obj[first_element].className = obj[last_element].className;
obj[first_element].id = obj[last_element].id;
obj[first_element].selected = obj[last_element].selected;
if (document.body.innerHTML) obj[last_element].innerHTML = tmp[0];
else obj[last_element].text = tmp[0];
obj[last_element].value = tmp[1];
obj[last_element].style.color = tmp[2];
obj[last_element].style.backgroundColor = tmp[3];
obj[last_element].className = tmp[4];
obj[last_element].id = tmp[5];
obj[last_element].selected = tmp[6];
}
function addItem(obj, text, value, index, id, classname, color, bg, selected) { /* NEW added from version 1.1 updated from version 1.2*/
obj = (typeof obj == "string") ? document.getElementById(obj) : obj;
if (obj.tagName.toLowerCase() != "select" || text == "")
return;
obj.length++;
if (typeof index == "number" && index < obj.length-1) {
var i = Number();
for (i=obj.length-2; i>index-1; i--) {
if (document.body.innerHTML) obj[i+1].innerHTML = obj[i].innerHTML;
else obj[i+1].text = obj[i].text;
obj[i+1].value = obj[i].value;
obj[i+1].id = obj[i].id;
obj[i+1].className = obj[i].className;
obj[i+1].style.color = obj[i].style.color;
obj[i+1].style.backgroundColor = obj[i].style.backgroundColor;
obj[i+1].selected = obj[i].selected;
}
} else {
index = obj.length - 1;
}
obj = obj[index];
if (document.body.innerHTML) obj.innerHTML = text;
else obj.text = text;
obj.value = value;
obj.id = id ? id : '';
obj.className = classname ? classname : '';
obj.style.color = color ? color : '';
obj.style.backgroundColor = bg ? bg : '';
obj.selected = selected
}
function removeSelectedFromList(obj, index) { /* NEW added from version 1.1 */
obj = (typeof obj == "string") ? document.getElementById(obj) : obj;
if (obj.tagName.toLowerCase() != "select" || obj.length == 0)
return;
if (index === true) {
for (index=obj.length-1; index>=0; index--) {
if (obj[index].selected) {
obj[index] = null;
}
}
} else {
obj[((typeof index != "number") || index > (obj.length - 1) || index < 0 ? obj.length - 1 : index)] = null;
}
}
function mousewheel(obj) {
obj = (typeof obj == "string") ? document.getElementById(obj) : obj;
if (obj.tagName.toLowerCase() != "select")
return;
if (obj.selectedIndex != -1) {
if (event.wheelDelta > 0) {
up(obj);
} else {
down(obj);
}
return false;
}
}
function sort2d(arrayName, element, num, cs) {
if (num) {
for (var i=0; i<(arrayName.length-1); i++) {
for (var j=i+1; j<arrayName.length; j++) {
if (parseInt(arrayName[j][element],10) < parseInt(arrayName[i][element],10)) {
var dummy = arrayName[i];
arrayName[i] = arrayName[j];
arrayName[j] = dummy;
}
}
}
} else {
for (var i=0; i<(arrayName.length-1); i++) {
for (var j=i+1; j<arrayName.length; j++) {
if (cs) {
if (arrayName[j][element].toLowerCase() < arrayName[i][element].toLowerCase()) {
var dummy = arrayName[i];
arrayName[i] = arrayName[j];
arrayName[j] = dummy;
}
} else {
if (arrayName[j][element] < arrayName[i][element]) {
var dummy = arrayName[i];
arrayName[i] = arrayName[j];
arrayName[j] = dummy;
}
}
}
}
}
}
/* sort the list!
by = 0 - order by text (default)
by = 1 - order by value
by = 2 - order by color
by = 3 - order by background color
by = 4 - order by class name
by = 5 - order by id
num = if true sorts numbers e.g. 2 before 10
cs = casesensitive e.g. a before Z*/
function listSort(obj, by, num, cs) { /*updated from version 1.2*/
obj = (typeof obj == "string") ? document.getElementById(obj) : obj;
by = (parseInt("0" + by) > 5) ? 0 : parseInt("0" + by);
if (obj.tagName.toLowerCase() != "select" && obj.length < 2)
return false;
var elements = new Array();
for (var i=0; i<obj.length; i++) {
elements[elements.length] = new Array((document.body.innerHTML ? obj[i].innerHTML : obj[i].text), obj[i].value, (obj[i].currentStyle ? obj[i].currentStyle.color : obj[i].style.color), (obj[i].currentStyle ? obj[i].currentStyle.backgroundColor : obj[i].style.backgroundColor), obj[i].className, obj[i].id, obj[i].selected);
}
sort2d(elements, by, num, cs);
for (i=0; i<obj.length; i++) {
if (document.body.innerHTML) obj[i].innerHTML = elements[i][0];
else obj[i].text = elements[i][0];
obj[i].value = elements[i][1];
obj[i].style.color = elements[i][2];
obj[i].style.backgroundColor = elements[i][3];
obj[i].className = elements[i][4];
obj[i].id = elements[i][5];
obj[i].selected = elements[i][6];
}
}
function viceVersa(obj, onlyselected) { /*updated from version 1.3*/
obj = (typeof obj == "string") ? document.getElementById(obj) : obj;
if (obj.tagName.toLowerCase() != "select" && obj.length < 2)
return false;
var elements = new Array();
for (var i=obj.length-1; i>-1; i--) {
if (obj[i].selected || !onlyselected) {
elements[elements.length] = new Array((document.body.innerHTML ? obj[i].innerHTML : obj[i].text), obj[i].value, obj[i].style.color, obj[i].style.backgroundColor, obj[i].className, obj[i].id, obj[i].selected);
}
}
var a = 0;
for (i=0; i<obj.length; i++) {
if (obj[i].selected || !onlyselected) {
if (document.body.innerHTML) obj[i].innerHTML = elements[a][0];
else obj[i].text = elements[a][0];
obj[i].value = elements[a][1];
obj[i].style.color = elements[a][2];
obj[i].style.backgroundColor = elements[a][3];
obj[i].className = elements[a][4];
obj[i].id = elements[a][5];
obj[i].selected = elements[a][6];
a++;
}
}
}
function top(obj) { /*updated from version 1.2*/
obj = (typeof obj == "string") ? document.getElementById(obj) : obj;
if (obj.tagName.toLowerCase() != "select" && obj.length < 2)
return false;
var elements = new Array();
for (var i=0; i<obj.length; i++) {
if (obj[i].selected) {
elements[elements.length] = new Array((document.body.innerHTML ? obj[i].innerHTML : obj[i].text), obj[i].value, obj[i].style.color, obj[i].style.backgroundColor, obj[i].className, obj[i].id, obj[i].selected);
}
}
for (i=0; i<obj.length; i++) {
if (!obj[i].selected) {
elements[elements.length] = new Array((document.body.innerHTML ? obj[i].innerHTML : obj[i].text), obj[i].value, obj[i].style.color, obj[i].style.backgroundColor, obj[i].className, obj[i].id, obj[i].selected);
}
}
for (i=0; i<obj.length; i++) {
if (document.body.innerHTML) obj[i].innerHTML = elements[i][0];
else obj[i].text = elements[i][0];
obj[i].value = elements[i][1];
obj[i].style.color = elements[i][2];
obj[i].style.backgroundColor = elements[i][3];
obj[i].className = elements[i][4];
obj[i].id = elements[i][5];
obj[i].selected = elements[i][6];
}
}
function bottom(obj) { /*updated from version 1.2*/
obj = (typeof obj == "string") ? document.getElementById(obj) : obj;
if (obj.tagName.toLowerCase() != "select" && obj.length < 2)
return false;
var elements = new Array();
for (var i=0; i<obj.length; i++) {
if (!obj[i].selected) {
elements[elements.length] = new Array((document.body.innerHTML ? obj[i].innerHTML : obj[i].text), obj[i].value, obj[i].style.color, obj[i].style.backgroundColor, obj[i].className, obj[i].id, obj[i].selected);
}
}
for (i=0; i<obj.length; i++) {
if (obj[i].selected) {
elements[elements.length] = new Array((document.body.innerHTML ? obj[i].innerHTML : obj[i].text), obj[i].value, obj[i].style.color, obj[i].style.backgroundColor, obj[i].className, obj[i].id, obj[i].selected);
}
}
for (i=obj.length-1; i>-1; i--) {
if (document.body.innerHTML) obj[i].innerHTML = elements[i][0];
else obj[i].text = elements[i][0];
obj[i].value = elements[i][1];
obj[i].style.color = elements[i][2];
obj[i].style.backgroundColor = elements[i][3];
obj[i].className = elements[i][4];
obj[i].id = elements[i][5];
obj[i].selected = elements[i][6];
}
}
function up(obj) { /*updated from version 1.2*/
obj = (typeof obj == "string") ? document.getElementById(obj) : obj;
if (obj.tagName.toLowerCase() != "select" && obj.length < 2)
return false;
var sel = new Array();
for (var i=0; i<obj.length; i++) {
if (obj[i].selected == true) {
sel[sel.length] = i;
}
}
for (i in sel) {
if (sel[i] != 0 && obj[sel[i]-1] && !obj[sel[i]-1].selected) {
var tmp = new Array((document.body.innerHTML ? obj[sel[i]-1].innerHTML : obj[sel[i]-1].text), obj[sel[i]-1].value, obj[sel[i]-1].id);
if (document.body.innerHTML) obj[sel[i]-1].innerHTML = obj[sel[i]].innerHTML;
else obj[sel[i]-1].text = obj[sel[i]].text;
obj[sel[i]-1].value = obj[sel[i]].value;
obj[sel[i]-1].style.color = obj[sel[i]].style.color;
obj[sel[i]-1].style.backgroundColor = obj[sel[i]].style.backgroundColor;
obj[sel[i]-1].className = obj[sel[i]].className;
obj[sel[i]-1].id = obj[sel[i]].id;
if (document.body.innerHTML) obj[sel[i]].innerHTML = tmp[0];
else obj[sel[i]].text = tmp[0];
obj[sel[i]].value = tmp[1];
obj[sel[i]].style.color = tmp[2];
obj[sel[i]].style.backgroundColor = tmp[3];
obj[sel[i]].className = tmp[4];
obj[sel[i]].id = tmp[5];
obj[sel[i]-1].selected = true;
obj[sel[i]].selected = false;
}
}
}
function down(obj) {
obj = (typeof obj == "string") ? document.getElementById(obj) : obj;
if (obj.tagName.toLowerCase() != "select" && obj.length < 2)
return false;
var sel = new Array();
for (var i=obj.length-1; i>-1; i--) {
if (obj[i].selected == true) {
sel[sel.length] = i;
}
}
for (i in sel) {
if (sel[i] != obj.length-1 && obj[sel[i]+1] && !obj[sel[i]+1].selected) {
var tmp = new Array((document.body.innerHTML ? obj[sel[i]+1].innerHTML : obj[sel[i]+1].text), obj[sel[i]+1].value, obj[sel[i]+1].id);
if (document.body.innerHTML) obj[sel[i]+1].innerHTML = obj[sel[i]].innerHTML;
else obj[sel[i]+1].text = obj[sel[i]].text;
obj[sel[i]+1].value = obj[sel[i]].value;
obj[sel[i]+1].style.color = obj[sel[i]].style.color;
obj[sel[i]+1].style.backgroundColor = obj[sel[i]].style.backgroundColor;
obj[sel[i]+1].className = obj[sel[i]].className;
obj[sel[i]+1].id = obj[sel[i]].id;
if (document.body.innerHTML) obj[sel[i]].innerHTML = tmp[0];
else obj[sel[i]].text = tmp[0];
obj[sel[i]].value = tmp[1];
obj[sel[i]].style.color = tmp[2];
obj[sel[i]].style.backgroundColor = tmp[3];
obj[sel[i]].className = tmp[4];
obj[sel[i]].id = tmp[5];
obj[sel[i]+1].selected = true;
obj[sel[i]].selected = false;
}
}
}
function inArray(v,a) {
for (var i in a) {
if (a[i] == v) {
return true;
}
}
return false;
}
function copyToList(from,to)
{
fromList = document.getElementById(from);
toList = document.getElementById(to);
if (toList.options.length > 0 && toList.options[0].value == '')
{
toList.options.length = 0;
}
var sel = false;
for (i=0;i<fromList.options.length;i++)
{
var current = fromList.options[i];
if (current.selected)
{
sel = true;
if (current.value == 'temp')
{
alert ('You cannot move this text!');
return;
}
txt = current.text;
val = current.value;
toList.options[toList.length] = new Option(txt,val);
// fromList.options[i] = null;
// i--;
}
}
}

View File

@@ -1,73 +0,0 @@
function MM_findObj(n, d) { //v4.01
var p,i,x; if(!d) d=document; if((p=n.indexOf("?"))>0&&parent.frames.length) {
d=parent.frames[n.substring(p+1)].document; n=n.substring(0,p);}
if(!(x=d[n])&&d.all) x=d.all[n]; for (i=0;!x&&i<d.forms.length;i++) x=d.forms[i][n];
for(i=0;!x&&d.layers&&i<d.layers.length;i++) x=MM_findObj(n,d.layers[i].document);
if(!x && d.getElementById) x=d.getElementById(n); return x;
}
function showsubgroup() {
var groupselect = MM_findObj("group");
if (!groupselect) {
return;
}
var selnum;
if (groupselect.value) {
selnum = groupselect.value;
} else {
for (var i=0; i<groupselect.length; i++) {
if (groupselect[i].checked) {
selnum = groupselect[i].value;
}
}
if (!selnum) {
groupselect[0].checked = true;
selnum = groupselect[0].value;
}
}
// object to show
var obj = MM_findObj("divsubgroup_"+selnum);
// disable all of them
for (var i=0; i<groupselect.length; i++) {
var gnum = groupselect[i].value;
var disableobj = MM_findObj("divsubgroup_"+gnum);
disableobj.style.display = "none";
}
MM_findObj("divsubgroup_null").style.display = "none";
var num_subgroups_enabled = 0;
var subgroupselect = MM_findObj("subgroup_"+selnum);
if (!subgroupselect) {
return;
}
if (subgroupselect.value) {
num_subgroups_enabled=1;
} else {
for (var i=0; i<subgroupselect.length; i++) {
if (!subgroupselect[i].disabled) {
num_subgroups_enabled++;
}
}
}
obj.style.display = "";
if (num_subgroups_enabled == 0) {
MM_findObj("Submit").disabled = true;
} else {
MM_findObj("Submit").disabled = false;
}
}
function group_init() {
testConfigHeight = new fx.Height('testconfig', {duration: 400});
testConfigHeight.hide();
}

View File

@@ -1,139 +0,0 @@
/*
json.js
2006-04-28
This file adds these methods to JavaScript:
object.toJSONString()
This method produces a JSON text from an object. The
object must not contain any cyclical references.
array.toJSONString()
This method produces a JSON text from an array. The
array must not contain any cyclical references.
string.parseJSON()
This method parses a JSON text to produce an object or
array. It will return false if there is an error.
*/
(function () {
var m = {
'\b': '\\b',
'\t': '\\t',
'\n': '\\n',
'\f': '\\f',
'\r': '\\r',
'"' : '\\"',
'\\': '\\\\'
},
s = {
array: function (x) {
var a = ['['], b, f, i, l = x.length, v;
for (i = 0; i < l; i += 1) {
v = x[i];
f = s[typeof v];
if (f) {
v = f(v);
if (typeof v == 'string') {
if (b) {
a[a.length] = ',';
}
a[a.length] = v;
b = true;
}
}
}
a[a.length] = ']';
return a.join('');
},
'boolean': function (x) {
return String(x);
},
'null': function (x) {
return "null";
},
number: function (x) {
return isFinite(x) ? String(x) : 'null';
},
object: function (x) {
if (x) {
if (x instanceof Array) {
return s.array(x);
}
var a = ['{'], b, f, i, v;
for (i in x) {
v = x[i];
f = s[typeof v];
if (f) {
v = f(v);
if (typeof v == 'string') {
if (b) {
a[a.length] = ',';
}
a.push(s.string(i), ':', v);
b = true;
}
}
}
a[a.length] = '}';
return a.join('');
}
return 'null';
},
string: function (x) {
if (/["\\\x00-\x1f]/.test(x)) {
x = x.replace(/([\x00-\x1f\\"])/g, function(a, b) {
var c = m[b];
if (c) {
return c;
}
c = b.charCodeAt();
return '\\u00' +
Math.floor(c / 16).toString(16) +
(c % 16).toString(16);
});
}
return '"' + x + '"';
}
};
Object.prototype.toJSONString = function () {
return s.object(this);
};
Array.prototype.toJSONString = function () {
return s.array(this);
};
})();
String.prototype.parseJSON = function () {
try {
return !(/[^,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t]/.test(
this.replace(/"(\\.|[^"\\])*"/g, ''))) &&
eval('(' + this + ')');
} catch (e) {
return false;
}
};
function fetchJSON(url,callbackFunction) {
var d = loadJSONDoc(url);
d.addBoth(function (res) {
d.deferred = null;
toggleMessage('none');
return res;
});
d.addCallback(callbackFunction);
// if anything goes wrong, except for a simple cancellation,
// then log the error and show the logger
d.addErrback(function (err) {
if (err instanceof CancelledError) {
return;
}
logError(err);
logger.debuggingBookmarklet();
});
}

View File

@@ -1,133 +0,0 @@
/*
moo.fx, simple effects library built with prototype.js (http://prototype.conio.net).
by Valerio Proietti (http://mad4milk.net) MIT-style LICENSE.
for more info (http://moofx.mad4milk.net).
Sunday, March 05, 2006
v 1.2.3
*/
var fx = new Object();
//base
fx.Base = function(){};
fx.Base.prototype = {
setOptions: function(options) {
this.options = {
duration: 500,
onComplete: '',
transition: fx.sinoidal
}
Object.extend(this.options, options || {});
},
step: function() {
var time = (new Date).getTime();
if (time >= this.options.duration+this.startTime) {
this.now = this.to;
clearInterval (this.timer);
this.timer = null;
if (this.options.onComplete) setTimeout(this.options.onComplete.bind(this), 10);
}
else {
var Tpos = (time - this.startTime) / (this.options.duration);
this.now = this.options.transition(Tpos) * (this.to-this.from) + this.from;
}
this.increase();
},
custom: function(from, to) {
if (this.timer != null) return;
this.from = from;
this.to = to;
this.startTime = (new Date).getTime();
this.timer = setInterval (this.step.bind(this), 13);
},
hide: function() {
this.now = 0;
this.increase();
},
clearTimer: function() {
clearInterval(this.timer);
this.timer = null;
}
}
//stretchers
fx.Layout = Class.create();
fx.Layout.prototype = Object.extend(new fx.Base(), {
initialize: function(el, options) {
this.el = $(el);
this.el.style.overflow = "hidden";
this.iniWidth = this.el.offsetWidth;
this.iniHeight = this.el.offsetHeight;
this.setOptions(options);
}
});
fx.Height = Class.create();
Object.extend(Object.extend(fx.Height.prototype, fx.Layout.prototype), {
increase: function() {
this.el.style.height = this.now + "px";
},
toggle: function() {
if (this.el.offsetHeight > 0) this.custom(this.el.offsetHeight, 0);
else this.custom(0, this.el.scrollHeight);
}
});
fx.Width = Class.create();
Object.extend(Object.extend(fx.Width.prototype, fx.Layout.prototype), {
increase: function() {
this.el.style.width = this.now + "px";
},
toggle: function(){
if (this.el.offsetWidth > 0) this.custom(this.el.offsetWidth, 0);
else this.custom(0, this.iniWidth);
}
});
//fader
fx.Opacity = Class.create();
fx.Opacity.prototype = Object.extend(new fx.Base(), {
initialize: function(el, options) {
this.el = $(el);
this.now = 1;
this.increase();
this.setOptions(options);
},
increase: function() {
if (this.now == 1 && (/Firefox/.test(navigator.userAgent))) this.now = 0.9999;
this.setOpacity(this.now);
},
setOpacity: function(opacity) {
if (opacity == 0 && this.el.style.visibility != "hidden") this.el.style.visibility = "hidden";
else if (this.el.style.visibility != "visible") this.el.style.visibility = "visible";
if (window.ActiveXObject) this.el.style.filter = "alpha(opacity=" + opacity*100 + ")";
this.el.style.opacity = opacity;
},
toggle: function() {
if (this.now > 0) this.custom(1, 0);
else this.custom(0, 1);
}
});
//transitions
fx.sinoidal = function(pos){
return ((-Math.cos(pos*Math.PI)/2) + 0.5);
//this transition is from script.aculo.us
}
fx.linear = function(pos){
return pos;
}
fx.cubic = function(pos){
return Math.pow(pos, 3);
}
fx.circ = function(pos){
return Math.sqrt(pos);
}

View File

@@ -1,347 +0,0 @@
/*
moo.fx pack, effects extensions for moo.fx.
by Valerio Proietti (http://mad4milk.net) MIT-style LICENSE
for more info visit (http://moofx.mad4milk.net).
Friday, April 14, 2006
v 1.2.4
*/
//smooth scroll
fx.Scroll = Class.create();
fx.Scroll.prototype = Object.extend(new fx.Base(), {
initialize: function(options) {
this.setOptions(options);
},
scrollTo: function(el){
var dest = Position.cumulativeOffset($(el))[1];
var client = window.innerHeight || document.documentElement.clientHeight;
var full = document.documentElement.scrollHeight;
var top = window.pageYOffset || document.body.scrollTop || document.documentElement.scrollTop;
if (dest+client > full) this.custom(top, dest - client + (full-dest));
else this.custom(top, dest);
},
increase: function(){
window.scrollTo(0, this.now);
}
});
//text size modify, now works with pixels too.
fx.Text = Class.create();
fx.Text.prototype = Object.extend(new fx.Base(), {
initialize: function(el, options) {
this.el = $(el);
this.setOptions(options);
if (!this.options.unit) this.options.unit = "em";
},
increase: function() {
this.el.style.fontSize = this.now + this.options.unit;
}
});
//composition effect: widht/height/opacity
fx.Combo = Class.create();
fx.Combo.prototype = {
setOptions: function(options) {
this.options = {
opacity: true,
height: true,
width: false
}
Object.extend(this.options, options || {});
},
initialize: function(el, options) {
this.el = $(el);
this.setOptions(options);
if (this.options.opacity) {
this.o = new fx.Opacity(el, options);
options.onComplete = null;
}
if (this.options.height) {
this.h = new fx.Height(el, options);
options.onComplete = null;
}
if (this.options.width) this.w = new fx.Width(el, options);
},
toggle: function() { this.checkExec('toggle'); },
hide: function(){ this.checkExec('hide'); },
clearTimer: function(){ this.checkExec('clearTimer'); },
checkExec: function(func){
if (this.o) this.o[func]();
if (this.h) this.h[func]();
if (this.w) this.w[func]();
},
//only if width+height
resizeTo: function(hto, wto) {
if (this.h && this.w) {
this.h.custom(this.el.offsetHeight, this.el.offsetHeight + hto);
this.w.custom(this.el.offsetWidth, this.el.offsetWidth + wto);
}
},
customSize: function(hto, wto) {
if (this.h && this.w) {
this.h.custom(this.el.offsetHeight, hto);
this.w.custom(this.el.offsetWidth, wto);
}
}
}
fx.MultiFadeSize = Class.create();
fx.MultiFadeSize.prototype = {
setOptions: function(options) {
this.options = {
delay: 100,
opacity: false
}
Object.extend(this.options, options || {});
},
initialize: function(elements, options) {
this.elements = elements;
this.setOptions(options);
var options = options || '';
this.fxa = [];
if (options && options.onComplete) options.onFinish = options.onComplete;
elements.each(function(el, i){
options.onComplete = function(){
if (el.offsetHeight > 0) el.style.height = '1%';
if (options.onFinish) options.onFinish(el);
}
this.fxa[i] = new fx.Combo(el, options);
this.fxa[i].hide();
}.bind(this));
},
showThisHideOpen: function(toShow){
this.elements.each(function(el, j){
if (el.offsetHeight > 0 && el != toShow) this.clearAndToggle(el, j);
if (el == toShow && toShow.offsetHeight == 0) setTimeout(function(){this.clearAndToggle(toShow, j);}.bind(this), this.options.delay);
}.bind(this));
},
clearAndToggle: function(el, i){
this.fxa[i].clearTimer();
this.fxa[i].toggle();
},
showAll: function() {
for (i=0;i<this.elements.length;i++){
if (this.elements[i].offsetHeight == 0) {
this.clearAndToggle(this.elements[i], i)
}
}
showAll=1;
},
hideAll: function() {
for (i=0;i<this.elements.length;i++){
if (this.elements[i].offsetHeight > 0) {
this.clearAndToggle(this.elements[i], i)
}
}
showAll=1;
},
toggle: function(el){
el = $(el);
for (i=0;i<this.elements.length;i++){
if (this.elements[i] == el) {
this.clearAndToggle(this.elements[i], i)
}
}
},
hide: function(el){
el = $(el);
for (i=0;i<this.elements.length;i++){
if (this.elements[i] == el) {
this.fxa[i].hide();
}
}
}
}
fx.Accordion = Class.create();
fx.Accordion.prototype = {
setOptions: function(options) {
this.options = {
delay: 100,
opacity: false
}
Object.extend(this.options, options || {});
},
initialize: function(togglers, elements, options) {
this.elements = elements;
this.setOptions(options);
var options = options || '';
this.fxa = [];
if (options && options.onComplete) options.onFinish = options.onComplete;
elements.each(function(el, i){
options.onComplete = function(){
if (el.offsetHeight > 0) el.style.height = '1%';
if (options.onFinish) options.onFinish(el);
}
this.fxa[i] = new fx.Combo(el, options);
this.fxa[i].hide();
}.bind(this));
togglers.each(function(tog, i){
if (typeof tog.onclick == 'function') var exClick = tog.onclick;
tog.onclick = function(){
if (exClick) exClick();
this.showThisHideOpen(elements[i]);
}.bind(this);
}.bind(this));
},
showThisHideOpen: function(toShow){
this.elements.each(function(el, j){
if (el.offsetHeight > 0 && el != toShow) this.clearAndToggle(el, j);
if (el == toShow && toShow.offsetHeight == 0) setTimeout(function(){this.clearAndToggle(toShow, j);}.bind(this), this.options.delay);
}.bind(this));
},
clearAndToggle: function(el, i){
this.fxa[i].clearTimer();
this.fxa[i].toggle();
}
}
var Remember = new Object();
Remember = function(){};
Remember.prototype = {
initialize: function(el, options){
this.el = $(el);
this.days = 365;
this.options = options;
this.effect();
var cookie = this.readCookie();
if (cookie) {
this.fx.now = cookie;
this.fx.increase();
}
},
//cookie functions based on code by Peter-Paul Koch
setCookie: function(value) {
var date = new Date();
date.setTime(date.getTime()+(this.days*24*60*60*1000));
var expires = "; expires="+date.toGMTString();
document.cookie = this.el+this.el.id+this.prefix+"="+value+expires+"; path=/";
},
readCookie: function() {
var nameEQ = this.el+this.el.id+this.prefix + "=";
var ca = document.cookie.split(';');
for(var i=0;c=ca[i];i++) {
while (c.charAt(0)==' ') c = c.substring(1,c.length);
if (c.indexOf(nameEQ) == 0) return c.substring(nameEQ.length,c.length);
}
return false;
},
custom: function(from, to){
if (this.fx.now != to) {
this.setCookie(to);
this.fx.custom(from, to);
}
}
}
fx.RememberHeight = Class.create();
fx.RememberHeight.prototype = Object.extend(new Remember(), {
effect: function(){
this.fx = new fx.Height(this.el, this.options);
this.prefix = 'height';
},
toggle: function(){
if (this.el.offsetHeight == 0) this.setCookie(this.el.scrollHeight);
else this.setCookie(0);
this.fx.toggle();
},
resize: function(to){
this.setCookie(this.el.offsetHeight+to);
this.fx.custom(this.el.offsetHeight,this.el.offsetHeight+to);
},
hide: function(){
if (!this.readCookie()) {
this.fx.hide();
}
}
});
fx.RememberText = Class.create();
fx.RememberText.prototype = Object.extend(new Remember(), {
effect: function(){
this.fx = new fx.Text(this.el, this.options);
this.prefix = 'text';
}
});
//useful for-replacement
Array.prototype.iterate = function(func){
for(var i=0;i<this.length;i++) func(this[i], i);
}
if (!Array.prototype.each) Array.prototype.each = Array.prototype.iterate;
//Easing Equations (c) 2003 Robert Penner, all rights reserved.
//This work is subject to the terms in http://www.robertpenner.com/easing_terms_of_use.html.
//expo
fx.expoIn = function(pos){
return Math.pow(2, 10 * (pos - 1));
}
fx.expoOut = function(pos){
return (-Math.pow(2, -10 * pos) + 1);
}
//quad
fx.quadIn = function(pos){
return Math.pow(pos, 2);
}
fx.quadOut = function(pos){
return -(pos)*(pos-2);
}
//circ
fx.circOut = function(pos){
return Math.sqrt(1 - Math.pow(pos-1,2));
}
fx.circIn = function(pos){
return -(Math.sqrt(1 - Math.pow(pos, 2)) - 1);
}
//back
fx.backIn = function(pos){
return (pos)*pos*((2.7)*pos - 1.7);
}
fx.backOut = function(pos){
return ((pos-1)*(pos-1)*((2.7)*(pos-1) + 1.7) + 1);
}
//sine
fx.sineOut = function(pos){
return Math.sin(pos * (Math.PI/2));
}
fx.sineIn = function(pos){
return -Math.cos(pos * (Math.PI/2)) + 1;
}
fx.sineInOut = function(pos){
return -(Math.cos(Math.PI*pos) - 1)/2;
}

View File

@@ -1,132 +0,0 @@
/* Prototype JavaScript framework
* (c) 2005 Sam Stephenson <sam@conio.net>
* Prototype is freely distributable under the terms of an MIT-style license.
* For details, see the Prototype web site: http://prototype.conio.net/
/*--------------------------------------------------------------------------*/
//note: modified & stripped down version of prototype, to be used with moo.fx by mad4milk (http://moofx.mad4milk.net).
var Class = {
create: function() {
return function() {
this.initialize.apply(this, arguments);
}
}
}
Object.extend = function(destination, source) {
for (property in source) destination[property] = source[property];
return destination;
}
Function.prototype.bind = function(object) {
var __method = this;
return function() {
return __method.apply(object, arguments);
}
}
Function.prototype.bindAsEventListener = function(object) {
var __method = this;
return function(event) {
__method.call(object, event || window.event);
}
}
function $() {
if (arguments.length == 1) return get$(arguments[0]);
var elements = [];
$c(arguments).each(function(el){
elements.push(get$(el));
});
return elements;
function get$(el){
if (typeof el == 'string') el = document.getElementById(el);
return el;
}
}
if (!window.Element) var Element = new Object();
Object.extend(Element, {
remove: function(element) {
element = $(element);
element.parentNode.removeChild(element);
},
hasClassName: function(element, className) {
element = $(element);
if (!element) return;
var hasClass = false;
element.className.split(' ').each(function(cn){
if (cn == className) hasClass = true;
});
return hasClass;
},
addClassName: function(element, className) {
element = $(element);
Element.removeClassName(element, className);
element.className += ' ' + className;
},
removeClassName: function(element, className) {
element = $(element);
if (!element) return;
var newClassName = '';
element.className.split(' ').each(function(cn, i){
if (cn != className){
if (i > 0) newClassName += ' ';
newClassName += cn;
}
});
element.className = newClassName;
},
cleanWhitespace: function(element) {
element = $(element);
$c(element.childNodes).each(function(node){
if (node.nodeType == 3 && !/\S/.test(node.nodeValue)) Element.remove(node);
});
},
find: function(element, what) {
element = $(element)[what];
while (element.nodeType != 1) element = element[what];
return element;
}
});
var Position = {
cumulativeOffset: function(element) {
var valueT = 0, valueL = 0;
do {
valueT += element.offsetTop || 0;
valueL += element.offsetLeft || 0;
element = element.offsetParent;
} while (element);
return [valueL, valueT];
}
};
document.getElementsByClassName = function(className) {
var children = document.getElementsByTagName('*') || document.all;
var elements = [];
$c(children).each(function(child){
if (Element.hasClassName(child, className)) elements.push(child);
});
return elements;
}
//useful array functions
Array.prototype.iterate = function(func){
for(var i=0;i<this.length;i++) func(this[i], i);
}
if (!Array.prototype.each) Array.prototype.each = Array.prototype.iterate;
function $c(array){
var nArray = [];
for (var i=0;i<array.length;i++) nArray.push(array[i]);
return nArray;
}

View File

@@ -1,107 +0,0 @@
#!/usr/bin/perl -w
# -*- mode: cperl; c-basic-offset: 8; indent-tabs-mode: nil; -*-
# ***** 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) 2006
# the Initial Developer. All Rights Reserved.
#
# Contributor(s):
# Chris Cooper <ccooper@deadsquid.com>
# Zach Lipton <zach@zachlipton.com>
#
# ***** END LICENSE BLOCK *****
use strict;
use Litmus;
use Litmus::Auth;
use Litmus::Error;
use Text::Markdown;
use JSON;
use CGI;
use Date::Manip;
Litmus->init();
my $c = Litmus->cgi();
print $c->header('text/plain');
if ($c->param("testcase_id")) {
my $testcase_id = $c->param("testcase_id");
my $testcase = Litmus::DB::Testcase->retrieve($testcase_id);
my @testgroups = Litmus::DB::Testgroup->search_EnabledByTestcase($testcase_id);
my @subgroups = Litmus::DB::Subgroup->search_EnabledByTestcase($testcase_id);
$testcase->{'testgroups'} = \@testgroups;
$testcase->{'subgroups'} = \@subgroups;
my $json = JSON->new(skipinvalid => 1, convblessed => 1);
# apply markdown formatting to the steps and expected results:
$testcase->{'steps_formatted'} = Text::Markdown::markdown($testcase->steps());
$testcase->{'expected_results_formatted'} = Text::Markdown::markdown($testcase->expected_results());
my $js = $json->objToJson($testcase);
print $js;
} elsif ($c->param("subgroup_id")) {
my $subgroup_id = $c->param("subgroup_id");
my $subgroup = Litmus::DB::Subgroup->retrieve($subgroup_id);
my @testgroups = Litmus::DB::Testgroup->search_EnabledBySubgroup($subgroup_id);
my @testcases = Litmus::DB::Testcase->search_EnabledBySubgroup($subgroup_id);
$subgroup->{'testgroups'} = \@testgroups;
$subgroup->{'testcases'} = \@testcases;
my $json = JSON->new(skipinvalid => 1, convblessed => 1);
my $js = $json->objToJson($subgroup);
print $js;
} elsif ($c->param("testgroup_id")) {
my $testgroup_id = $c->param("testgroup_id");
my $testgroup = Litmus::DB::Testgroup->retrieve($testgroup_id);
my @subgroups = Litmus::DB::Subgroup->search_EnabledByTestgroup($testgroup_id);
$testgroup->{'subgroups'} = \@subgroups;
my $json = JSON->new(skipinvalid => 1, convblessed => 1);
my $js = $json->objToJson($testgroup);
print $js;
} elsif ($c->param("product_id")) {
my $product_id = $c->param("product_id");
my $product = Litmus::DB::Product->retrieve($product_id);
my $json = JSON->new(skipinvalid => 1, convblessed => 1);
my $js = $json->objToJson($product);
print $js;
} elsif ($c->param("platform_id")) {
my $platform_id = $c->param("platform_id");
my $platform = Litmus::DB::Platform->retrieve($platform_id);
my @products = Litmus::DB::Product->search_ByPlatform($platform_id);
$platform->{'products'} = \@products;
my $json = JSON->new(skipinvalid => 1, convblessed => 1);
my $js = $json->objToJson($platform);
print $js;
} elsif ($c->param("opsys_id")) {
my $opsys_id = $c->param("opsys_id");
my $opsys = Litmus::DB::Opsys->retrieve($opsys_id);
my $json = JSON->new(skipinvalid => 1, convblessed => 1);
my $js = $json->objToJson($opsys);
print $js;
} elsif ($c->param("branch_id")) {
my $branch_id = $c->param("branch_id");
my $branch = Litmus::DB::Branch->retrieve($branch_id);
my $json = JSON->new(skipinvalid => 1, convblessed => 1);
my $js = $json->objToJson($branch);
print $js;
}

View File

@@ -1,45 +0,0 @@
#!/usr/bin/perl -w
# -*- mode: cperl; c-basic-offset: 8; indent-tabs-mode: nil; -*-
# ***** 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) 2006
# the Initial Developer. All Rights Reserved.
#
# Contributor(s):
# Chris Cooper <ccooper@deadsquid.com>
# Zach Lipton <zach@zachlipton.com>
#
# ***** END LICENSE BLOCK *****
use strict;
$|++;
use Litmus;
use Litmus::Auth;
Litmus->init();
use CGI;
my $title = "Log in";
Litmus::Auth::requireLogin("index.cgi");
exit;

View File

@@ -1,56 +0,0 @@
#!/usr/bin/perl -w
# -*- mode: cperl; c-basic-offset: 8; indent-tabs-mode: nil; -*-
# ***** 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) 2006
# the Initial Developer. All Rights Reserved.
#
# Contributor(s):
# Chris Cooper <ccooper@deadsquid.com>
# Zach Lipton <zach@zachlipton.com>
#
# ***** END LICENSE BLOCK *****
use strict;
$|++;
use Litmus;
use Litmus::Auth;
Litmus->init();
my $title = "Log out";
Litmus::Auth::logout();
my $c = Litmus->cgi();
print $c->header();
my $vars = {
title => $title,
};
Litmus->template()->process("logout.tmpl", $vars) ||
internalError(Litmus->template()->error());
exit;

View File

@@ -1,352 +0,0 @@
#!/usr/bin/perl -w
# -*- mode: cperl; c-basic-offset: 8; indent-tabs-mode: nil; -*-
# ***** 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) 2006
# the Initial Developer. All Rights Reserved.
#
# Contributor(s):
# Chris Cooper <ccooper@deadsquid.com>
# Zach Lipton <zach@zachlipton.com>
#
# ***** END LICENSE BLOCK *****
use strict;
$|++;
#use Time::HiRes qw( gettimeofday tv_interval );
#my $t0 = [gettimeofday];
use Litmus;
use Litmus::Auth;
use Litmus::Cache;
use Litmus::Error;
use Litmus::FormWidget;
use CGI;
use Time::Piece::MySQL;
Litmus->init();
Litmus::Auth::requireAdmin("edit_categories.cgi");
my $c = Litmus->cgi();
print $c->header();
my $message;
my $status;
my $rv;
my $rebuild_cache = 0;
my $defaults;
if ($c->param) {
# Process product changes.
if ($c->param("delete_product_button") and
$c->param("product_id")) {
my $product_id = $c->param("product_id");
my $product = Litmus::DB::Product->retrieve($product_id);
if ($product) {
$rv = $product->delete_with_refs();
if ($rv) {
$status = "success";
$message = "Product ID# $product_id deleted successfully.";
$rebuild_cache=1;
} else {
$status = "failure";
$message = "Failed to delete Product ID# $product_id.";
}
} else {
$status = "failure";
$message = "Product ID# $product_id does not exist. (Already deleted?)";
}
} elsif ($c->param("edit_product_form_mode")) {
my $enabled = $c->param('edit_product_form_enabled') ? 1 : 0;
if ($c->param("edit_product_form_mode") eq "add") {
my %hash = (
name => $c->param('edit_product_form_name'),
iconpath => $c->param('edit_product_form_iconpath'),
enabled => $enabled,
);
my $new_product =
Litmus::DB::Product->create(\%hash);
if ($new_product) {
$status = "success";
$message = "Product added successfully. New product ID# is " . $new_product->product_id;
$defaults->{'product_id'} = $new_product->product_id;
$rebuild_cache=1;
} else {
$status = "failure";
$message = "Failed to add product.";
}
} elsif ($c->param("edit_product_form_mode") eq "edit") {
my $product_id = $c->param("edit_product_form_product_id");
my $product = Litmus::DB::Product->retrieve($product_id);
if ($product) {
$product->name($c->param('edit_product_form_name'));
$product->iconpath($c->param('edit_product_form_iconpath') ? $c->param('edit_product_form_iconpath') : '');
$product->enabled($enabled);
$rv = $product->update();
if ($rv) {
$status = "success";
$message = "Product ID# $product_id updated successfully.";
$defaults->{'product_id'} = $product_id;
$rebuild_cache=1;
} else {
$status = "failure";
$message = "Failed to update product ID# $product_id.";
}
} else {
$status = "failure";
$message = "Product ID# $product_id not found.";
}
}
}
# Process platform changes.
if ($c->param("delete_platform_button") and
$c->param("platform_id")) {
my $platform_id = $c->param("platform_id");
my $platform = Litmus::DB::Platform->retrieve($platform_id);
if ($platform) {
$rv = $platform->delete_with_refs();
if ($rv) {
$status = "success";
$message = "Platform ID# $platform_id deleted successfully.";
$rebuild_cache=1;
} else {
$status = "failure";
$message = "Failed to delete Platform ID# $platform_id.";
}
} else {
$status = "failure";
$message = "Platform ID# $platform_id does not exist. (Already deleted?)";
}
} elsif ($c->param("edit_platform_form_mode")) {
if ($c->param("edit_platform_form_mode") eq "add") {
my %hash = (
name => $c->param('edit_platform_form_name'),
iconpath => $c->param('edit_platform_form_iconpath'),
detect_regexp => $c->param('edit_platform_form_detect_regexp'),
);
my $new_platform =
Litmus::DB::Platform->create(\%hash);
if ($new_platform) {
my @selected_products = $c->param("edit_platform_form_platform_products");
$new_platform->update_products(\@selected_products);
$status = "success";
$message = "Platform added successfully. New platform ID# is " . $new_platform->platform_id;
$defaults->{'platform_id'} = $new_platform->platform_id;
$rebuild_cache=1;
} else {
$status = "failure";
$message = "Failed to add platform.";
}
} elsif ($c->param("edit_platform_form_mode") eq "edit") {
my $platform_id = $c->param("edit_platform_form_platform_id");
my $platform = Litmus::DB::Platform->retrieve($platform_id);
if ($platform) {
$platform->name($c->param('edit_platform_form_name'));
$platform->iconpath($c->param('edit_platform_form_iconpath') ? $c->param('edit_platform_form_iconpath') : '');
$platform->detect_regexp($c->param('edit_platform_form_detect_regexp') ? $c->param('edit_platform_form_detect_regexp') : '');
$rv = $platform->update();
if ($rv) {
my @selected_products = $c->param("edit_platform_form_platform_products");
$platform->update_products(\@selected_products);
$status = "success";
$message = "Platform ID# $platform_id updated successfully.";
$defaults->{'platform_id'} = $platform_id;
$rebuild_cache=1;
} else {
$status = "failure";
$message = "Failed to update platform ID# $platform_id.";
}
} else {
$status = "failure";
$message = "Platform ID# $platform_id not found.";
}
}
}
# Process opsys changes.
if ($c->param("delete_opsys_button") and
$c->param("opsys_id")) {
my $opsys_id = $c->param("opsys_id");
my $opsys = Litmus::DB::Opsys->retrieve($opsys_id);
if ($opsys) {
$rv = $opsys->delete;
if ($rv) {
$status = "success";
$message = "Operating system ID# $opsys_id deleted successfully.";
$rebuild_cache=1;
} else {
$status = "failure";
$message = "Failed to delete Operating system ID# $opsys_id.";
}
} else {
$status = "failure";
$message = "Operating system ID# $opsys_id does not exist. (Already deleted?)";
}
} elsif ($c->param("edit_opsys_form_mode")) {
if ($c->param("edit_opsys_form_mode") eq "add") {
my %hash = (
name => $c->param('edit_opsys_form_name'),
platform_id => $c->param('edit_opsys_form_platform_id'),
detect_regexp => $c->param('edit_opsys_form_detect_regexp'),
);
my $new_opsys =
Litmus::DB::Opsys->create(\%hash);
if ($new_opsys) {
$status = "success";
$message = "Operating system added successfully. New operating system ID# is " . $new_opsys->opsys_id;
$defaults->{'opsys_id'} = $new_opsys->opsys_id;
$rebuild_cache=1;
} else {
$status = "failure";
$message = "Failed to add operating system.";
}
} elsif ($c->param("edit_opsys_form_mode") eq "edit") {
my $opsys_id = $c->param("edit_opsys_form_opsys_id");
my $opsys = Litmus::DB::Opsys->retrieve($opsys_id);
if ($opsys) {
$opsys->name($c->param('edit_opsys_form_name'));
$opsys->platform_id($c->param('edit_opsys_form_platform_id'));
$opsys->detect_regexp($c->param('edit_opsys_form_detect_regexp') ? $c->param('edit_opsys_form_detect_regexp') : '');
$rv = $opsys->update();
if ($rv) {
$status = "success";
$message = "Operating system ID# $opsys_id updated successfully.";
$defaults->{'opsys_id'} = $opsys_id;
$rebuild_cache=1;
} else {
$status = "failure";
$message = "Failed to update operating system ID# $opsys_id.";
}
} else {
$status = "failure";
$message = "Operating systen ID# $opsys_id not found.";
}
}
}
# Process branch changes.
if ($c->param("delete_branch_button") and
$c->param("branch_id")) {
my $branch_id = $c->param("branch_id");
my $branch = Litmus::DB::Branch->retrieve($branch_id);
if ($branch) {
$rv = $branch->delete;
if ($rv) {
$status = "success";
$message = "Branch ID# $branch_id deleted successfully.";
$rebuild_cache=1;
} else {
$status = "failure";
$message = "Failed to delete branch ID# $branch_id.";
}
} else {
$status = "failure";
$message = "Branch ID# $branch_id does not exist. (Already deleted?)";
}
} elsif ($c->param("edit_branch_form_mode")) {
my $enabled = $c->param('edit_branch_form_enabled') ? 1 : 0;
if ($c->param("edit_branch_form_mode") eq "add") {
my %hash = (
name => $c->param('edit_branch_form_name'),
product_id => $c->param('edit_branch_form_product_id'),
detect_regexp => $c->param('edit_branch_form_detect_regexp'),
enabled => $enabled,
);
my $new_branch =
Litmus::DB::Branch->create(\%hash);
if ($new_branch) {
$status = "success";
$message = "Branch added successfully. New branch ID# is " . $new_branch->branch_id;
$defaults->{'branch_id'} = $new_branch->branch_id;
$rebuild_cache=1;
} else {
$status = "failure";
$message = "Failed to add branch.";
}
} elsif ($c->param("edit_branch_form_mode") eq "edit") {
my $branch_id = $c->param("edit_branch_form_branch_id");
my $branch = Litmus::DB::Branch->retrieve($branch_id);
if ($branch) {
$branch->name($c->param('edit_branch_form_name'));
$branch->product_id($c->param('edit_branch_form_product_id'));
$branch->detect_regexp($c->param('edit_branch_form_detect_regexp') ? $c->param('edit_branch_form_detect_regexp') : '');
$branch->enabled($enabled);
$rv = $branch->update();
if ($rv) {
$status = "success";
$message = "Branch ID# $branch_id updated successfully.";
$defaults->{'branch_id'} = $branch_id;
$rebuild_cache=1;
} else {
$status = "failure";
$message = "Failed to update branch ID# $branch_id.";
}
} else {
$status = "failure";
$message = "Branch ID# $branch_id not found.";
}
}
}
}
if ($rebuild_cache) {
rebuildCache();
}
my $products = Litmus::FormWidget->getProducts();
my $platforms = Litmus::FormWidget->getPlatforms();
my $branches = Litmus::FormWidget->getBranches();
my $opsyses = Litmus::FormWidget->getOpsyses();
my $vars = {
title => 'Manage Categories',
products => $products,
platforms => $platforms,
branches => $branches,
opsyses => $opsyses,
};
if ($status and $message) {
$vars->{'onload'} = "toggleMessage('$status','$message');";
}
my $cookie = Litmus::Auth::getCookie();
$vars->{"defaultemail"} = $cookie;
$vars->{"show_admin"} = Litmus::Auth::istrusted($cookie);
Litmus->template()->process("admin/edit_categories.tmpl", $vars) ||
internalError(Litmus->template()->error());
#my $elapsed = tv_interval ( $t0 );
#printf "<div id='pageload'>Page took %f seconds to load.</div>", $elapsed;
exit 0;

View File

@@ -1,200 +0,0 @@
#!/usr/bin/perl -w
# -*- mode: cperl; c-basic-offset: 8; indent-tabs-mode: nil; -*-
# ***** 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) 2006
# the Initial Developer. All Rights Reserved.
#
# Contributor(s):
# Chris Cooper <ccooper@deadsquid.com>
# Zach Lipton <zach@zachlipton.com>
#
# ***** END LICENSE BLOCK *****
use strict;
use Litmus;
use Litmus::Auth;
use Litmus::Cache;
use Litmus::Error;
use Litmus::FormWidget;
use Litmus::Utils;
use CGI;
use Date::Manip;
use JSON;
Litmus->init();
my $c = Litmus->cgi();
my $vars;
my $subgroup_id;
my $message;
my $status;
my $rv;
if ($c->param("searchSubgroupList")) {
print $c->header('text/plain');
my $product_id = $c->param("product");
my $testgroup_id = $c->param("testgroup");
my $subgroups;
if ($testgroup_id) {
$subgroups = Litmus::DB::Subgroup->search_ByTestgroup($testgroup_id);
} elsif ($product_id) {
$subgroups = Litmus::DB::Subgroup->search(product => $product_id);
}
while (my $sg = $subgroups->next) {
print $sg->subgroup_id()."\n";
}
exit;
}
# anyone can use this script for its searching capabilities, but if we
# get here, then you need to be an admin:
Litmus::Auth::requireAdmin('manage_subgroups.cgi');
if ($c->param("subgroup_id")) {
$subgroup_id = $c->param("subgroup_id");
}
my $rebuild_cache = 0;
my $defaults;
if ($c->param("delete_subgroup_button")) {
my $subgroup = Litmus::DB::Subgroup->retrieve($subgroup_id);
if ($subgroup) {
$rv = $subgroup->delete_with_refs();
if ($rv) {
$status = "success";
$message = "Subgroup ID# $subgroup_id deleted successfully.";
$rebuild_cache = 1;
} else {
$status = "failure";
$message = "Failed to delete Subgroup ID# $subgroup_id.";
}
} else {
$status = "failure";
$message = "Subgroup ID# $subgroup_id does not exist. (Already deleted?)";
}
} elsif ($c->param("clone_subgroup_button")) {
my $subgroup = Litmus::DB::Subgroup->retrieve($subgroup_id);
my $new_subgroup = $subgroup->clone;
if ($new_subgroup) {
$status = "success";
$message = "Subgroup cloned successfully. New subgroup ID# is " . $new_subgroup->subgroup_id;
$defaults->{'subgroup_id'} = $new_subgroup->subgroup_id;
$rebuild_cache = 1;
} else {
$status = "failure";
$message = "Failed to clone Subgroup ID# $subgroup_id.";
}
} elsif ($c->param("editform_mode")) {
requireField('product', $c->param('product'));
requireField('testgroup', $c->param('testgroup'));
my $enabled = $c->param('editform_enabled') ? 1 : 0;
if ($c->param("editform_mode") eq "add") {
my %hash = (
name => $c->param('editform_name'),
product_id => $c->param('product'),
enabled => $enabled,
);
my $new_subgroup =
Litmus::DB::Subgroup->create(\%hash);
if ($new_subgroup) {
my @selected_testgroups = $c->param("testgroup");
$new_subgroup->update_testgroups(\@selected_testgroups);
my @selected_testcases = $c->param("editform_subgroup_testcases");
$new_subgroup->update_testcases(\@selected_testcases);
$status = "success";
$message = "Subgroup added successfully. New subgroup ID# is " . $new_subgroup->subgroup_id;
$defaults->{'subgroup_id'} = $new_subgroup->subgroup_id;
$rebuild_cache = 1;
} else {
$status = "failure";
$message = "Failed to add subgroup.";
}
} elsif ($c->param("editform_mode") eq "edit") {
requireField('subgroup_id', $c->param("editform_subgroup_id"));
$subgroup_id = $c->param("editform_subgroup_id");
my $subgroup = Litmus::DB::Subgroup->retrieve($subgroup_id);
if ($subgroup) {
$subgroup->product_id($c->param('editform_product'));
$subgroup->enabled($enabled);
$subgroup->name($c->param('editform_name'));
$rv = $subgroup->update();
if ($rv) {
my @selected_testgroups = $c->param("testgroup");
$subgroup->update_testgroups(\@selected_testgroups);
my @selected_testcases = $c->param("editform_subgroup_testcases");
$subgroup->update_testcases(\@selected_testcases);
$status = "success";
$message = "Subgroup ID# $subgroup_id updated successfully.";
$defaults->{'subgroup_id'} = $subgroup_id;
$rebuild_cache = 1;
} else {
$status = "failure";
$message = "Failed to update subgroup ID# $subgroup_id.";
}
} else {
$status = "failure";
$message = "Subgroup ID# $subgroup_id not found.";
}
}
} else {
$defaults->{'subgroup_id'} = $c->param("subgroup_id");
}
if ($defaults) {
$vars->{'defaults'} = $defaults;
}
if ($status and $message) {
$vars->{'onload'} = "toggleMessage('$status','$message');";
}
if ($rebuild_cache) {
rebuildCache();
}
my $subgroups = Litmus::FormWidget->getSubgroups;
my $products = Litmus::FormWidget->getProducts();
my $testcases = Litmus::FormWidget->getTestcases;
my $json = JSON->new(skipinvalid => 1, convblessed => 1);
my $testcases_js = $json->objToJson($testcases);
$vars->{'title'} = "Manage Subgroups";
$vars->{'subgroups'} = $subgroups;
$vars->{'products'} = $products;
$vars->{'all_testcases'} = $testcases_js;
$vars->{'user'} = Litmus::Auth::getCurrentUser();
my $cookie = Litmus::Auth::getCookie();
$vars->{"defaultemail"} = $cookie;
$vars->{"show_admin"} = Litmus::Auth::istrusted($cookie);
print $c->header();
Litmus->template()->process("admin/manage_subgroups.tmpl", $vars) ||
internalError("Error loading template.");

View File

@@ -1,218 +0,0 @@
#!/usr/bin/perl -w
# -*- mode: cperl; c-basic-offset: 8; indent-tabs-mode: nil; -*-
# ***** 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) 2006
# the Initial Developer. All Rights Reserved.
#
# Contributor(s):
# Chris Cooper <ccooper@deadsquid.com>
# Zach Lipton <zach@zachlipton.com>
#
# ***** END LICENSE BLOCK *****
use strict;
use Litmus;
use Litmus::Auth;
use Litmus::Cache;
use Litmus::Error;
use Litmus::FormWidget;
use Litmus::Utils;
use CGI;
use Date::Manip;
Litmus->init();
my $c = Litmus->cgi();
my $vars;
my $testcase_id;
my $edit;
my $message;
my $status;
my $rv;
if ($c->param("searchTestcaseList")) {
print $c->header('text/plain');
my $product_id = $c->param("product");
my $testgroup_id = $c->param("testgroup");
my $subgroup_id = $c->param("subgroup");
my $tests;
if ($subgroup_id) {
$tests = Litmus::DB::Testcase->search_BySubgroup($subgroup_id);
} elsif ($testgroup_id) {
$tests = Litmus::DB::Testcase->search_ByTestgroup($testgroup_id);
} elsif ($product_id) {
$tests = Litmus::DB::Testcase->search(product => $product_id);
}
while (my $t = $tests->next) {
print $t->testcase_id()."\n";
}
exit;
}
# anyone can use this script for its searching capabilities, but if we
# get here, then you need to be an admin:
Litmus::Auth::requireAdmin('manage_testcases.cgi');
if ($c->param("testcase_id")) {
$testcase_id = $c->param("testcase_id");
if ($c->param("edit")) {
$edit = $testcase_id;
}
}
my $rebuild_cache = 0;
my $defaults;
if ($c->param("delete_testcase_button")) {
my $testcase = Litmus::DB::Testcase->retrieve($testcase_id);
if ($testcase) {
$rv = $testcase->delete_with_refs();
if ($rv) {
$status = "success";
$message = "Testcase ID# $testcase_id deleted successfully.";
$rebuild_cache=1;
} else {
$status = "failure";
$message = "Failed to delete Testcase ID# $testcase_id.";
}
} else {
$status = "failure";
$message = "Testcase ID# $testcase_id does not exist. (Already deleted?)";
}
} elsif ($c->param("clone_testcase_button")) {
my $testcase = Litmus::DB::Testcase->retrieve($testcase_id);
my $new_testcase = $testcase->clone;
if ($new_testcase) {
$status = "success";
$message = "Testcase cloned successfully. New testcase ID# is " . $new_testcase->testcase_id;
$defaults->{'testcase_id'} = $new_testcase->testcase_id;
$rebuild_cache=1;
} else {
$status = "failure";
$message = "Failed to clone Testcase ID# $testcase_id.";
}
} elsif ($c->param("editform_mode")) {
requireField('summary', $c->param('editform_summary'));
requireField('product', $c->param('product'));
requireField('subgroup', $c->param('subgroup'));
requireField('author', $c->param('editform_author_id'));
my $enabled = $c->param('editform_enabled') ? 1 : 0;
my $community_enabled = $c->param('editform_communityenabled') ? 1 : 0;
my $now = &UnixDate("today","%q");
if ($c->param("editform_mode") eq "add") {
my %hash = (
summary => $c->param('editform_summary'),
steps => $c->param('editform_steps') ? $c->param('editform_steps') : '',
expected_results => $c->param('editform_results') ? $c->param('editform_results') : '',
product_id => $c->param('product'),
enabled => $enabled,
community_enabled => $community_enabled,
regression_bug_id => $c->param('editform_regression_bug_id') ? $c->param('editform_regression_bug_id') : '',
author_id => $c->param('editform_author_id'),
creation_date => $now,
last_updated => $now,
);
my $new_testcase =
Litmus::DB::Testcase->create(\%hash);
if ($new_testcase) {
my @selected_subgroups = $c->param("subgroup");
$new_testcase->update_subgroups(\@selected_subgroups);
$status = "success";
$message = "Testcase added successfully. New testcase ID# is " . $new_testcase->testcase_id;
$defaults->{'testcase_id'} = $new_testcase->testcase_id;
$rebuild_cache=1;
} else {
$status = "failure";
$message = "Failed to add testcase.";
}
} elsif ($c->param("editform_mode") eq "edit") {
requireField('testcase_id', $c->param("editform_testcase_id"));
$testcase_id = $c->param("editform_testcase_id");
my $testcase = Litmus::DB::Testcase->retrieve($testcase_id);
if ($testcase) {
$testcase->summary($c->param('editform_summary'));
$testcase->steps($c->param('editform_steps') ? $c->param('editform_steps') : '');
$testcase->expected_results($c->param('editform_results') ? $c->param('editform_results') : '');
$testcase->product_id($c->param('product'));
$testcase->enabled($enabled);
$testcase->community_enabled($community_enabled);
$testcase->regression_bug_id($c->param('editform_regression_bug_id') ? $c->param('editform_regression_bug_id') : '');
$testcase->author_id($c->param('editform_author_id'));
$testcase->last_updated($now);
$testcase->version($testcase->version + 1);
$rv = $testcase->update();
if ($rv) {
my @selected_subgroups = $c->param("subgroup");
$testcase->update_subgroups(\@selected_subgroups);
$status = "success";
$message = "Testcase ID# $testcase_id updated successfully.";
$defaults->{'testcase_id'} = $testcase_id;
$rebuild_cache=1;
} else {
$status = "failure";
$message = "Failed to update testcase ID# $testcase_id.";
}
} else {
$status = "failure";
$message = "Testcase ID# $testcase_id not found.";
}
}
} else {
$defaults->{'testcase_id'} = $c->param("testcase_id");
}
if ($defaults) {
$vars->{'defaults'} = $defaults;
}
if ($status and $message) {
$vars->{'onload'} = "toggleMessage('$status','$message');";
}
if ($rebuild_cache) {
rebuildCache();
}
my $testcases = Litmus::FormWidget->getTestcases();
my $products = Litmus::FormWidget->getProducts();
my $authors = Litmus::FormWidget->getAuthors();
$vars->{'title'} = "Manage Testcases";
$vars->{'testcases'} = $testcases;
$vars->{'products'} = $products;
$vars->{'authors'} = $authors;
$vars->{'user'} = Litmus::Auth::getCurrentUser();
$vars->{'edit'} = $edit;
my $cookie = Litmus::Auth::getCookie();
$vars->{"defaultemail"} = $cookie;
$vars->{"show_admin"} = Litmus::Auth::istrusted($cookie);
print $c->header();
Litmus->template()->process("admin/manage_testcases.tmpl", $vars) ||
internalError("Error loading template: ".Litmus->template()->error());

View File

@@ -1,189 +0,0 @@
#!/usr/bin/perl -w
# -*- mode: cperl; c-basic-offset: 8; indent-tabs-mode: nil; -*-
# ***** 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) 2006
# the Initial Developer. All Rights Reserved.
#
# Contributor(s):
# Chris Cooper <ccooper@deadsquid.com>
# Zach Lipton <zach@zachlipton.com>
#
# ***** END LICENSE BLOCK *****
use strict;
use Litmus;
use Litmus::Auth;
use Litmus::Cache;
use Litmus::Error;
use Litmus::FormWidget;
use Litmus::Utils;
use CGI;
use Date::Manip;
use JSON;
Litmus->init();
my $c = Litmus->cgi();
my $vars;
my $testgroup_id;
my $message;
my $status;
my $rv;
if ($c->param("searchTestgroupList")) {
print $c->header('text/plain');
my $product_id = $c->param("product");
my $testgroups = Litmus::DB::Testgroup->search(product => $product_id);
while (my $tg = $testgroups->next) {
print $tg->testgroup_id()."\n";
}
exit;
}
# anyone can use this script for its searching capabilities, but if we
# get here, then you need to be an admin:
Litmus::Auth::requireAdmin('manage_testgroups.cgi');
if ($c->param("testgroup_id")) {
$testgroup_id = $c->param("testgroup_id");
}
my $rebuild_cache = 0;
my $defaults;
if ($c->param("delete_testgroup_button")) {
my $testgroup = Litmus::DB::Testgroup->retrieve($testgroup_id);
if ($testgroup) {
$rv = $testgroup->delete_with_refs();
if ($rv) {
$status = "success";
$message = "Testgroup ID# $testgroup_id deleted successfully.";
$rebuild_cache = 1;
} else {
$status = "failure";
$message = "Failed to delete Testgroup ID# $testgroup_id.";
}
} else {
$status = "failure";
$message = "Testgroup ID# $testgroup_id does not exist. (Already deleted?)";
}
} elsif ($c->param("clone_testgroup_button")) {
my $testgroup = Litmus::DB::Testgroup->retrieve($testgroup_id);
my $new_testgroup = $testgroup->clone;
if ($new_testgroup) {
$status = "success";
$message = "Testgroup cloned successfully. New testgroup ID# is " . $new_testgroup->testgroup_id;
$defaults->{'testgroup_id'} = $new_testgroup->testgroup_id;
$rebuild_cache = 1;
} else {
$status = "failure";
$message = "Failed to clone Testgroup ID# $testgroup_id.";
}
} elsif ($c->param("editform_mode")) {
requireField('product', $c->param('product'));
my $enabled = $c->param('editform_enabled') ? 1 : 0;
if ($c->param("editform_mode") eq "add") {
my %hash = (
name => $c->param('editform_name'),
product_id => $c->param('product'),
enabled => $enabled,
);
my $new_testgroup =
Litmus::DB::Testgroup->create(\%hash);
if ($new_testgroup) {
my @selected_subgroups = $c->param("editform_testgroup_subgroups");
$new_testgroup->update_subgroups(\@selected_subgroups);
# XXX: Placeholder for updating test runs
$status = "success";
$message = "Testgroup added successfully. New testgroup ID# is " . $new_testgroup->testgroup_id;
$defaults->{'testgroup_id'} = $new_testgroup->testgroup_id;
$rebuild_cache = 1;
} else {
$status = "failure";
$message = "Failed to add testgroup.";
}
} elsif ($c->param("editform_mode") eq "edit") {
requireField('testgroup_id', $c->param("editform_testgroup_id"));
$testgroup_id = $c->param("editform_testgroup_id");
my $testgroup = Litmus::DB::Testgroup->retrieve($testgroup_id);
if ($testgroup) {
$testgroup->product_id($c->param('editform_product'));
$testgroup->enabled($enabled);
$testgroup->name($c->param('editform_name'));
$rv = $testgroup->update();
if ($rv) {
my @selected_subgroups = $c->param("editform_testgroup_subgroups");
$testgroup->update_subgroups(\@selected_subgroups);
# XXX: Placeholder for updating test runs
$status = "success";
$message = "Testgroup ID# $testgroup_id updated successfully.";
$defaults->{'testgroup_id'} = $testgroup_id;
$rebuild_cache = 1;
} else {
$status = "failure";
$message = "Failed to update testgroup ID# $testgroup_id.";
}
} else {
$status = "failure";
$message = "Testgroup ID# $testgroup_id not found.";
}
}
} else {
$defaults->{'testgroup_id'} = $c->param("testgroup_id");
}
if ($defaults) {
$vars->{'defaults'} = $defaults;
}
if ($status and $message) {
$vars->{'onload'} = "toggleMessage('$status','$message');";
}
if ($rebuild_cache) {
rebuildCache();
}
my $testgroups = Litmus::FormWidget->getTestgroups;
my $products = Litmus::FormWidget->getProducts();
my $subgroups = Litmus::FormWidget->getSubgroups;
my $json = JSON->new(skipinvalid => 1, convblessed => 1);
my $subgroups_js = $json->objToJson($subgroups);
$vars->{'title'} = "Manage Testgroups";
$vars->{'testgroups'} = $testgroups;
$vars->{'products'} = $products;
$vars->{'all_subgroups'} = $subgroups_js;
$vars->{'user'} = Litmus::Auth::getCurrentUser();
my $cookie = Litmus::Auth::getCookie();
$vars->{"defaultemail"} = $cookie;
$vars->{"show_admin"} = Litmus::Auth::istrusted($cookie);
print $c->header();
Litmus->template()->process("admin/manage_testgroups.tmpl", $vars) ||
internalError("Error loading template.");

View File

@@ -1,279 +0,0 @@
#!/usr/bin/perl -w
# -*- mode: cperl; c-basic-offset: 8; indent-tabs-mode: nil; -*-
# ***** 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) 2006
# the Initial Developer. All Rights Reserved.
#
# Contributor(s):
# Chris Cooper <ccooper@deadsquid.com>
# Zach Lipton <zach@zachlipton.com>
#
# ***** END LICENSE BLOCK *****
use strict;
use Getopt::Long;
use Litmus::Config;
use DBI;
$|++;
my $reset_db;
my $help;
GetOptions('help|?' => \$help,'r|resetdb' => \$reset_db);
if ($help) {
&usage;
exit;
}
unless (-e "data/") {
system("mkdir", "data/");
}
system("chmod -R 777 data/");
unless (-e "localconfig") {
open(OUT, ">localconfig");
print OUT <<EOT;
our \$db_host = "";
our \$db_name = "";
our \$db_user = "";
our \$db_pass = "";
our \$user_cookiename = "litmus_login";
our \$sysconfig_cookiename = "litmustestingconfiguration";
our \$tr_host = "";
our \$tr_name = "";
our \$tr_user = "";
our \$tr_pass = "";
our \$bugzilla_auth_enabled = 1;
our \$bugzilla_db = "bugzilla";
our \$bugzilla_host = "localhost";
our \$bugzilla_user = "litmus";
our \$bugzilla_pass = "litmus";
EOT
close(OUT);
print "Go edit 'localconfig' with your configuration and \n";
print "run this script again.";
exit;
}
# 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";
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";
}
# 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: anything changed here should also be added to schema.pl for new
# installations
use Litmus::DBTools;
my $dbtool = Litmus::DBTools->new($dbh);
# ZLL: Authentication System fields
$dbtool->DropField("users", "is_trusted");
$dbtool->AddField("users", "bugzilla_uid", "int default '1'");
$dbtool->AddField("users", "password", "varchar(255)");
$dbtool->AddField("users", "realname", "varchar(255)");
$dbtool->AddField("users", "is_admin", "tinyint(1) default '0'");
$dbtool->AddField("users", "irc_nickname", "varchar(32)");
$dbtool->DropIndex("users", "email");
$dbtool->DropIndex("users", "irc_nickname");
$dbtool->AddUniqueKey("users","email","(email)");
$dbtool->AddUniqueKey("users","irc_nickname","(irc_nickname)");
$dbtool->AddKey("users","bugzilla_uid","(bugzilla_uid)");
$dbtool->AddKey("users","realname","(realname)");
$dbtool->AddKey("users","is_admin","(is_admin)");
# replace enums with more portable and flexible formats:
$dbtool->ChangeFieldType("products", "enabled", 'tinyint(1) default "1"');
$dbtool->DropField("test_result_logs", "log_path");
$dbtool->AddField("test_result_logs", "log_text", "longtext");
$dbtool->AddKey("test_result_logs", "log_text", "(log_text(255))");
$dbtool->AddField("test_results", "valid", "tinyint(1) default '1'");
$dbtool->AddField("test_results", "vetted", "tinyint(1) default '0'");
$dbtool->AddField("test_results", "validated_by_user_id", "int(11) default '0'");
$dbtool->AddField("test_results", "vetted_by_user_id", "int(11) default '0'");
$dbtool->AddField("test_results", "validated_timestamp", "datetime");
$dbtool->AddField("test_results", "vetted_timestamp", "datetime");
$dbtool->AddKey("test_results", "valid", "(valid)");
$dbtool->AddKey("test_results", "vetted", "(vetted)");
$dbtool->AddKey("test_results", "validated_by_user_id", "(validated_by_user_id)");
$dbtool->AddKey("test_results", "vetted_by_user_id", "(vetted_by_user_id)");
$dbtool->AddKey("test_results", "validated_timestamp", "(valid)");
$dbtool->AddKey("test_results", "vetted_timestamp", "(vetted)");
$dbtool->DropField("test_results", "validity_id");
$dbtool->DropField("test_results", "vetting_status_id");
$dbtool->DropTable("validity_lookup");
$dbtool->DropTable("vetting_status_lookup");
$dbtool->RenameTable("test_groups","testgroups");
$dbtool->AddField("testgroups", "enabled", "tinyint(1) NO NULL default '1'");
$dbtool->AddKey("testgroups","enabled","(enabled)");
$dbtool->DropField("testgroups", "obsolete");
$dbtool->DropField("testgroups", "expiration_days");
$dbtool->AddField("subgroups", "enabled", "tinyint(1) NOT NULL default '1'");
$dbtool->AddKey("subgroups","enabled","(enabled)");
$dbtool->AddField("subgroups", "product_id", "tinyint(4) NOT NULL");
$dbtool->AddKey("subgroups","product_id","(product_id)");
$dbtool->DropField("subgroups", "testgroup_id");
$dbtool->AddField("users", "enabled", "tinyint(1) NOT NULL default '1'");
$dbtool->AddKey("users","enabled","(enabled)");
$dbtool->DropField("users", "disabled");
$dbtool->DropTable("test_status_lookup");
# Remove reference to test_status_lookup
$dbtool->RenameTable("tests","testcases");
$dbtool->AddField("testcases", "enabled", "tinyint(1) NOT NULL default '1'");
$dbtool->AddKey("testcases","enabled","(enabled)");
$dbtool->DropIndex("testcases", "test_id");
$dbtool->RenameField("testcases", "test_id", "testcase_id");
$dbtool->AddKey("testcases","testcase_id","(testcase_id)");
$dbtool->AddKey("testcases","summary_2","(summary, steps, expected_results)");
$dbtool->ChangeFieldType("testcases", "community_enabled", 'tinyint(1) default "1"');
$dbtool->AddField("testcases", "product_id", "tinyint(4) NOT NULL");
$dbtool->AddKey("testcases","product_id","(product_id)");
$dbtool->DropField("testcases", "subgroup_id");
$dbtool->DropIndex("test_results", "test_id");
$dbtool->RenameField("test_results", "test_id", "testcase_id");
$dbtool->AddKey("test_results","testcase_id","(testcase_id)");
$dbtool->RenameField("test_results", "buildid", "build_id");
$dbtool->ChangeFieldType("test_results", "build_id", 'int(10) unsigned');
$dbtool->AddKey("test_results","build_id","(build_id)");
$dbtool->DropIndex("test_results", "result_id");
$dbtool->RenameField("test_results", "result_id", "result_status_id");
$dbtool->AddKey("test_results","result_status_id","(result_status_id)");
$dbtool->DropField("test_results", "platform_id");
$dbtool->AddField("branches", "enabled", "tinyint(1) NOT NULL default '1'");
$dbtool->AddKey("branches","enabled","(enabled)");
$dbtool->DropField("platforms", "product_id");
$dbtool->AddField("subgroup_testgroups", "sort_order", "smallint(6) NOT NULL default '1'");
$dbtool->AddKey("subgroup_testgroups","sort_order","(sort_order)");
$dbtool->AddField("testcase_subgroups", "sort_order", "smallint(6) NOT NULL default '1'");
$dbtool->AddKey("testcase_subgroups","sort_order","(sort_order)");
$dbtool->DropField("subgroups", "sort_order");
$dbtool->DropField("testcases", "sort_order");
$dbtool->AddField("users", "authtoken", "varchar(255)");
$dbtool->AddFullText("users", "key", "(email, realname, irc_nickname)");
# zll 2006-06-15: users.irc_nickname cannot have a unique index, since
# many users have a null nickname:
$dbtool->DropIndex("users", "irc_nickname");
$dbtool->AddKey("users", "irc_nickname", "(irc_nickname)");
# this should be a normal index, not a fulltext index
$dbtool->DropIndex("users", "key(email, realname, irc_nickname)");
$dbtool->AddKey("users", '(email, realname, irc_nickname)', '');
# make logs have a many-to-many relationship with test_results
$dbtool->DropIndex("test_result_logs", "test_result_id");
$dbtool->DropField("test_result_logs", "test_result_id");
$dbtool->AddField("test_results", "is_automated_result", "tinyint(1) not null default '0'");
print "Schema update complete.\n\n";
print <<EOS;
Due to the schema changes introduced, and depending on the when you last
updated your schema, you may now need to update/normalize your data as
well. This will include, but may not be limited to:
* populating the platform_products table;
* updating/normalizing platforms;
* updating/normalizing platform_ids in test_results;
* updating/normalizing opsyses;
* updating/normalizing opsys_ids in test_results;
* populating the subgroup_testgroups table;
* populating the testcase_subgroups table;
* filling in product_ids for each testcase/subgroup;
* populating the testgroup_branches table
EOS
# javascript cache
print "Rebuilding JS cache...";
require Litmus::Cache;
Litmus::Cache::rebuildCache();
print "done.\n";
exit;
#########################################################################
sub usage() {
print "./populatedb.pl [-h|--help] [-r|--resetdb]\n";
}

File diff suppressed because one or more lines are too long

View File

@@ -1,56 +0,0 @@
#!/usr/bin/perl -w
# -*- mode: cperl; c-basic-offset: 8; indent-tabs-mode: nil; -*-
# ***** 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) 2006
# the Initial Developer. All Rights Reserved.
#
# Contributor(s):
# Chris Cooper <ccooper@deadsquid.com>
# Zach Lipton <zach@zachlipton.com>
#
# ***** END LICENSE BLOCK *****
use strict;
use Litmus;
use Litmus::Auth;
use Litmus::Error;
use CGI;
use Date::Manip;
Litmus->init();
my $c = Litmus->cgi();
print $c->header;
my $vars = {
title => 'Preview',
};
if ($c->param("preview")) {
$vars->{'text_to_preview'} = $c->param("preview");
}
my $cookie = Litmus::Auth::getCookie();
$vars->{"defaultemail"} = $cookie;
$vars->{"show_admin"} = Litmus::Auth::istrusted($cookie);
Litmus->template()->process("admin/preview.tmpl", $vars) ||
internalError(Litmus->template()->error());

View File

@@ -1,231 +0,0 @@
#!/usr/bin/perl -w
# -*- mode: cperl; c-basic-offset: 8; indent-tabs-mode: nil; -*-
# ***** 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) 2006
# the Initial Developer. All Rights Reserved.
#
# Contributor(s):
# Chris Cooper <ccooper@deadsquid.com>
# Zach Lipton <zach@zachlipton.com>
#
# ***** END LICENSE BLOCK *****
use strict;
use Litmus;
use Litmus::Error;
use Litmus::DB::Product;
use Litmus::UserAgentDetect;
use Litmus::SysConfig;
use Litmus::Auth;
use Litmus::Utils;
use Litmus::DB::Resultbug;
use Litmus::XML;
use CGI;
use Date::Manip;
Litmus->init();
my $c = Litmus->cgi();
if ($c->param('data')) {
# we're getting XML result data from an automated testing provider,
# so pass that off to XML.pm for processing
my $x = Litmus::XML->new();
$x->processResults($c->param('data'));
# return whatever response was generated:
print $c->header('text/plain');
print $x->response();
exit; # that's all folks!
}
my $user;
my $sysconfig;
if ($c->param("isSysConfig")) {
$user = $user || Litmus::Auth::getCurrentUser();
if (!$user) {
my $return = $c->param("return") || 'index.cgi';
Litmus::Auth::requireLogin($return);
}
$sysconfig = Litmus::SysConfig->processForm($c);
# get the user id and set a sysconfig cookie
$c->storeCookie($sysconfig->setCookie());
}
print $c->header();
my @names = $c->param();
# find all the test numbers contained in this result submission
my @tests;
foreach my $curname (@names) {
if ($curname =~ /testresult_(\d*)/) {
push(@tests, $1);
}
}
# don't get to use the simple test interface if you really
# have more than one test (i.e. you cheated and changed the
# hidden input)
if (scalar @tests > 1 && $c->param("isSimpleTest")) {
invalidInputError("Cannot use simpletest interface with more than one test");
}
my $testcount;
my %resultcounts;
my $product;
foreach my $curtestid (@tests) {
unless ($c->param("testresult_".$curtestid)) {
# user didn't submit a result for this test so just skip
# it and move on...
next;
}
my $curtest = Litmus::DB::Testcase->retrieve($curtestid);
unless ($curtest) {
# oddly enough, the test doesn't exist
next;
}
$testcount++;
$product = $curtest->product();
my $ua = Litmus::UserAgentDetect->new();
# for simpletest, build a temporary sysconfig based on the
# UA string and product of this test:
if ($c->param("isSimpleTest")) {
$sysconfig = Litmus::SysConfig->new(
$curtest->product(),
$ua->platform($curtest->product()),
"NULL", # no way to autodetect the opsys
$ua->branch($curtest->product()),
$ua->build_id(),
);
}
# get system configuration. If there is no configuration and we're
# not doing the simpletest interface, then we make you enter it
# Get system configuration. If there is no configuration,
# then we make the user enter it.
if (!$sysconfig) {
$sysconfig = Litmus::SysConfig->getCookie($product);
}
# Users who still don't have a sysconfig for this product
# should go configure themselves first.
if (!$sysconfig) {
Litmus::SysConfig->displayForm($product,
"process_test.cgi",
$c);
exit;
}
my $result_status = Litmus::DB::ResultStatus->retrieve($c->param("testresult_".$curtestid));
$resultcounts{$result_status->name()}++;
my $note = $c->param("comment_".$curtestid);
my $bugs = $c->param("bugs_".$curtestid);
my $time = &Date::Manip::UnixDate("now","%q");
# normally, the user comes with a cookie, but for simpletest
# users, we just use the web-user@mozilla.org user:
if ($c->param("isSimpleTest")) {
$user = $user || Litmus::DB::User->search(email => 'web-tester@mozilla.org')->next();
} else {
$user = $user || Litmus::Auth::getCookie()->user_id();
}
my $tr = Litmus::DB::Testresult->create({
user => $user,
testcase => $curtest,
timestamp => $time,
last_updated => $time,
useragent => $ua,
result_status => $result_status,
opsys => $sysconfig->opsys(),
branch => $sysconfig->branch(),
build_id => $sysconfig->build_id(),
locale_abbrev => $sysconfig->locale(),
});
# if there's a note, create an entry in the comments table for it
if ($note and
$note ne '') {
Litmus::DB::Comment->create({
testresult => $tr,
submission_time => $time,
last_updated => $time,
user => $user,
comment => $note
});
}
if ($bugs and
$bugs ne '') {
$bugs =~ s/[^0-9,]//g;
my @new_bugs = split(/,/,$bugs);
foreach my $new_bug (@new_bugs) {
next if ($new_bug eq '0');
my $bug = Litmus::DB::Resultbug->create({
testresult => $tr,
last_updated => $time,
submission_time => $time,
user => $user,
bug_id => $new_bug,
});
}
}
}
if (! $testcount) {
invalidInputError("No results submitted.");
}
my $testgroup;
if ($c->param("testgroup")) {
$testgroup = Litmus::DB::Testgroup->retrieve($c->param("testgroup"));
if (! $product) {
$product = $testgroup->product();
}
}
my $vars;
$vars->{'title'} = 'Run Tests';
my $cookie = Litmus::Auth::getCookie();
$vars->{"defaultemail"} = $cookie;
$vars->{"show_admin"} = Litmus::Auth::istrusted($cookie);
$vars->{'testcount'} = $testcount;
$vars->{'product'} = $product || undef;
$vars->{'resultcounts'} = \%resultcounts || undef;
$vars->{'testgroup'} = $testgroup || undef;
$vars->{'return'} = $c->param("return") || undef;
Litmus->template()->process("process/process.html.tmpl", $vars) ||
internalError(Litmus->template()->error());

View File

@@ -1,2 +0,0 @@
User-agent: *
Disallow:

View File

@@ -1,195 +0,0 @@
#!/usr/bin/perl -w
# -*- mode: cperl; c-basic-offset: 8; indent-tabs-mode: nil; -*-
# ***** 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) 2006
# the Initial Developer. All Rights Reserved.
#
# Contributor(s):
# Chris Cooper <ccooper@deadsquid.com>
# Zach Lipton <zach@zachlipton.com>
#
# ***** END LICENSE BLOCK *****
use strict;
use Time::HiRes qw( gettimeofday tv_interval );
our $t0 = [gettimeofday];
use Litmus;
use Litmus::Error;
use Litmus::DB::Product;
use Litmus::UserAgentDetect;
use Litmus::SysConfig;
use Litmus::Auth;
use CGI;
use Time::Piece::MySQL;
Litmus->init();
our $title = "Run Tests";
our $c = Litmus->cgi();
if ($c->param("group")) { # display the test screen
page_test();
} elsif ($c->param("platform") || $c->param("continuetesting")) { # pick a group
page_pickGroupSubgroup();
} else { # need to setup their system config
page_sysSetup();
}
# a menu for the user to enter their platform information
sub page_sysSetup {
print $c->header();
# sometimes the user will have already selected their product
my $productid = $c->param("product");
my $product = undef;
if ($productid) {
$product = Litmus::DB::Product->retrieve($productid);
unless ($product) {
invalidInputError("Invalid product selection: $productid");
}
}
Litmus::SysConfig->displayForm($product, "run_tests.cgi");
exit;
}
# the user has selected their system information and now needs to pick
# an area to test:
sub page_pickGroupSubgroup {
my $sysconfig;
my $product = Litmus::DB::Product->retrieve($c->param("product"));
if (! $product) {
print $c->header();
invalidInputError("Invalid product ".$c->param("product"));
}
my $branch;
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()
};
$branch = $sysconfig->branch();
} else {
$branch = Litmus::DB::Branch->retrieve($c->param("branch"));
if (! $branch) {
print $c->header();
invalidInputError("Invalid branch ".$c->param("branch"));
}
$sysconfig = Litmus::SysConfig->processForm($c);
# get the user id and set a sysconfig cookie
$c->storeCookie($sysconfig->setCookie());
}
Litmus::Auth::requireLogin("run_tests.cgi");
print $c->header();
# Get all groups for the current branch.
my @groups = Litmus::DB::Testgroup->search_EnabledByBranch($branch->branch_id());
# all possible subgroups per group:
my %subgroups;
foreach my $curgroup (@groups) {
my @subgroups = Litmus::DB::Subgroup->search_EnabledByTestgroup($curgroup->testgroup_id());
$subgroups{$curgroup->testgroup_id()} = \@subgroups;
}
my $defaultgroup = "";
if ($c->param("defaulttestgroup")) {
$defaultgroup = Litmus::DB::Testgroup->
retrieve($c->param("defaulttestgroup"));
}
my $vars = {
title => $title,
user => Litmus::Auth::getCurrentUser(),
opsys => $sysconfig->opsys(),
groups => \@groups,
subgroups => \%subgroups,
sysconfig => $sysconfig,
defaultgroup => $defaultgroup,
};
my $cookie = Litmus::Auth::getCookie();
$vars->{"defaultemail"} = $cookie;
$vars->{"show_admin"} = Litmus::Auth::istrusted($cookie);
Litmus->template()->process("runtests/selectgroupsubgroup.html.tmpl",
$vars) ||
internalError(Litmus->template()->error());
if ($Litmus::Config::DEBUG) {
my $elapsed = tv_interval ( $t0 );
printf "<div id='pageload'>Page took %f seconds to load.</div>", $elapsed;
}
}
# display a page of testcases:
sub page_test {
# the form has a subgroup radio button set for each possible group, named
# subgroup_n where n is the group id number. We get the correct
# subgroup based on whatever group the user selected:
my $testgroup_id = $c->param("group");
my $subgroup_id = $c->param("subgroup_".$testgroup_id);
print $c->header();
# get the tests to display:
my @tests = Litmus::DB::Testcase->search_CommunityEnabledBySubgroup($subgroup_id);
# get all possible test results:
# my @results = Litmus::DB::Result->retrieve_all();
my $sysconfig = Litmus::SysConfig->getCookie($tests[0]->product());
my $cookie = Litmus::Auth::getCookie();
my $vars = {
title => $title,
sysconfig => Litmus::SysConfig->getCookie($tests[0]->product()),
group => Litmus::DB::Testgroup->retrieve($testgroup_id),
subgroup => Litmus::DB::Subgroup->retrieve($subgroup_id),
tests => \@tests,
# results => \@results,
defaultemail => $cookie,
show_admin => Litmus::Auth::istrusted($cookie),
istrusted => Litmus::Auth::istrusted($cookie),
};
$vars->{"defaultemail"} = $cookie;
$vars->{"show_admin"} = Litmus::Auth::istrusted($cookie);
$vars->{"istrusted"} = Litmus::Auth::istrusted($cookie);
Litmus->template()->process("runtests/testdisplay.html.tmpl", $vars) ||
internalError(Litmus->template()->error());
if ($Litmus::Config::DEBUG) {
my $elapsed = tv_interval ( $t0 );
printf "<div id='pageload'>Page took %f seconds to load.</div>", $elapsed;
}
}

View File

@@ -1,43 +0,0 @@
#!/usr/bin/perl -w
# -*- Mode: perl; indent-tabs-mode: nil -*-
#
# 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 the Bugzilla Bug Tracking System.
#
# The Initial Developer of the Original Code is Mike Norton.
# Portions created by the Initial Developer are Copyright (C) 2002
# the Initial Developer. All Rights Reserved.
#
# Contributor(s):
# Zach Lipton <zach@zachlipton.com>
#
# Make it harder for us to do dangerous things in Perl.
use strict;
use Test::Harness qw(&runtests $verbose);
$verbose = 0;
my $onlytest = "";
foreach (@ARGV) {
if (/^(?:-v|--verbose)$/) {
$verbose = 1;
}
else {
$onlytest = sprintf("%0.3d",$_);
}
}
runtests(glob("t/$onlytest*.t"));

View File

@@ -1,364 +0,0 @@
# 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) 2006
# the Initial Developer. All Rights Reserved.
#
# Contributor(s):
# Chris Cooper <ccooper@deadsquid.com>
# Zach Lipton <zach@zachlipton.com>
# Litmus database schema
# IMPORTANT: Any changes (other than new tables) made here must also be made
# by adding --TABLE-- upgrading code to populatedb.pl to handle upgrades from
# previous versions of the schema.
our $table;
$table{branches} =
'branch_id smallint(6) not null primary key auto_increment,
product_id tinyint(4) not null,
name varchar(64) not null,
detect_regexp varchar(255),
enabled tinyint(1) default 1,
index(product_id),
index(name),
index(detect_regexp),
index(enabled)
';
$table{build_type_lookup} =
'build_type_id tinyint(4) not null primary key auto_increment,
name varchar(64) not null,
index(name)';
$table{exit_status_lookup} =
'exit_status_id tinyint(4) 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(4) not null primary key auto_increment,
name varchar(64) not null,
index(name)';
$table{opsyses} =
'opsys_id smallint(6) not null primary key auto_increment,
platform_id smallint(6) not null,
name varchar(64) not null,
detect_regexp varchar(255),
index(platform_id),
index(name),
index(detect_regexp)';
$table{platform_products} =
'platform_id smallint(6) not null,
product_id tinyint(4) not null,
primary key (platform_id, product_id)';
$table{platforms} =
'platform_id smallint not null primary key auto_increment,
name varchar(64) not null,
detect_regexp varchar(255),
iconpath varchar(255),
index(name),
index(detect_regexp),
index(iconpath)';
$table{products} =
'product_id tinyint not null primary key auto_increment,
name varchar(64) not null,
iconpath varchar(255),
enabled tinyint(1) default \'1\',
unique key(name),
index(iconpath),
index(enabled)';
$table{related_testcases} =
'testcase_id int(11) not null,
related_testcase_id int(11) not null,
primary key (testcase_id, related_testcase_id)';
$table{sessions} =
'session_id int(11) not null primary key auto_increment,
user_id int(11) not null,
sessioncookie varchar(255) not null,
expires datetime not null,
index(user_id),
index(sessioncookie),
index(expires)';
$table{subgroup_testgroups} =
'subgroup_id smallint(6) not null,
testgroup_id smallint(6) not null,
sort_order smallint(6) not null default "1",
primary key(subgroup_id, testgroup_id),
index(sort_order)';
$table{subgroups} =
'subgroup_id smallint(6) not null primary key auto_increment,
name varchar(64) not null,
testrunner_group_id int(11),
enabled tinyint(1) default "1",
product_id tinyint(4) not null,
index(name),
index(testrunner_group_id),
index(enabled),
index(product_id)';
$table{test_format_lookup} =
'format_id tinyint(4) not null primary key auto_increment,
name varchar(255) not null,
index(name)';
$table{test_result_bugs} =
'test_result_id int(11) not null primary key auto_increment,
last_updated datetime not null,
submission_time datetime not null,
user_id int(11),
bug_id int(11) not null,
index(test_result_id),
index(last_updated),
index(submission_time),
index(user_id)';
$table{test_result_comments} =
'comment_id int(11) not null primary key auto_increment,
test_result_id int(11) not null,
last_updated datetime not null,
submission_time datetime not null,
user_id int(11),
comment text,
index(test_result_id),
index(last_updated),
index(submission_time),
index(user_id)';
$table{test_result_logs} =
'log_id int(11) not null primary key auto_increment,
last_updated datetime not null,
submission_time datetime not null,
log_text longtext,
log_type_id tinyint(4) not null default \'1\',
index(last_updated),
index(submission_time),
index(log_type_id),
index(log_text(255))';
$table{testresult_logs_join} =
'test_result_id int(11) not null,
log_id int(11) not null,
primary key(test_result_id, log_id)';
$table{test_result_status_lookup} =
'result_status_id smallint(6) 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(11) not null primary key auto_increment,
testcase_id int(11) not null,
last_updated datetime,
submission_time datetime,
user_id int(11),
opsys_id smallint(6),
branch_id smallint(6),
build_id int(10) unsigned,
user_agent varchar(255),
result_status_id smallint(6),
build_type_id tinyint(4) not null default \'1\',
machine_name varchar(64),
exit_status_id tinyint(4) not null default \'1\',
duration_ms int(11) unsigned,
talkback_id int(11) unsigned,
locale_abbrev varchar(16) not null default \'en-US\',
valid tinyint(1) not null default \'1\',
vetted tinyint(1) not null default \'0\',
validated_by_user_id int(11) default \'0\',
vetted_by_user_id int(11) default \'0\',
validated_timestamp datetime,
vetted_timestamp datetime,
is_automated_result tinyint(1) not null default \'0\',
index(testcase_id),
index(last_updated),
index(submission_time),
index(user_id),
index(opsys_id),
index(branch_id),
index(build_id),
index(user_agent),
index(result_status_id),
index(build_type_id),
index(machine_name),
index(exit_status_id),
index(duration_ms),
index(talkback_id),
index(locale_abbrev),
index(valid),
index(vetted),
index(validated_by_user_id),
index(vetted_by_user_id),
index(validated_timestamp),
index(vetted_timestamp)';
$table{test_run_branches} =
'test_run_id int(11) not null,
branch_id smallint(6) not null,
primary key(test_run_id, branch_id)';
$table{test_run_build_ids} =
'test_run_id int(11) not null,
build_id int(10) not null,
primary key(test_run_id, build_id)';
$table{test_run_opsyses} =
'test_run_id int(11) not null,
opsys_id smallint(6) not null,
primary key(test_run_id, opsys_id)';
$table{test_run_platforms} =
'test_run_id int(11) not null,
platform_id smallint(6) not null,
primary key(test_run_id, platform_id)';
$table{test_runs} =
'test_run_id int(11) not null primary key auto_increment,
testgroup_id smallint(6) not null,
name varchar(64) not null,
description varchar(255),
start_timestamp datetime not null,
finish_timestamp datetime not null,
enabled tinyint(1) not null default "1",
index(testgroup_id),
index(name),
index(description),
index(start_timestamp),
index(finish_timestamp),
index(enabled)';
$table{testcase_subgroups} =
'testcase_id int(11) not null,
subgroup_id smallint(6) not null,
sort_order smallint(6) not null default "1",
primary key(testcase_id, subgroup_id),
index(sort_order)';
$table{testcases} =
'testcase_id int(11) not null primary key auto_increment,
summary varchar(255) not null,
details text,
enabled tinyint(1) not null default \'1\',
community_enabled tinyint(1) default \'1\',
format_id tinyint(4) not null default \'1\',
regression_bug_id int(11),
steps longtext,
expected_results longtext,
author_id int(11) not null,
creation_date datetime not null,
last_updated datetime not null,
version smallint(6) not null default \'1\',
testrunner_case_id int(11),
testrunner_case_version int(11),
product_id tinyint(4) not null,
index(summary),
index(enabled),
index(community_enabled),
index(format_id),
index(regression_bug_id),
index(steps(255)),
index(expected_results(255)),
index(author_id),
index(creation_date),
index(last_updated),
index(testrunner_case_id),
index(testrunner_case_version),
index(product_id),
fulltext key(summary,steps,expected_results)';
$table{testgroup_branches} =
'testgroup_id smallint(6) not null,
branch_id smallint(6) not null,
primary key(testgroup_id, branch_id)';
$table{testgroups} =
'testgroup_id smallint(6) not null primary key auto_increment,
product_id tinyint(4) not null,
name varchar(64) not null,
enabled tinyint(1) default "1",
testrunner_plan_id int(11),
index(product_id),
index(name),
index(enabled),
index(testrunner_plan_id)';
$table{users} =
'user_id int(11) not null primary key auto_increment,
bugzilla_uid int,
email varchar(255) not null,
password varchar(255),
realname varchar(255),
irc_nickname varchar(32),
enabled tinyint(1),
is_admin tinyint(1),
authtoken varchar(255),
index(bugzilla_uid),
unique index(email),
index(irc_nickname),
index(password),
index(realname),
index(enabled),
index(is_admin),
index(email, realname, irc_nickname)';

View File

@@ -1,196 +0,0 @@
#!/usr/bin/perl -w
# -*- mode: cperl; c-basic-offset: 8; indent-tabs-mode: nil; -*-
# ***** 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) 2006
# the Initial Developer. All Rights Reserved.
#
# Contributor(s):
# Chris Cooper <ccooper@deadsquid.com>
# Zach Lipton <zach@zachlipton.com>
#
# ***** END LICENSE BLOCK *****
use strict;
use Litmus;
use Litmus::Auth;
use Litmus::Error;
use Litmus::DB::Testresult;
use Litmus::FormWidget;
use CGI;
use Time::Piece::MySQL;
Litmus->init();
my $c = Litmus->cgi();
print $c->header();
my $criteria = "Custom<br/>";
my $results;
my @where;
my @order_by;
my $limit;
my $where_criteria = "";
my $order_by_criteria = "";
my $limit_criteria = "";
if ($c->param) {
foreach my $param ($c->param) {
next if ($c->param($param) eq '');
if ($param =~ /^order_by_(.*)$/) {
my $order_by_proto = quotemeta($1);
next if ($c->param($param) ne 'ASC' and
$c->param($param) ne 'DESC');
my $order_by_direction = $c->param($param);
push @order_by, {field => $order_by_proto,
direction => $order_by_direction};
$order_by_criteria .= "Order by $order_by_proto $order_by_direction<br/>";
} elsif ($param eq 'branch') {
my $value = quotemeta($c->param($param));
push @where, {field => $param,
value => $value};
$where_criteria .= "Branch is \'".$c->param($param)."\'<br/>";
} elsif ($param eq 'locale') {
my $value = quotemeta($c->param($param));
push @where, {field => 'locale',
value => $value};
$where_criteria .= "Locale is \'".$c->param($param)."\'<br/>";
} elsif ($param eq 'product') {
my $value = quotemeta($c->param($param));
push @where, {field => $param,
value => $value};
$where_criteria .= "Product is \'".$c->param($param)."\'<br/>";
} elsif ($param eq 'platform') {
my $value = quotemeta($c->param($param));
push @where, {field => $param,
value => $value};
$where_criteria .= "Platform is \'".$c->param($param)."\'<br/>";
} elsif ($param eq 'test_group') {
my $value = quotemeta($c->param($param));
push @where, {field => $param,
value => $value};
$where_criteria .= "Test group is \'".$c->param($param)."\'<br/>";
} elsif ($param eq 'testcase_id') {
my $value = quotemeta($c->param($param));
push @where, {field => $param,
value => $value};
$where_criteria .= "Testcase ID# is \'".$c->param($param)."\'<br/>";
} elsif ($param eq 'summary') {
my $value = quotemeta($c->param($param));
push @where, {field => $param,
value => $value};
$where_criteria .= "Summary like \'".$c->param($param)."\'<br/>";
} elsif ($param eq 'email') {
my $value = quotemeta($c->param($param));
push @where, {field => $param,
value => $value};
$where_criteria .= "Submitted By like \'".$c->param($param)."\'<br/>";
} elsif ($param eq 'result_status') {
my $value = quotemeta($c->param($param));
push @where, {field => $param,
value => $value};
$where_criteria .= "Status is \'".$c->param($param)."\'<br/>";
} elsif ($param eq 'timespan') {
my $value = $c->param($param);
if ($value ne 'all') {
$value =~ s/[^\-0-9]//g;
push @where, {field => $param,
value => $value};
$value =~ s/\-//g;
if ($value == 1) {
$where_criteria .= "Submitted in the last day<br/>";
} else {
$where_criteria .= "Submitted in the last $value days<br/>";
}
} else {
$where_criteria .= "All Results<br/>";
}
} elsif ($param eq "limit") {
$limit = quotemeta($c->param($param));
next if ($limit == $Litmus::DB::Testresult::_num_results_default);
$limit_criteria .= "Limit to $limit results";
} else {
# Skip unknown field
}
}
if ($where_criteria eq '' and
$order_by_criteria eq '' and
$limit_criteria eq '') {
($criteria,$results) =
Litmus::DB::Testresult->getDefaultTestResults;
} else {
$criteria .= $where_criteria . $order_by_criteria . $limit_criteria;
$criteria =~ s/_/ /g;
$results = Litmus::DB::Testresult->getTestResults(\@where,
\@order_by,
$limit);
}
} else {
($criteria,$results) =
Litmus::DB::Testresult->getDefaultTestResults;
}
# Populate each of our form widgets for select/input.
# Set a default value as appropriate.
my $products = Litmus::FormWidget->getProducts;
my $platforms = Litmus::FormWidget->getUniquePlatforms;
my $test_groups = Litmus::FormWidget->getTestgroups;
my $result_statuses = Litmus::FormWidget->getResultStatuses;
my $branches = Litmus::FormWidget->getBranches;
my $locales = Litmus::FormWidget->getLocales;
my $title = 'Search Test Results';
my $vars = {
title => $title,
criteria => $criteria,
products => $products,
platforms => $platforms,
test_groups => $test_groups,
result_statuses => $result_statuses,
branches => $branches,
locales => $locales,
limit => $limit,
};
# Only include results if we have them.
if ($results and scalar @$results > 0) {
$vars->{results} = $results;
}
my $cookie = Litmus::Auth::getCookie();
$vars->{"defaultemail"} = $cookie;
$vars->{"show_admin"} = Litmus::Auth::istrusted($cookie);
Litmus->template()->process("reporting/search_results.tmpl", $vars) ||
internalError(Litmus->template()->error());
exit 0;

View File

@@ -1,192 +0,0 @@
#!/usr/bin/perl -w
# -*- Mode: cperl; indent-tabs-mode: nil -*-
#
# 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 Netscape Communications
# Corporation. Portions created by Netscape are
# Copyright (C) 1998 Netscape Communications Corporation. All
# Rights Reserved.
#
# Contributor(s): Zach Lipton <zach@zachlipton.com>
use strict;
use Litmus;
use Litmus::Error;
use Litmus::DB::Product;
use Litmus::UserAgentDetect;
use Litmus::SysConfig;
use Litmus::Auth;
use Litmus::Utils;
use Litmus::DB::Resultbug;
use CGI;
use Date::Manip;
use Time::Piece::MySQL;
Litmus->init();
my $c = Litmus->cgi();
print $c->header();
my $vars;
my $cookie = Litmus::Auth::getCookie();
$vars->{"defaultemail"} = $cookie;
$vars->{"show_admin"} = Litmus::Auth::istrusted($cookie);
$vars->{'default_match_limit'} = Litmus::DB::Testcase->getDefaultMatchLimit();
$vars->{'default_num_days'} = Litmus::DB::Testcase->getDefaultNumDays();
$vars->{'default_relevance_threshold'} = Litmus::DB::Testcase->getDefaultRelevanceThreshold();
if (! $c->param) {
Litmus->template()->process("show/search_for_testcases.tmpl", $vars) ||
internalError(Litmus->template()->error());
exit;
}
if ($c->param("id")) {
my $testcase_id = $c->param("id");
# Process changes to testcases:
# Only users with canedit can edit testcases.
my @changed;
my $update_status = 0;
if ($c->param("editingTestcases") &&
Litmus::Auth::canEdit(Litmus::Auth::getCookie())) {
# the editingTestcases param contains a comma-separated list of
# testcase IDs that the user has made changes to (well, has clicked
# the edit button for).
@changed = split(',' => $c->param("editingTestcases"));
foreach my $editid (@changed) {
my $edittest = Litmus::DB::Testcase->retrieve($editid);
if (! $edittest) {invalidInputError("Testcase $editid does not exist")}
$edittest->summary($c->param("summary_edit_$editid"));
my $product = Litmus::DB::Product->retrieve($c->param("product_$editid"));
requireField("product", $product);
$edittest->product($product);
$edittest->steps($c->param("steps_edit_$editid"));
$edittest->expected_results($c->param("results_edit_$editid"));
if ($c->param("enabled_$editid")) {
$edittest->enabled(1);
if ($c->param("communityenabled_$editid")) {
$edittest->communityenabled(1);
} else {
$edittest->communityenabled(0);
}
} else {
$edittest->enabled(0);
$edittest->communityenabled(0);
}
my $r_bug_id = $c->param("regression_bug_id_$editid");
if ($r_bug_id eq '' or $r_bug_id eq '0') {
undef $r_bug_id;
}
$edittest->regression_bug_id($r_bug_id);
# $edittest->sort_order($c->param("sort_order_$editid"));
$edittest->author_id(Litmus::Auth::getCurrentUser());
$edittest->last_updated(&Date::Manip::UnixDate("now","%q"));
$edittest->version($edittest->version()+1);
my $update_status = $edittest->update();
my $status = "";
my $message = "";
if ($update_status) {
$status = "success";
$message = "Testcase ID# $editid updated successfully.";
} else {
$status = "failure";
$message = "Unable to update testcase ID# $editid.";
}
$vars->{'onload'} = "toggleMessage('$status','$message');";
}
} elsif ($c->param("editingTestcases") &&
! Litmus::Auth::canEdit(Litmus::Auth::getCookie())) {
invalidInputError("You do not have permissions to edit testcases. ");
}
my $testcase = Litmus::DB::Testcase->retrieve($testcase_id);
if (! $testcase) {
invalidInputError("\"$testcase_id\" is not a valid testcase ID.");
}
my @testgroups = Litmus::DB::Testgroup->search_EnabledByTestcase($testcase_id);
my @subgroups = Litmus::DB::Subgroup->search_EnabledByTestcase($testcase_id);
my @result_statuses = Litmus::DB::ResultStatus->retrieve_all();
my $showallresults = $c->param("showallresults") || "";
my @where;
push @where, { field => 'testcase_id', value => $testcase_id };
my @order_by;
push @order_by, { field => 'created', direction => 'DESC' };
my $test_results = Litmus::DB::Testresult->getTestResults(\@where,\@order_by);
$vars->{'testcase'} = $testcase;
$vars->{'sysconfig'} = Litmus::SysConfig->getCookie($testcase->product());
$vars->{'testgroups'} = \@testgroups;
$vars->{'subgroups'} = \@subgroups;
$vars->{'result_statuses'} = \@result_statuses;
$vars->{'showallresults'} = $showallresults;
$vars->{'test_results'} = $test_results;
Litmus->template()->process("show/show.html.tmpl", $vars) ||
internalError(Litmus->template()->error());
exit;
}
if ($c->param("text_snippet")) {
my $text_snippet = $c->param("text_snippet");
my $match_limit = $c->param("match_limit");
my $relevance_threshold = $c->param("relevance_threshold");
my @testcases = Litmus::DB::Testcase->getFullTextMatches($text_snippet,
$match_limit,
$relevance_threshold);
$vars->{'testcases'} = \@testcases;
$vars->{'search_string_for_display'} = "Full-Text Search: \"$text_snippet\"";
$vars->{'fulltext'} = 1;
} elsif ($c->param("recently")) {
my $recently = $c->param("recently");
my $match_limit = $c->param("match_limit");
my $num_days = $c->param("num_days") || Litmus::DB::Testcase->getDefaultNumDays();
my @testcases;
my $search_string_for_display;
if ($recently eq 'added') {
@testcases = Litmus::DB::Testcase->getNewTestcases(
$num_days,
$match_limit
);
$search_string_for_display = "Testcases added in the last $num_days days";
} elsif ($recently eq 'changed') {
@testcases = Litmus::DB::Testcase->getRecentlyUpdated(
$num_days,
$match_limit
);
$search_string_for_display = "Testcases changed in the last $num_days days";
}
$vars->{'testcases'} = \@testcases;
$vars->{'search_string_for_display'} = $search_string_for_display;
}
Litmus->template()->process("show/search_for_testcases.tmpl", $vars) ||
internalError(Litmus->template()->error());

Some files were not shown because too many files have changed in this diff Show More