Two significant user authentication changes:
Bug 329250 - User permission groups. Creates several layers of admin groups, including super-administrators, test run/test day administrators, and product administrators, and restricts access to administrative functions according to user group levels. Also adds auth tools to search for users by group and to grant/revoke group permissions. Added hooks for testcases to belong to security groups (much like Bugzilla's group system) for future use. Bug 314928 - Forgot Password feature. Allows users who have forgotten their passwords to change them without intervention from the QA team. Password change requests are authenticated by an email to the user and a link they must follow to confirm their identity. Also adds Litmus::Mailer, with general support for sending email from within Litmus for future email features. Also reinstated Memoization in a mod_perl-aware way for a few common functions. git-svn-id: svn://10.0.0.236/trunk@227557 18797224-902f-48f8-a5cc-f745e15eee43
This commit is contained in:
parent
e2f8d0ce1b
commit
3c1dc52fd9
@ -2,7 +2,7 @@
|
||||
|
||||
== Required Perl Modules ==
|
||||
|
||||
Apache::DBI
|
||||
Apache::DBI - if mod_perl is being used
|
||||
CGI
|
||||
Class::DBI
|
||||
Class::DBI::mysql
|
||||
@ -24,13 +24,31 @@ Time::Piece::MySQL
|
||||
Time::Seconds
|
||||
XML::XPath
|
||||
|
||||
Also, note that 'sendmail' (or a mailer with a compatible command-line
|
||||
interface) is required.
|
||||
|
||||
== Setting up the database ==
|
||||
|
||||
Run populatedb.pl. This will create a template configuration file, 'localconfig,' that contains variables to hold your database configuration information. Edit the newly created 'localconfig' file with your database configuration. Once 'localconfig' is populated with your database information, run the populatedb.pl again to populate the initial products, locales, etc... There is no UI at present for doing this.
|
||||
Run populatedb.pl. This will create a template configuration file,
|
||||
'localconfig,' that contains variables to hold your database configuration
|
||||
information. Edit the newly created 'localconfig' file with your database
|
||||
configuration. Once 'localconfig' is populated with your database information,
|
||||
run the populatedb.pl again to populate the initial products, locales, etc...
|
||||
There is no UI at present for doing this.
|
||||
|
||||
Then just pop the whole thing into a directory where your web server can
|
||||
get at it. Have fun!
|
||||
|
||||
To get yourself an administrator account, you'll need to load up Litmus in your
|
||||
web browser and follow the link to create a new account. You'll have been
|
||||
lucky enough to score user id number 1. Grant yourself admin rights by loading
|
||||
up mysql, connecting to your Litmus database, and running the following command:
|
||||
|
||||
insert into user_group_map values ('1', '1');
|
||||
|
||||
From there, you can go into "Edit Users" in the web interface and grant
|
||||
rights to any new users.
|
||||
|
||||
Note: After upgrading Litmus, it's a good idea to run populatedb.pl
|
||||
again to pick up any schema changes that may have occured.
|
||||
|
||||
|
||||
@ -63,11 +63,17 @@ sub init() {
|
||||
}
|
||||
|
||||
# Global Template object
|
||||
our $template;
|
||||
sub template() {
|
||||
my $class = shift;
|
||||
request_cache()->{template} ||= Litmus::Template->create();
|
||||
return request_cache()->{template};
|
||||
my $class = shift;
|
||||
$template ||= Litmus::Template->create();
|
||||
return $template;
|
||||
}
|
||||
#sub template() {
|
||||
# my $class = shift;
|
||||
# request_cache()->{template} ||= Litmus::Template->create();
|
||||
# return request_cache()->{template};
|
||||
#}
|
||||
|
||||
# Global CGI object
|
||||
sub cgi() {
|
||||
|
||||
@ -43,6 +43,9 @@ use Litmus::Error;
|
||||
use Time::Piece;
|
||||
use Time::Seconds;
|
||||
use Litmus::DB::User;
|
||||
use Litmus::DB::PasswordResets;
|
||||
use Litmus::Memoize;
|
||||
use Litmus::Mailer;
|
||||
|
||||
use CGI;
|
||||
|
||||
@ -114,7 +117,7 @@ sub requireLogin {
|
||||
}
|
||||
|
||||
# Used by a CGI in much the same way as requireLogin() when the user must
|
||||
# be an admin to proceed.
|
||||
# be a superuser to proceed.
|
||||
sub requireAdmin {
|
||||
my $return_to = shift;
|
||||
my $cgi = Litmus->cgi();
|
||||
@ -127,6 +130,48 @@ sub requireAdmin {
|
||||
return $user;
|
||||
}
|
||||
|
||||
# similar to the above, but the user may be a run/day admin
|
||||
sub requireRunDayAdmin {
|
||||
my $return_to = shift;
|
||||
my $cgi = Litmus->cgi();
|
||||
|
||||
my $user = requireLogin($return_to, 1);
|
||||
if (!$user || !$user->isRunDayAdmin()) {
|
||||
print $cgi->header();
|
||||
basicError("You must be a Test Run/Test Day administrator to perform this function.");
|
||||
}
|
||||
return $user;
|
||||
}
|
||||
|
||||
# similar to requireAdmin, but the user may be a product admin as well
|
||||
sub requireProductAdmin {
|
||||
my $return_to = shift;
|
||||
my $product = shift; # optional
|
||||
|
||||
my $cgi = Litmus->cgi();
|
||||
|
||||
my $user = requireLogin($return_to, 1);
|
||||
if (!$user || !$user->isInAdminGroup()) {
|
||||
print $cgi->header();
|
||||
basicError("You must be a Litmus administrator to perform this function.");
|
||||
}
|
||||
# superusers can do anything:
|
||||
if ($user->isSuperUser()) {
|
||||
return $user;
|
||||
}
|
||||
# otherwise, they must be an admin of $product if $product is specified:
|
||||
if ($product) {
|
||||
if ($user->isProductAdmin($product)) {
|
||||
return $user;
|
||||
} else {
|
||||
print $cgi->header();
|
||||
basicError("You must be an administrator of product ".
|
||||
$product->name()." 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() {
|
||||
@ -165,6 +210,109 @@ sub getCurrentUser() {
|
||||
}
|
||||
}
|
||||
|
||||
########################################
|
||||
# Reset Password #
|
||||
########################################
|
||||
|
||||
# Change the user's forgotten password. This is done in two phases, with an
|
||||
# email confirmation to validate the user's identity before changing the
|
||||
# password.
|
||||
sub resetPassword {
|
||||
my $user = shift;
|
||||
|
||||
# invalidate any pending password reset sessions:
|
||||
my @resets = Litmus::DB::PasswordResets->search(user => $user);
|
||||
foreach my $cur (@resets) {
|
||||
$cur->session()->makeExpire();
|
||||
$cur->delete();
|
||||
}
|
||||
|
||||
my $session = makeSession($user, 1);
|
||||
Litmus::DB::PasswordResets->create({user => $user, session => $session});
|
||||
|
||||
my $vars_mail = {
|
||||
user => $user,
|
||||
token => $session->sessioncookie(),
|
||||
};
|
||||
my $output;
|
||||
Litmus->template()->process("auth/passwordreset/message.mail.tmpl",
|
||||
$vars_mail, \$output, {POST_CHOMP => 0, PRE_CHOMP => 0}) ||
|
||||
internalError(Litmus->template()->error());
|
||||
|
||||
# fix weird template nonsense
|
||||
$output =~ s/^.*(To: )/To: /s;
|
||||
|
||||
Litmus::Mailer::sendMessage($output);
|
||||
|
||||
my $vars_html = {
|
||||
title => "Reset Password",
|
||||
return_to => "login.cgi",
|
||||
};
|
||||
print Litmus->cgi()->header();
|
||||
Litmus->template()->process("auth/passwordreset/checkEmail.html.tmpl", $vars_html) ||
|
||||
internalError(Litmus->template()->error());
|
||||
|
||||
exit;
|
||||
}
|
||||
|
||||
# after the user follows the link in the email, they end up here to actually
|
||||
# reset their password:
|
||||
sub resetPasswordForm {
|
||||
my $token = shift;
|
||||
|
||||
my $reset = validateToken($token);
|
||||
|
||||
my $vars = {
|
||||
title => "Reset Password",
|
||||
return_to => "login.cgi",
|
||||
user => $reset->user(),
|
||||
token => $token,
|
||||
};
|
||||
print Litmus->cgi()->header();
|
||||
Litmus->template()->process("auth/passwordreset/resetForm.html.tmpl", $vars) ||
|
||||
internalError(Litmus->template()->error());
|
||||
}
|
||||
|
||||
# and after they complete the reset password from, they come here to
|
||||
# actually change the password:
|
||||
sub doResetPassword {
|
||||
my $uid = shift;
|
||||
my $token = shift;
|
||||
my $password = shift;
|
||||
|
||||
my $reset = validateToken($token);
|
||||
changePassword($reset->user(), $password);
|
||||
|
||||
my $session = makeSession($reset->user());
|
||||
Litmus->cgi()->storeCookie(makeCookie($session));
|
||||
|
||||
$reset->session()->makeExpire();
|
||||
$reset->delete();
|
||||
}
|
||||
|
||||
sub validateToken {
|
||||
my $token = shift;
|
||||
my @sessions = Litmus::DB::Session->search(sessioncookie => $token);
|
||||
my $session = $sessions[0];
|
||||
if (!$session) {
|
||||
invalidInputError("That authentication token is invalid. It may have
|
||||
been copied incorrectly from the email, or have already been used.
|
||||
Please check that the entire URL was copied correctly.");
|
||||
}
|
||||
|
||||
if (! $session->isValid()) {
|
||||
invalidInputError("That authentication token has expired. You'll need to
|
||||
request a new password reset and try again.");
|
||||
}
|
||||
|
||||
my @resets = Litmus::DB::PasswordResets->search(session => $session);
|
||||
my $reset = $resets[0];
|
||||
if (!$reset) {
|
||||
invalidInputError("That authentication token is invalid. It does not
|
||||
belong to a user that has requested a password reset.");
|
||||
}
|
||||
return $reset;
|
||||
}
|
||||
|
||||
#
|
||||
# ONLY NON-PUBLIC API BEYOND THIS POINT
|
||||
@ -187,6 +335,22 @@ sub processLoginForm {
|
||||
return; # we're done here
|
||||
}
|
||||
|
||||
# the user just reset their password, so no need to do anything
|
||||
if ($c->param('login_type') eq 'doResetPassword') {
|
||||
return;
|
||||
}
|
||||
|
||||
# check to see if they have forgotten their password:
|
||||
if ($type eq "forgot_password") {
|
||||
my $username = $c->param("email");
|
||||
my @users = Litmus::DB::User->search(email => $username);
|
||||
if (! $users[0]) {
|
||||
loginError($c, "Invalid email address entered. Please try again");
|
||||
}
|
||||
resetPassword($users[0]);
|
||||
return;
|
||||
}
|
||||
|
||||
if ($type eq "litmus") {
|
||||
my $username = $c->param("email");
|
||||
my $password = $c->param("password");
|
||||
@ -390,6 +554,7 @@ sub expireSessions {
|
||||
# Given a userobj, process the login and return a session object
|
||||
sub makeSession {
|
||||
my $userobj = shift;
|
||||
my $dontsetsession = shift;
|
||||
my $c = Litmus->cgi();
|
||||
|
||||
my $expires = localtime() + ONE_DAY * $cookie_expire_days;
|
||||
@ -401,7 +566,9 @@ sub makeSession {
|
||||
sessioncookie => $sessioncookie,
|
||||
expires => $expires});
|
||||
|
||||
Litmus->request_cache->{'curSession'} = $session;
|
||||
unless ($dontsetsession) {
|
||||
Litmus->request_cache->{'curSession'} = $session;
|
||||
}
|
||||
return $session;
|
||||
}
|
||||
|
||||
@ -530,16 +697,12 @@ sub getCookie() {
|
||||
return getCurrentUser();
|
||||
}
|
||||
|
||||
# trusted means "is a super user"
|
||||
sub istrusted($) {
|
||||
my $userobj = shift;
|
||||
|
||||
return 0 if (!$userobj);
|
||||
|
||||
if ($userobj->istrusted()) {
|
||||
return 1;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
return $userobj->isSuperUser();
|
||||
}
|
||||
|
||||
sub canEdit($) {
|
||||
|
||||
53
mozilla/webtools/litmus/Litmus/DB/GroupProductMap.pm
Executable file
53
mozilla/webtools/litmus/Litmus/DB/GroupProductMap.pm
Executable file
@ -0,0 +1,53 @@
|
||||
# -*- mode: cperl; c-basic-offset: 8; indent-tabs-mode: nil; -*-
|
||||
|
||||
=head1 COPYRIGHT
|
||||
|
||||
# ***** BEGIN LICENSE BLOCK *****
|
||||
# Version: MPL 1.1
|
||||
#
|
||||
# The contents of this file are subject to the Mozilla Public License
|
||||
# Version 1.1 (the "License"); you may not use this file except in
|
||||
# compliance with the License. You may obtain a copy of the License
|
||||
# at http://www.mozilla.org/MPL/
|
||||
#
|
||||
# Software distributed under the License is distributed on an "AS IS"
|
||||
# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
|
||||
# the License for the specific language governing rights and
|
||||
# limitations under the License.
|
||||
#
|
||||
# The Original Code is Litmus.
|
||||
#
|
||||
# The Initial Developer of the Original Code is
|
||||
# the Mozilla Corporation.
|
||||
# Portions created by the Initial Developer are Copyright (C) 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::GroupProductMap;
|
||||
|
||||
use strict;
|
||||
use Litmus::Config;
|
||||
use base 'Litmus::DBI';
|
||||
|
||||
Litmus::DB::GroupProductMap->table('group_product_map');
|
||||
|
||||
Litmus::DB::GroupProductMap->columns(All => qw/group_id product_id/);
|
||||
Litmus::DB::GroupProductMap->columns(TEMP => qw//);
|
||||
|
||||
Litmus::DB::GroupProductMap->column_alias("group_id", "group");
|
||||
Litmus::DB::GroupProductMap->column_alias("product_id", "product");
|
||||
|
||||
Litmus::DB::GroupProductMap->has_a(group => "Litmus::DB::SecurityGroup");
|
||||
Litmus::DB::GroupProductMap->has_a(product => "Litmus::DB::Product");
|
||||
|
||||
1;
|
||||
|
||||
|
||||
|
||||
53
mozilla/webtools/litmus/Litmus/DB/PasswordResets.pm
Executable file
53
mozilla/webtools/litmus/Litmus/DB/PasswordResets.pm
Executable file
@ -0,0 +1,53 @@
|
||||
# -*- mode: cperl; c-basic-offset: 8; indent-tabs-mode: nil; -*-
|
||||
|
||||
=head1 COPYRIGHT
|
||||
|
||||
# ***** BEGIN LICENSE BLOCK *****
|
||||
# Version: MPL 1.1
|
||||
#
|
||||
# The contents of this file are subject to the Mozilla Public License
|
||||
# Version 1.1 (the "License"); you may not use this file except in
|
||||
# compliance with the License. You may obtain a copy of the License
|
||||
# at http://www.mozilla.org/MPL/
|
||||
#
|
||||
# Software distributed under the License is distributed on an "AS IS"
|
||||
# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
|
||||
# the License for the specific language governing rights and
|
||||
# limitations under the License.
|
||||
#
|
||||
# The Original Code is Litmus.
|
||||
#
|
||||
# The Initial Developer of the Original Code is
|
||||
# the Mozilla Corporation.
|
||||
# Portions created by the Initial Developer are Copyright (C) 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::PasswordResets;
|
||||
|
||||
use strict;
|
||||
use Litmus::Config;
|
||||
use base 'Litmus::DBI';
|
||||
|
||||
Litmus::DB::PasswordResets->table('password_resets');
|
||||
|
||||
Litmus::DB::PasswordResets->columns(All => qw/user_id session_id/);
|
||||
Litmus::DB::PasswordResets->columns(TEMP => qw//);
|
||||
|
||||
Litmus::DB::PasswordResets->column_alias("user_id", "user");
|
||||
Litmus::DB::PasswordResets->column_alias("session_id", "session");
|
||||
|
||||
Litmus::DB::PasswordResets->has_a(user => "Litmus::DB::User");
|
||||
Litmus::DB::PasswordResets->has_a(session => "Litmus::DB::Session");
|
||||
|
||||
1;
|
||||
|
||||
|
||||
|
||||
@ -51,6 +51,7 @@ Litmus::DB::Product->has_many(testgroups => "Litmus::DB::Testgroup",
|
||||
{ order_by => 'name' });
|
||||
Litmus::DB::Product->has_many(branches => "Litmus::DB::Branch",
|
||||
{ order_by => 'name' });
|
||||
Litmus::DB::Product->has_many(groups => ["Litmus::DB::GroupProductMap" => 'group_id']);
|
||||
|
||||
__PACKAGE__->set_sql(ByPlatform => qq{
|
||||
SELECT pr.*
|
||||
|
||||
120
mozilla/webtools/litmus/Litmus/DB/SecurityGroup.pm
Executable file
120
mozilla/webtools/litmus/Litmus/DB/SecurityGroup.pm
Executable file
@ -0,0 +1,120 @@
|
||||
# -*- 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) 2007
|
||||
# the Initial Developer. All Rights Reserved.
|
||||
#
|
||||
# Contributor(s):
|
||||
# Zach Lipton <zach@zachlipton.com>
|
||||
#
|
||||
# ***** END LICENSE BLOCK *****
|
||||
|
||||
=cut
|
||||
|
||||
package Litmus::DB::SecurityGroup;
|
||||
|
||||
use strict;
|
||||
use Litmus::Config;
|
||||
use Litmus::Memoize;
|
||||
use base 'Litmus::DBI';
|
||||
|
||||
Litmus::DB::SecurityGroup->table('security_groups');
|
||||
|
||||
Litmus::DB::SecurityGroup->columns(All => qw/group_id name description grouptype isactive/);
|
||||
Litmus::DB::SecurityGroup->columns(TEMP => qw//);
|
||||
|
||||
Litmus::DB::SecurityGroup->has_many(users => ["Litmus::DB::UserGroupMap" => 'user_id']);
|
||||
Litmus::DB::SecurityGroup->has_many(products => ["Litmus::DB::GroupProductMap" => 'product_id']);
|
||||
|
||||
# group types:
|
||||
# 1 - superuser
|
||||
# 2 - test run and test day administrator
|
||||
# 3 - product admin
|
||||
# 4 - testcase security group
|
||||
|
||||
# create an initial set of groups for an upgraded installation
|
||||
sub upgradeGroups {
|
||||
# check to see if groups need to be created:
|
||||
my @rows = Litmus::DB::SecurityGroup->search({grouptype => 1});
|
||||
if ($rows[0]) {
|
||||
return;
|
||||
}
|
||||
print "creating intial groups...";
|
||||
# first, create a superuser group:
|
||||
my $admingroup = Litmus::DB::SecurityGroup->create({
|
||||
name => "Litmus Super Administrators",
|
||||
description => "Global administrators of this Litmus installation",
|
||||
grouptype => 1,
|
||||
isactive => 1,
|
||||
});
|
||||
# add current gloabl admins to the superuser group
|
||||
my @admins = Litmus::DB::User->search({is_admin_old => 1});
|
||||
foreach my $cur (@admins) {
|
||||
Litmus::DB::UserGroupMap->create({group => $admingroup, user=>$cur});
|
||||
}
|
||||
|
||||
# create a test run/testday admin group
|
||||
my $rundaygroup = Litmus::DB::SecurityGroup->create({
|
||||
name => "Litmus Test Run/Test Day Administrators",
|
||||
description => "Administrators of Litmus Test Runs and Test Days",
|
||||
grouptype => 2,
|
||||
isactive => 1,
|
||||
});
|
||||
|
||||
# create product admin groups for all products
|
||||
my @products = Litmus::DB::Product->retrieve_all();
|
||||
foreach my $cur2 (@products) {
|
||||
my $productgroup = Litmus::DB::SecurityGroup->create({
|
||||
name => $cur2->name()." Administrators",
|
||||
description => "Administrators of the ".$cur2->name()." product",
|
||||
grouptype => 3,
|
||||
isactive => 1,
|
||||
});
|
||||
Litmus::DB::GroupProductMap->create({group=>$productgroup, product=>$cur2});
|
||||
}
|
||||
}
|
||||
|
||||
# hack!
|
||||
sub selected {
|
||||
my $self = shift;
|
||||
if ($self->{'selected'}) {
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
# this can persist across mod_perl requests:
|
||||
memoize('getSuperUserGroup', persist=>1);
|
||||
sub getSuperUserGroup {
|
||||
my $self = shift;
|
||||
my @rows = __PACKAGE__->search(name => "Litmus Super Administrators");
|
||||
return $rows[0];
|
||||
}
|
||||
memoize('getRunDayGroup', persist=>1);
|
||||
sub getRunDayGroup {
|
||||
my $self = shift;
|
||||
my @rows = __PACKAGE__->search(name => "Litmus Test Run/Test Day Administrators");
|
||||
return $rows[0];
|
||||
}
|
||||
1;
|
||||
|
||||
|
||||
|
||||
@ -139,7 +139,7 @@ sub coverage() {
|
||||
$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)";
|
||||
if ($trusted) {
|
||||
$sql .= ", users u";
|
||||
$sql .= ", users u, user_group_map ugm, security_groups sg";
|
||||
}
|
||||
$sql .= " WHERE tsg.subgroup_id=? AND tr.build_id=? AND tr.locale_abbrev=? AND o.platform_id=? AND o.opsys_id=?";
|
||||
if ($community_only) {
|
||||
@ -149,7 +149,8 @@ sub coverage() {
|
||||
$sql .= " AND tr.user_id=" . $user->{'user_id'};
|
||||
}
|
||||
if ($trusted) {
|
||||
$sql .= " AND tr.user_id=u.user_id AND u.is_admin=1";
|
||||
$sql .= " AND tr.user_id=u.user_id AND u.user_id=ugm.user_id AND ugm.group_id=sd.group_id ";
|
||||
$sql .= " AND (sd.grouptype=1 OR sd.grouptype=3)";
|
||||
}
|
||||
|
||||
$sql .= " GROUP BY tr.testcase_id";
|
||||
|
||||
@ -53,6 +53,14 @@ Litmus::DB::TestRun->has_a(product => "Litmus::DB::Product");
|
||||
Litmus::DB::TestRun->has_a(branch => "Litmus::DB::Branch");
|
||||
Litmus::DB::TestRun->has_a(author => "Litmus::DB::User");
|
||||
|
||||
Litmus::DB::TestRun->set_sql('daterange' => qq {
|
||||
SELECT __ESSENTIAL__
|
||||
FROM __TABLE__
|
||||
WHERE
|
||||
start_timestamp<= ? AND finish_timestamp>?
|
||||
ORDER BY finish_timestamp ASC, product_id ASC, branch_id ASC, test_run_id ASC
|
||||
});
|
||||
|
||||
#########################################################################
|
||||
sub getCriteria() {
|
||||
my $self = shift;
|
||||
@ -313,8 +321,11 @@ sub coverage {
|
||||
|
||||
my $sql = "
|
||||
SELECT COUNT(DISTINCT(tr.testcase_id))
|
||||
FROM test_runs trun, test_run_testgroups truntg, testgroups tg, subgroup_testgroups sgtg, subgroups sg, testcase_subgroups tcsg, testcases tc, test_results tr, opsyses o, platforms pl, users u
|
||||
WHERE
|
||||
FROM test_runs trun, test_run_testgroups truntg, testgroups tg, subgroup_testgroups sgtg, subgroups sg, testcase_subgroups tcsg, testcases tc, test_results tr, opsyses o, platforms pl, users u";
|
||||
if ($trusted) {
|
||||
$sql .= ", user_group_map ugm, security_groups secgrps";
|
||||
}
|
||||
$sql .= " WHERE
|
||||
trun.test_run_id=? AND
|
||||
trun.test_run_id=truntg.test_run_id AND
|
||||
truntg.testgroup_id=sgtg.testgroup_id AND
|
||||
@ -343,7 +354,8 @@ WHERE
|
||||
}
|
||||
|
||||
if ($trusted) {
|
||||
$sql .= " AND u.is_admin=1";
|
||||
$sql .= " AND tr.user_id=u.user_id AND u.user_id=ugm.user_id AND
|
||||
ugm.group_id=sd.group_id AND (secgrps.grouptype=1 OR secgrps.grouptype=3)";
|
||||
}
|
||||
|
||||
$sql .= $self->getCriteriaSql();
|
||||
@ -373,8 +385,11 @@ sub getNumResultsByStatus {
|
||||
|
||||
my $sql = "
|
||||
SELECT COUNT(DISTINCT(tr.testresult_id))
|
||||
FROM test_runs trun, test_run_testgroups truntg, testgroups tg, subgroup_testgroups sgtg, subgroups sg, testcase_subgroups tcsg, testcases tc, test_results tr, opsyses o, platforms pl, users u
|
||||
WHERE
|
||||
FROM test_runs trun, test_run_testgroups truntg, testgroups tg, subgroup_testgroups sgtg, subgroups sg, testcase_subgroups tcsg, testcases tc, test_results tr, opsyses o, platforms pl, users u";
|
||||
if ($trusted) {
|
||||
$sql .= ", user_group_map ugm, security_groups secgrps";
|
||||
}
|
||||
$sql .= " WHERE
|
||||
trun.test_run_id=? AND
|
||||
trun.test_run_id=truntg.test_run_id AND
|
||||
truntg.testgroup_id=sgtg.testgroup_id AND
|
||||
@ -404,7 +419,8 @@ WHERE
|
||||
}
|
||||
|
||||
if ($trusted) {
|
||||
$sql .= " AND u.is_admin=1";
|
||||
$sql .= " AND tr.user_id=u.user_id AND u.user_id=ugm.user_id AND
|
||||
ugm.group_id=sd.group_id AND (secgrps.grouptype=1 OR secgrps.grouptype=3)";
|
||||
}
|
||||
|
||||
$sql .= $self->getCriteriaSql();
|
||||
@ -427,8 +443,11 @@ sub getNumResultsWithComments {
|
||||
|
||||
my $sql = "
|
||||
SELECT COUNT(DISTINCT(tr.testresult_id))
|
||||
FROM test_runs trun, test_run_testgroups trtg, testgroups tg, subgroup_testgroups sgtg, subgroups sg, testcase_subgroups tcsg, testcases tc, test_results tr INNER JOIN test_result_comments trc ON tr.testresult_id=trc.test_result_id, opsyses o, platforms pl, users u
|
||||
WHERE
|
||||
FROM test_runs trun, test_run_testgroups trtg, testgroups tg, subgroup_testgroups sgtg, subgroups sg, testcase_subgroups tcsg, testcases tc, test_results tr INNER JOIN test_result_comments trc ON tr.testresult_id=trc.test_result_id, opsyses o, platforms pl, users u ";
|
||||
if ($trusted) {
|
||||
$sql .= ", user_group_map ugm, security_groups secgrps";
|
||||
}
|
||||
$sql .= " WHERE
|
||||
trun.test_run_id=? AND
|
||||
trun.test_run_id=trtg.test_run_id AND
|
||||
trtg.testgroup_id=sgtg.testgroup_id AND
|
||||
@ -457,7 +476,8 @@ WHERE
|
||||
}
|
||||
|
||||
if ($trusted) {
|
||||
$sql .= " AND u.is_admin=1";
|
||||
$sql .= " AND tr.user_id=u.user_id AND u.user_id=ugm.user_id AND
|
||||
ugm.group_id=sd.group_id AND (secgrps.grouptype=1 OR secgrps.grouptype=3)";
|
||||
}
|
||||
|
||||
$sql .= $self->getCriteriaSql();
|
||||
|
||||
@ -232,7 +232,8 @@ sub coverage() {
|
||||
$where .= " AND tr.user_id=" . quotemeta($user->{'user_id'});
|
||||
}
|
||||
if ($trusted) {
|
||||
$where .= " AND u.is_admin=1";
|
||||
$from .= ", user_group_map ugm, security_groups sg";
|
||||
$where .= " AND tr.user_id=u.user_id AND u.user_id=ugm.user_id AND ugm.group_id=sd.group_id AND (sg.grouptype=1 OR sg.grouptype=3)";
|
||||
}
|
||||
my $sql = $select . $from . $where . $order_by;
|
||||
#print $sql,"<br/>\n";
|
||||
|
||||
@ -125,13 +125,16 @@ Litmus::DB::Testresult->set_sql(CompletedByUser => qq{
|
||||
|
||||
Litmus::DB::Testresult->set_sql(CompletedByTrusted => qq{
|
||||
SELECT tr.*
|
||||
FROM test_results tr, users u
|
||||
FROM test_results tr, users u, users u,
|
||||
user_group_map ugm, security_groups sg
|
||||
WHERE tr.testcase_id=? AND
|
||||
tr.build_id=? AND
|
||||
tr.locale_abbrev=? AND
|
||||
tr.opsys_id=? AND
|
||||
tr.user_id=u.user_id AND
|
||||
u.is_admin=1
|
||||
AND tr.user_id=u.user_id AND u.user_id=ugm.user_id AND
|
||||
ugm.group_id=sd.group_id AND
|
||||
(sd.grouptype=1 OR sd.grouptype=3)
|
||||
ORDER BY tr.submission_time DESC
|
||||
});
|
||||
|
||||
@ -231,14 +234,22 @@ sub getTestResults($\@\@$) {
|
||||
} elsif ($criterion->{'field'} eq 'trusted_only') {
|
||||
if ($criterion->{'value'} ne 'all') {
|
||||
if ($from !~ /users u/) {
|
||||
$from .= ", users u";
|
||||
$from .= ", users u"
|
||||
}
|
||||
$from .= ", user_group_map ugm, ";
|
||||
$from .= "security_groups secgps, group_product_map gpm";
|
||||
}
|
||||
$where .= " AND u.user_id=tr.user_id AND u.is_admin=";
|
||||
if ($criterion->{'value'} == 1 or $criterion->{'value'} eq 'on') {
|
||||
$where .= '1';
|
||||
$where .= qq{ AND u.user_id=tr.user_id AND (
|
||||
u.user_id=ugm.user_id
|
||||
AND ugm.group_id=secgps.group_id AND
|
||||
secgps.grouptype=1) OR
|
||||
(gpm.product_id=pr.product_id AND
|
||||
gpm.group_id=secgps.group_id AND
|
||||
secgps.grouptype=3)};
|
||||
} else {
|
||||
$where .= '0';
|
||||
$where .= '(secgps.grouptype != 1 AND secgps.grouptype != 2
|
||||
AND secgps.grouptype != 3)';
|
||||
}
|
||||
} elsif ($criterion->{'field'} eq 'vetted_only') {
|
||||
if ($criterion->{'value'} ne 'all') {
|
||||
|
||||
@ -34,19 +34,23 @@ package Litmus::DB::User;
|
||||
|
||||
use strict;
|
||||
use Litmus::Config;
|
||||
use Litmus::Memoize;
|
||||
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->columns(TEMP => qw/num_results/);
|
||||
Litmus::DB::User->columns(All => qw/user_id bugzilla_uid email password realname irc_nickname enabled authtoken/);
|
||||
Litmus::DB::User->columns(TEMP => qw/is_admin_old num_results/);
|
||||
|
||||
Litmus::DB::User->column_alias("isSuperUser", "istrusted");
|
||||
Litmus::DB::User->column_alias("isSuperUser", "is_trusted");
|
||||
Litmus::DB::User->column_alias("isSuperUser", "is_admin");
|
||||
|
||||
Litmus::DB::User->column_alias("is_trusted", "istrusted");
|
||||
Litmus::DB::User->column_alias("is_admin", "is_trusted");
|
||||
Litmus::DB::User->column_alias("email", "username");
|
||||
|
||||
Litmus::DB::User->has_many(test_results => "Litmus::DB::Testresult");
|
||||
Litmus::DB::User->has_many(sessions => "Litmus::DB::Session");
|
||||
Litmus::DB::User->has_many(groups => ["Litmus::DB::UserGroupMap" => 'group']);
|
||||
|
||||
# ZLL: only load BugzillaUser if Bugzilla Auth is actually enabled
|
||||
if ($Litmus::Config::bugzilla_auth_enabled) {
|
||||
@ -68,6 +72,63 @@ __PACKAGE__->set_sql(TopTesters => qq{
|
||||
LIMIT 15
|
||||
});
|
||||
|
||||
|
||||
|
||||
#########################################################################
|
||||
# search for users by email, irc nick, realname, or group
|
||||
sub search_full_text {
|
||||
my $self = shift;
|
||||
my $email = shift;
|
||||
my $nick = shift;
|
||||
my $realname = shift;
|
||||
my @groups = shift;
|
||||
|
||||
my $dbh = Litmus::DBI->db_Main();
|
||||
my @args;
|
||||
|
||||
my $sql = q{
|
||||
SELECT DISTINCT users.user_id, users.email, users.irc_nickname
|
||||
FROM users, user_group_map
|
||||
WHERE
|
||||
(
|
||||
};
|
||||
|
||||
if ($email) {
|
||||
$sql .= "users.email COLLATE latin1_general_ci like concat('%%',?,'%%') OR ";
|
||||
push(@args, $email);
|
||||
}
|
||||
if ($nick) {
|
||||
$sql .= "users.irc_nickname COLLATE latin1_general_ci like concat('%%',?,'%%') OR ";
|
||||
push(@args, $nick);
|
||||
}
|
||||
if ($realname) {
|
||||
$sql .= "users.realname COLLATE latin1_general_ci like concat('%%',?,'%%')";
|
||||
push(@args, $realname);
|
||||
}
|
||||
# catch all case for no email, nick, or realname
|
||||
if (! ($realname || $nick || $email)) {
|
||||
$sql .= "1=1";
|
||||
}
|
||||
|
||||
|
||||
$sql .= ")";
|
||||
|
||||
if ($groups[0]) {
|
||||
$sql .= " AND ((user_group_map.user_id = users.user_id) ";
|
||||
foreach my $cur (@groups) {
|
||||
$sql .= "AND user_group_map.group_id = ".$cur->group_id();
|
||||
}
|
||||
$sql .= ") ";
|
||||
}
|
||||
|
||||
$sql .= "GROUP BY users.user_id ";
|
||||
$sql .= "ORDER BY users.email ASC";
|
||||
|
||||
my $sth = $dbh->prepare($sql);
|
||||
$sth->execute(@args);
|
||||
return $self->sth_to_objects($sth);
|
||||
}
|
||||
|
||||
# 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
|
||||
@ -96,6 +157,7 @@ sub getRealPasswd {
|
||||
}
|
||||
|
||||
#########################################################################
|
||||
memoize('getDisplayName');
|
||||
sub getDisplayName() {
|
||||
my $self = shift;
|
||||
|
||||
@ -114,6 +176,96 @@ sub getDisplayName() {
|
||||
return undef;
|
||||
}
|
||||
|
||||
#########################################################################
|
||||
# Group functions
|
||||
#########################################################################
|
||||
__PACKAGE__->set_sql(userInGroup => q{
|
||||
SELECT DISTINCT users.user_id FROM __TABLE__, security_groups, user_group_map
|
||||
WHERE
|
||||
user_group_map.group_id = ? AND users.user_id = user_group_map.user_id
|
||||
AND users.user_id= ?
|
||||
});
|
||||
|
||||
__PACKAGE__->set_sql(userInAnyAdminGroup => q{
|
||||
SELECT DISTINCT users.user_id FROM __TABLE__, security_groups, user_group_map
|
||||
WHERE
|
||||
(security_groups.grouptype=1 OR security_groups.grouptype=2
|
||||
OR security_groups.grouptype=3) AND
|
||||
users.user_id = user_group_map.user_id
|
||||
AND users.user_id= ?
|
||||
});
|
||||
|
||||
__PACKAGE__->set_sql(userInProductAdminGroup => q{
|
||||
SELECT DISTINCT users.user_id FROM __TABLE__, security_groups,
|
||||
user_group_map, group_product_map
|
||||
WHERE security_groups.grouptype=3 AND
|
||||
users.user_id = user_group_map.user_id AND
|
||||
user_group_map.group_id=security_groups.group_id AND
|
||||
users.user_id= ? AND
|
||||
security_groups.group_id=group_product_map.group_id AND
|
||||
group_product_map.product_id = ?
|
||||
});
|
||||
|
||||
# returns true if the user is a member of $group, otherwise false
|
||||
memoize('inGroup');
|
||||
sub inGroup {
|
||||
my $self = shift;
|
||||
my $group = shift;
|
||||
|
||||
my @users = __PACKAGE__->search_userInGroup($group, $self);
|
||||
|
||||
if (@users) { return 1 }
|
||||
return 0;
|
||||
}
|
||||
|
||||
memoize('isSuperUser');
|
||||
sub isSuperUser {
|
||||
my $self = shift;
|
||||
if ($self->inGroup(Litmus::DB::SecurityGroup->getSuperUserGroup)) {
|
||||
return 1;
|
||||
}
|
||||
else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
memoize('isRunDayAdmin');
|
||||
sub isRunDayAdmin {
|
||||
my $self = shift;
|
||||
if ($self->inGroup(Litmus::DB::SecurityGroup->getRunDayGroup()) ||
|
||||
$self->isSuperUser()) {
|
||||
return 1;
|
||||
}
|
||||
else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
# returns true if the user is a superuser or a member of any product admin group
|
||||
# (to determine whether to show any admin controls)
|
||||
memoize('isInAdminGroup');
|
||||
sub isInAdminGroup {
|
||||
my $self = shift;
|
||||
my @rows = $self->search_userInAnyAdminGroup($self);
|
||||
if (@rows) {
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
# returns true if the user is an admin of $product
|
||||
memoize('isProductAdmin');
|
||||
sub isProductAdmin {
|
||||
my $self = shift;
|
||||
my $product = shift;
|
||||
|
||||
my @users = $self->search_userInProductAdminGroup($self, $product);
|
||||
if (@users) {
|
||||
return 1;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
1;
|
||||
|
||||
|
||||
66
mozilla/webtools/litmus/Litmus/DB/UserGroupMap.pm
Executable file
66
mozilla/webtools/litmus/Litmus/DB/UserGroupMap.pm
Executable file
@ -0,0 +1,66 @@
|
||||
# -*- 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::UserGroupMap;
|
||||
|
||||
use strict;
|
||||
use Litmus::Config;
|
||||
use base 'Litmus::DBI';
|
||||
|
||||
Litmus::DB::UserGroupMap->table('user_group_map');
|
||||
|
||||
Litmus::DB::UserGroupMap->columns(All => qw/user_id group_id/);
|
||||
Litmus::DB::UserGroupMap->columns(TEMP => qw//);
|
||||
|
||||
Litmus::DB::UserGroupMap->column_alias("user_id", "user");
|
||||
Litmus::DB::UserGroupMap->column_alias("group_id", "group");
|
||||
|
||||
Litmus::DB::UserGroupMap->has_a(user => "Litmus::DB::User");
|
||||
Litmus::DB::UserGroupMap->has_a(group => "Litmus::DB::SecurityGroup");
|
||||
|
||||
__PACKAGE__->set_sql(remove_map => q{
|
||||
DELETE FROM __TABLE__ WHERE
|
||||
user_id = ? AND group_id = ?
|
||||
});
|
||||
|
||||
sub remove {
|
||||
my $self = shift;
|
||||
my $user_id = shift;
|
||||
my $group_id = shift;
|
||||
my $sth = __PACKAGE__->sql_remove_map;
|
||||
$sth->execute($user_id, $group_id);
|
||||
}
|
||||
|
||||
1;
|
||||
|
||||
|
||||
|
||||
@ -36,7 +36,7 @@ require Apache::DBI;
|
||||
use strict;
|
||||
use warnings;
|
||||
use Litmus::Config;
|
||||
use Memoize;
|
||||
use Litmus::Memoize;
|
||||
|
||||
use base 'Class::DBI::mysql';
|
||||
|
||||
@ -60,7 +60,7 @@ sub column_alias {
|
||||
# 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');
|
||||
memoize('find_column', persist=>1);
|
||||
sub find_column {
|
||||
my $self = shift;
|
||||
my $wanted = shift;
|
||||
|
||||
@ -295,14 +295,20 @@ sub getTestdays()
|
||||
#########################################################################
|
||||
sub getAuthors()
|
||||
{
|
||||
my $sql = "SELECT user_id, email FROM users WHERE is_admin=1 ORDER BY email";
|
||||
my $sql = "SELECT users.user_id, users.email FROM users, user_group_map, security_groups
|
||||
WHERE
|
||||
users.user_id=user_group_map.user_id AND
|
||||
user_group_map.group_id=security_groups.group_id AND
|
||||
(security_groups.grouptype=1 OR security_groups.grouptype=2
|
||||
OR security_groups.grouptype=3)
|
||||
ORDER BY users.email";
|
||||
return _getValues($sql);
|
||||
}
|
||||
|
||||
#########################################################################
|
||||
sub getTestRuns() {
|
||||
my ($self, $enabled) = @_;
|
||||
my $sql = "SELECT test_run_id, name FROM test_runs";
|
||||
my $sql = "SELECT test_run_id, name, product_id FROM test_runs";
|
||||
if ($enabled) {
|
||||
$sql .= " WHERE enabled=1";
|
||||
}
|
||||
|
||||
63
mozilla/webtools/litmus/Litmus/Mailer.pm
Executable file
63
mozilla/webtools/litmus/Litmus/Mailer.pm
Executable file
@ -0,0 +1,63 @@
|
||||
# -*- 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) 2007
|
||||
# the Initial Developer. All Rights Reserved.
|
||||
#
|
||||
# Contributor(s):
|
||||
# Zach Lipton <zach@zachlipton.com>
|
||||
#
|
||||
# ***** END LICENSE BLOCK *****
|
||||
|
||||
=cut
|
||||
|
||||
# Email management functions
|
||||
|
||||
package Litmus::Mailer;
|
||||
|
||||
use strict;
|
||||
|
||||
#use Litmus;
|
||||
use Litmus::Error;
|
||||
#use Litmus::Config;
|
||||
use Email::MIME;
|
||||
use Email::MIME::Modifier;
|
||||
use Email::Send;
|
||||
|
||||
our @ISA = qw(Exporter);
|
||||
@Litmus::Mailer::EXPORT = qw(
|
||||
sendMessage
|
||||
);
|
||||
|
||||
# cribbed in part from Bugzilla's MessageToMTA
|
||||
sub sendMessage {
|
||||
my $msg = shift;
|
||||
|
||||
local $ENV{PATH} = $Litmus::Config::sendmail_path;
|
||||
|
||||
open(MAIL, "| sendmail -t -oi") || Litmus::Error::basicError("Could not send email: $!");
|
||||
print MAIL $msg || Litmus::Error::basicError("Could not send email: $!");
|
||||
close(MAIL) || Litmus::Error::basicError("Could not send email: $!");
|
||||
}
|
||||
|
||||
|
||||
|
||||
1;
|
||||
81
mozilla/webtools/litmus/Litmus/Memoize.pm
Executable file
81
mozilla/webtools/litmus/Litmus/Memoize.pm
Executable file
@ -0,0 +1,81 @@
|
||||
# -*- 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::Memoize;
|
||||
|
||||
use strict;
|
||||
use Exporter;
|
||||
our @EXPORT = qw(memoize);
|
||||
use Memoize ();
|
||||
use base 'Memoize';
|
||||
|
||||
# Subclass of Memoize.pm that gives us control over when our data is
|
||||
# flushed and ensures that cached data does not persist across mod_perl
|
||||
# requests unless we really want it to
|
||||
|
||||
sub memoize {
|
||||
my $fn = shift;
|
||||
my %options = @_;
|
||||
|
||||
if ($ENV{MOD_PERL} && ! Apache->request()) {
|
||||
return;
|
||||
}
|
||||
|
||||
my $uppack = caller;
|
||||
|
||||
$options{INSTALL} = $uppack . '::' . $fn;
|
||||
|
||||
$fn = Memoize::_make_cref($fn, $uppack);
|
||||
|
||||
# if the persist flag is given, we store the memoized data normally
|
||||
# and it will persist across mod_perl requests
|
||||
if ($options{persist}) {
|
||||
Memoize::memoize($fn, %options);
|
||||
return;
|
||||
}
|
||||
|
||||
# otherwise, we keep the cache in request_cache where it will get
|
||||
# flushed when the request ends
|
||||
my $cache = {};
|
||||
if ($ENV{MOD_PERL}) {
|
||||
$cache = Apache->request()->pnotes();
|
||||
}
|
||||
$cache->{'S'.$fn} = {};
|
||||
$cache->{'L'.$fn} = {};
|
||||
my $s_cache = $cache->{'S'.$fn};
|
||||
my $l_cache = $cache->{'L'.$fn};
|
||||
$options{SCALAR_CACHE} = [HASH => $s_cache];
|
||||
$options{LIST_CACHE} = [HASH => $l_cache];
|
||||
Memoize::memoize($fn, %options);
|
||||
return;
|
||||
}
|
||||
|
||||
1;
|
||||
@ -44,18 +44,37 @@ my $c = Litmus->cgi();
|
||||
Litmus::Auth::requireLogin("edit_users.cgi");
|
||||
|
||||
# Only trusted users can edit other users.
|
||||
my $cookie = Litmus::Auth::getCookie();
|
||||
my $cookie = undef;
|
||||
$cookie = Litmus::Auth::getCookie();
|
||||
if (Litmus::Auth::istrusted($cookie)) {
|
||||
|
||||
if ($c->param('search_string')) {
|
||||
if ($c->param('submit')) {
|
||||
# search for users:
|
||||
my @users = Litmus::DB::User->search_FullTextMatches(
|
||||
|
||||
# gather group membership bits:
|
||||
my @groups = Litmus::DB::SecurityGroup->retrieve_all(order_by => "grouptype, group_id");
|
||||
my @group_search;
|
||||
my %checked;
|
||||
foreach my $cur (@groups) {
|
||||
if ($c->param("group_".$cur->group_id())) {
|
||||
push(@group_search, $cur);
|
||||
$checked{$cur->group_id()} = 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
my @users = Litmus::DB::User->search_full_text(
|
||||
$c->param('search_string'),
|
||||
$c->param('search_string'),
|
||||
$c->param('search_string'));
|
||||
$c->param('search_string'),
|
||||
@group_search);
|
||||
|
||||
|
||||
my $vars = {
|
||||
users => \@users,
|
||||
search_string => $c->param('search_string'),
|
||||
groups => \@groups,
|
||||
checked => \%checked,
|
||||
};
|
||||
print $c->header();
|
||||
Litmus->template()->process("admin/edit_users/search_results.html.tmpl", $vars) ||
|
||||
@ -68,9 +87,11 @@ if (Litmus::Auth::istrusted($cookie)) {
|
||||
if (! $user) {
|
||||
invalidInputError("Invalid user ID: $uid");
|
||||
}
|
||||
my @groups = Litmus::DB::SecurityGroup->retrieve_all();
|
||||
my $vars = {
|
||||
user => $user,
|
||||
};
|
||||
groups => \@groups,
|
||||
};
|
||||
Litmus->template()->process("admin/edit_users/edit_user.html.tmpl", $vars) ||
|
||||
internalError(Litmus->template()->error());
|
||||
} elsif ($c->param('user_id')) {
|
||||
@ -101,16 +122,23 @@ if (Litmus::Auth::istrusted($cookie)) {
|
||||
$revoke_sessions = 1;
|
||||
}
|
||||
}
|
||||
|
||||
# Check to see whether we are changing the admin status of this user.
|
||||
if ($c->param('is_admin')) {
|
||||
$user->is_admin(1);
|
||||
} else {
|
||||
if ($user->is_admin) {
|
||||
$user->is_admin(0);
|
||||
$revoke_sessions = 1;
|
||||
}
|
||||
|
||||
$user->authtoken($c->param('authtoken'));
|
||||
|
||||
# process changes to group permissions:
|
||||
my @allgroups = Litmus::DB::SecurityGroup->retrieve_all();
|
||||
foreach my $group (@allgroups) {
|
||||
if ($c->param("group_".$group->group_id())) {
|
||||
# we're blessing this user
|
||||
Litmus::DB::UserGroupMap->find_or_create(user=>$user, group=>$group);
|
||||
$revoke_sessions = 1;
|
||||
} else {
|
||||
# unblesing (if previously blessed) the user
|
||||
Litmus::DB::UserGroupMap->remove($user, $group);
|
||||
$revoke_sessions = 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
$user->authtoken($c->param('authtoken'));
|
||||
$user->update();
|
||||
@ -121,13 +149,16 @@ if (Litmus::Auth::istrusted($cookie)) {
|
||||
|
||||
my $vars = {
|
||||
user => $user,
|
||||
onload => "toggleMessage('success','User information updated successfully.');"
|
||||
onload => "toggleMessage('success','User information updated successfully.');",
|
||||
groups => \@allgroups,
|
||||
};
|
||||
Litmus->template()->process("admin/edit_users/search_users.html.tmpl", $vars) ||
|
||||
internalError(Litmus->template()->error());
|
||||
} else {
|
||||
# we're here for the first time, so display the search form
|
||||
my @groups = Litmus::DB::SecurityGroup->retrieve_all();
|
||||
my $vars = {
|
||||
groups => \@groups,
|
||||
};
|
||||
print $c->header();
|
||||
Litmus->template()->process("admin/edit_users/search_users.html.tmpl", $vars) ||
|
||||
|
||||
@ -169,8 +169,8 @@ function populateTestRun(data) {
|
||||
|
||||
setAuthor(test_run.author_id.user_id);
|
||||
|
||||
var enabled_em = document.getElementById('enabled')
|
||||
var enabled_display_em = document.getElementById('enabled_display')
|
||||
var enabled_em = document.getElementById('enabled');
|
||||
var enabled_display_em = document.getElementById('enabled_display');
|
||||
if (test_run.enabled == 1) {
|
||||
enabled_em.checked = true;
|
||||
enabled_display_em.checked = true;
|
||||
|
||||
@ -37,14 +37,31 @@ Litmus->init();
|
||||
|
||||
my $title = "Log in";
|
||||
|
||||
# allow the user to reset their forgotten password
|
||||
my $c = Litmus->cgi();
|
||||
if ($c->param('resetPassword')) {
|
||||
Litmus::Auth::resetPasswordForm($c->param('resetPassword'));
|
||||
exit;
|
||||
}
|
||||
if ($c->param('login_type') eq 'doResetPassword') {
|
||||
# check that the two password fields are equal:
|
||||
if ($c->param('password') ne $c->param('password_confirm')) {
|
||||
invalidInputError("The 'password' and 'confirm password' fields do
|
||||
not match. Please try again");
|
||||
}
|
||||
Litmus::Auth::doResetPassword($c->param('user'), $c->param('token'),
|
||||
$c->param('password'));
|
||||
print $c->header();
|
||||
}
|
||||
|
||||
Litmus::Auth::requireLogin("index.cgi");
|
||||
|
||||
# if we end up here, it means the user was already logged in
|
||||
# for some reason, so we should send a redirect to index.cgi:
|
||||
print Litmus->cgi()->start_html(-title=>'Please Wait',
|
||||
-head=>Litmus->cgi()->meta({-http_equiv=> 'refresh', -content=>'0;url=index.cgi'})
|
||||
print $c->start_html(-title=>'Please Wait',
|
||||
-head=>$c->meta({-http_equiv=> 'refresh', -content=>'0;url=index.cgi'})
|
||||
);
|
||||
print Litmus->cgi()->end_html();
|
||||
print $c->end_html();
|
||||
|
||||
exit;
|
||||
|
||||
|
||||
@ -44,7 +44,7 @@ use JSON;
|
||||
use Time::Piece::MySQL;
|
||||
|
||||
Litmus->init();
|
||||
Litmus::Auth::requireAdmin("edit_categories.cgi");
|
||||
Litmus::Auth::requireProductAdmin("edit_categories.cgi");
|
||||
|
||||
my $c = Litmus->cgi();
|
||||
print $c->header();
|
||||
@ -56,6 +56,16 @@ my $rebuild_cache = 0;
|
||||
my $defaults;
|
||||
|
||||
if ($c->param) {
|
||||
# auth:
|
||||
# must be a super user for all changes but branch changes:
|
||||
if ((!Litmus::Auth::getCurrentUser()->isSuperUser()) &&
|
||||
($c->param("product_id") || $c->param("edit_product_form_mode") ||
|
||||
$c->param("platform_id") || $c->param("edit_platform_form_mode") ||
|
||||
$c->param("opsys_id") || $c->param("edit_opsys_form_mode") ||
|
||||
$c->param("edit_opsys_form_opsys_id"))) {
|
||||
Litmus::Auth::requireAdmin("manage_categories.cgi");
|
||||
}
|
||||
|
||||
# Process product changes.
|
||||
if ($c->param("delete_product_button") and
|
||||
$c->param("product_id")) {
|
||||
@ -250,6 +260,8 @@ if ($c->param) {
|
||||
my $branch_id = $c->param("branch_id");
|
||||
my $branch = Litmus::DB::Branch->retrieve($branch_id);
|
||||
if ($branch) {
|
||||
# must be a product admin
|
||||
Litmus::Auth::requireProductAdmin("manage_categories.cgi", $branch->product());
|
||||
$rv = $branch->delete;
|
||||
if ($rv) {
|
||||
$status = "success";
|
||||
@ -264,6 +276,11 @@ if ($c->param) {
|
||||
$message = "Branch ID# $branch_id does not exist. (Already deleted?)";
|
||||
}
|
||||
} elsif ($c->param("edit_branch_form_mode")) {
|
||||
# need to be a product admin for the branch's product and for any
|
||||
# product the branch may be moved into:
|
||||
Litmus::Auth::requireProductAdmin("manage_categories",
|
||||
$c->param('edit_branch_form_product_id'));
|
||||
|
||||
my $enabled = $c->param('edit_branch_form_enabled') ? 1 : 0;
|
||||
if ($c->param("edit_branch_form_mode") eq "add") {
|
||||
my %hash = (
|
||||
@ -287,6 +304,10 @@ if ($c->param) {
|
||||
my $branch_id = $c->param("edit_branch_form_branch_id");
|
||||
my $branch = Litmus::DB::Branch->retrieve($branch_id);
|
||||
if ($branch) {
|
||||
# must be a product admin to edit the branch:
|
||||
Litmus::Auth::requireProductAdmin('manage_categories.cgi',
|
||||
$branch->product());
|
||||
|
||||
$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') : '');
|
||||
@ -321,6 +342,23 @@ my $testgroups = Litmus::FormWidget->getTestgroups();
|
||||
my $opsyses = Litmus::FormWidget->getOpsyses();
|
||||
my $locales = Litmus::FormWidget->getLocales;
|
||||
|
||||
# if the user is not a superuser, only allow them access to the
|
||||
# branches they are product admins for
|
||||
my $authorized_branches;
|
||||
if (Litmus::Auth::getCurrentUser()->isSuperUser()) {
|
||||
$authorized_branches = $branches;
|
||||
} else {
|
||||
my @tmp;
|
||||
foreach my $b (@{$branches}) {
|
||||
my %cur = %{$b};
|
||||
if (Litmus::Auth::getCurrentUser()->isProductAdmin($cur{product_id})) {
|
||||
push(@tmp, $b);
|
||||
}
|
||||
}
|
||||
$authorized_branches = \@tmp;
|
||||
}
|
||||
$branches = $authorized_branches;
|
||||
|
||||
my $json = JSON->new(skipinvalid => 1, convblessed => 1);
|
||||
my $products_js = $json->objToJson($products);
|
||||
my $branches_js = $json->objToJson($branches);
|
||||
|
||||
@ -76,7 +76,7 @@ if ($c->param("searchSubgroupList")) {
|
||||
|
||||
# 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');
|
||||
Litmus::Auth::requireProductAdmin('manage_subgroups.cgi');
|
||||
|
||||
if ($c->param("subgroup_id")) {
|
||||
$subgroup_id = $c->param("subgroup_id");
|
||||
@ -86,6 +86,7 @@ my $defaults;
|
||||
if ($c->param("delete_subgroup_button")) {
|
||||
my $subgroup = Litmus::DB::Subgroup->retrieve($subgroup_id);
|
||||
if ($subgroup) {
|
||||
Litmus::Auth::requireProductAdmin("manage_subgroups.cgi", $subgroup->product());
|
||||
$rv = $subgroup->delete_with_refs();
|
||||
if ($rv) {
|
||||
$status = "success";
|
||||
@ -100,6 +101,7 @@ if ($c->param("delete_subgroup_button")) {
|
||||
}
|
||||
} elsif ($c->param("clone_subgroup_button")) {
|
||||
my $subgroup = Litmus::DB::Subgroup->retrieve($subgroup_id);
|
||||
Litmus::Auth::requireProductAdmin("manage_subgroups.cgi", $subgroup->product());
|
||||
my $new_subgroup = $subgroup->clone;
|
||||
if ($new_subgroup) {
|
||||
$status = "success";
|
||||
@ -114,6 +116,7 @@ if ($c->param("delete_subgroup_button")) {
|
||||
requireField('branch', $c->param('branch'));
|
||||
my $enabled = $c->param('enabled') ? 1 : 0;
|
||||
if ($c->param("mode") eq "add") {
|
||||
Litmus::Auth::requireProductAdmin("manage_subgroups.cgi", $c->param('product'));
|
||||
my %hash = (
|
||||
name => $c->param('name'),
|
||||
product_id => $c->param('product'),
|
||||
@ -139,6 +142,7 @@ if ($c->param("delete_subgroup_button")) {
|
||||
$subgroup_id = $c->param("editform_subgroup_id");
|
||||
my $subgroup = Litmus::DB::Subgroup->retrieve($subgroup_id);
|
||||
if ($subgroup) {
|
||||
Litmus::Auth::requireProductAdmin("manage_subgroups.cgi", $subgroup->product());
|
||||
$subgroup->product_id($c->param('product'));
|
||||
$subgroup->branch_id($c->param('branch'));
|
||||
$subgroup->enabled($enabled);
|
||||
@ -177,6 +181,51 @@ my $testgroups = Litmus::FormWidget->getTestgroups(0);
|
||||
my $subgroups = Litmus::FormWidget->getSubgroups(0,'name');
|
||||
my $testcases = Litmus::FormWidget->getTestcases(0,'name');
|
||||
|
||||
# only allow the user access to the products they are product admins for
|
||||
my %authorized_products;
|
||||
my @tmp_products;
|
||||
foreach my $b (@{$products}) {
|
||||
my %cur = %{$b};
|
||||
if (Litmus::Auth::getCurrentUser()->isProductAdmin($cur{product_id})) {
|
||||
push(@tmp_products, $b);
|
||||
$authorized_products{$cur{product_id}} = 1;
|
||||
}
|
||||
}
|
||||
$products = \@tmp_products;
|
||||
|
||||
# likewise for branches:
|
||||
my %authorized_branches;
|
||||
my @tmp_branches;
|
||||
foreach my $b (@{$branches}) {
|
||||
my %cur = %{$b};
|
||||
if ($authorized_products{$cur{product_id}}) {
|
||||
push(@tmp_branches, $b);
|
||||
$authorized_branches{$cur{branch_id}} = 1;
|
||||
}
|
||||
}
|
||||
$branches = \@tmp_branches;
|
||||
|
||||
# and testgroups
|
||||
my @tmp_testgroups;
|
||||
foreach my $b (@{$testgroups}) {
|
||||
my %cur = %{$b};
|
||||
if ($authorized_products{$cur{product_id}}) {
|
||||
push(@tmp_testgroups, $b);
|
||||
}
|
||||
}
|
||||
$testgroups = \@tmp_testgroups;
|
||||
|
||||
# and of course, subgroups
|
||||
my @tmp_subgroups;
|
||||
foreach my $b (@{$subgroups}) {
|
||||
my %cur = %{$b};
|
||||
if ($authorized_products{$cur{product_id}}) {
|
||||
push(@tmp_subgroups, $b);
|
||||
}
|
||||
}
|
||||
$subgroups = \@tmp_subgroups;
|
||||
|
||||
|
||||
my $json = JSON->new(skipinvalid => 1, convblessed => 1);
|
||||
my $products_js = $json->objToJson($products);
|
||||
my $branches_js = $json->objToJson($branches);
|
||||
|
||||
@ -70,7 +70,7 @@ if ($c->param("searchTestRunList")) {
|
||||
}
|
||||
|
||||
|
||||
Litmus::Auth::requireAdmin('manage_test_runs.cgi');
|
||||
Litmus::Auth::requireRunDayAdmin('manage_test_runs.cgi');
|
||||
|
||||
if ($c->param("test_run_id")) {
|
||||
$test_run_id = $c->param("test_run_id");
|
||||
@ -79,6 +79,7 @@ my $defaults;
|
||||
if ($c->param("delete_test_run_button")) {
|
||||
my $test_run = Litmus::DB::TestRun->retrieve($test_run_id);
|
||||
if ($test_run) {
|
||||
Litmus::Auth::requireProductAdmin("manage_test_runs.cgi", $test_run->product());
|
||||
$rv = $test_run->delete_with_refs();
|
||||
if ($rv) {
|
||||
$status = "success";
|
||||
@ -93,13 +94,20 @@ if ($c->param("delete_test_run_button")) {
|
||||
}
|
||||
} elsif ($c->param("clone_test_run_button")) {
|
||||
my $test_run = Litmus::DB::TestRun->retrieve($test_run_id);
|
||||
my $new_test_run = $test_run->clone;
|
||||
if ($new_test_run) {
|
||||
$status = "success";
|
||||
$message = "Test run cloned successfully. New test_run ID# is " . $new_test_run->test_run_id;
|
||||
$defaults->{'test_run_id'} = $new_test_run->test_run_id;
|
||||
if ($test_run) {
|
||||
Litmus::Auth::requireProductAdmin("manage_test_runs.cgi", $test_run->product());
|
||||
my $new_test_run = $test_run->clone;
|
||||
if ($new_test_run) {
|
||||
Litmus::Auth::requireProductAdmin("manage_test_runs.cgi", $test_run->product());
|
||||
$status = "success";
|
||||
$message = "Test run cloned successfully. New test_run ID# is " . $new_test_run->test_run_id;
|
||||
$defaults->{'test_run_id'} = $new_test_run->test_run_id;
|
||||
} else {
|
||||
$status = "failure";
|
||||
$message = "Failed to clone Test run ID# $test_run_id.";
|
||||
}
|
||||
} else {
|
||||
$status = "failure";
|
||||
$status = "failure";
|
||||
$message = "Failed to clone Test run ID# $test_run_id.";
|
||||
}
|
||||
} elsif ($c->param("mode")) {
|
||||
@ -108,6 +116,9 @@ if ($c->param("delete_test_run_button")) {
|
||||
requireField('branch', $c->param('branch'));
|
||||
requireField('start_timestamp', $c->param('start_timestamp'));
|
||||
requireField('finish_timestamp', $c->param('finish_timestamp'));
|
||||
|
||||
Litmus::Auth::requireProductAdmin("manage_test_runs.cgi", $c->param('product'));
|
||||
|
||||
my $enabled = $c->param('enabled') ? 1 : 0;
|
||||
my $recommended = $c->param('recommended') ? 1 : 0;
|
||||
my $now = &UnixDate("today", "%q");
|
||||
@ -149,6 +160,7 @@ if ($c->param("delete_test_run_button")) {
|
||||
$test_run_id = $c->param("editform_test_run_id");
|
||||
my $test_run = Litmus::DB::TestRun->retrieve($test_run_id);
|
||||
if ($test_run) {
|
||||
Litmus::Auth::requireProductAdmin("manage_test_runs.cgi", $test_run->product());
|
||||
$test_run->name($c->param('name'));
|
||||
$test_run->description($c->param('description'));
|
||||
$test_run->product_id($c->param('product'));
|
||||
@ -203,6 +215,50 @@ my $platforms = Litmus::FormWidget->getPlatforms();
|
||||
my $opsyses = Litmus::FormWidget->getOpsyses();
|
||||
my $authors = Litmus::FormWidget->getAuthors();
|
||||
|
||||
# only allow the user access to the products they are product admins for
|
||||
my %authorized_products;
|
||||
my @tmp_products;
|
||||
foreach my $b (@{$products}) {
|
||||
my %cur = %{$b};
|
||||
if (Litmus::Auth::getCurrentUser()->isProductAdmin($cur{product_id})) {
|
||||
push(@tmp_products, $b);
|
||||
$authorized_products{$cur{product_id}} = 1;
|
||||
}
|
||||
}
|
||||
$products = \@tmp_products;
|
||||
|
||||
# likewise for branches:
|
||||
my %authorized_branches;
|
||||
my @tmp_branches;
|
||||
foreach my $b (@{$branches}) {
|
||||
my %cur = %{$b};
|
||||
if ($authorized_products{$cur{product_id}}) {
|
||||
push(@tmp_branches, $b);
|
||||
$authorized_branches{$cur{branch_id}} = 1;
|
||||
}
|
||||
}
|
||||
$branches = \@tmp_branches;
|
||||
|
||||
# testgroups
|
||||
my @tmp_testgroups;
|
||||
foreach my $b (@{$testgroups}) {
|
||||
my %cur = %{$b};
|
||||
if ($authorized_products{$cur{product_id}}) {
|
||||
push(@tmp_testgroups, $b);
|
||||
}
|
||||
}
|
||||
$testgroups = \@tmp_testgroups;
|
||||
|
||||
# and, of course, testruns
|
||||
my @tmp_testruns;
|
||||
foreach my $b (@{$test_runs}) {
|
||||
my %cur = %{$b};
|
||||
if ($authorized_products{$cur{product_id}}) {
|
||||
push(@tmp_testruns, $b);
|
||||
}
|
||||
}
|
||||
$test_runs = \@tmp_testruns;
|
||||
|
||||
my $json = JSON->new(skipinvalid => 1, convblessed => 1);
|
||||
my $products_js = $json->objToJson($products);
|
||||
my $branches_js = $json->objToJson($branches);
|
||||
|
||||
@ -78,12 +78,17 @@ if ($c->param("searchTestcaseList")) {
|
||||
|
||||
# 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');
|
||||
Litmus::Auth::requireProductAdmin('manage_testcases.cgi');
|
||||
|
||||
if ($c->param("testcase_id")) {
|
||||
$testcase_id = $c->param("testcase_id");
|
||||
if ($c->param("edit")) {
|
||||
$edit = $testcase_id;
|
||||
# show an error if they are not a product admin for that product
|
||||
my $testcase = Litmus::DB::Testcase->retrieve($testcase_id);
|
||||
if ($testcase) {
|
||||
Litmus::Auth::requireProductAdmin("manage_testcases.cgi", $testcase->product());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -91,6 +96,7 @@ my $defaults;
|
||||
if ($c->param("delete_testcase_button")) {
|
||||
my $testcase = Litmus::DB::Testcase->retrieve($testcase_id);
|
||||
if ($testcase) {
|
||||
Litmus::Auth::requireProductAdmin("manage_testcases.cgi", $testcase->product());
|
||||
$rv = $testcase->delete_with_refs();
|
||||
if ($rv) {
|
||||
$status = "success";
|
||||
@ -105,6 +111,7 @@ if ($c->param("delete_testcase_button")) {
|
||||
}
|
||||
} elsif ($c->param("clone_testcase_button")) {
|
||||
my $testcase = Litmus::DB::Testcase->retrieve($testcase_id);
|
||||
Litmus::Auth::requireProductAdmin("manage_testcases.cgi", $testcase->product());
|
||||
my $new_testcase = $testcase->clone;
|
||||
if ($new_testcase) {
|
||||
$status = "success";
|
||||
@ -123,6 +130,7 @@ if ($c->param("delete_testcase_button")) {
|
||||
my $community_enabled = $c->param('communityenabled') ? 1 : 0;
|
||||
my $now = &UnixDate("today","%q");
|
||||
if ($c->param("mode") eq "add") {
|
||||
Litmus::Auth::requireProductAdmin("manage_testcases.cgi", $c->param('product'));
|
||||
my %hash = (
|
||||
summary => $c->param('summary'),
|
||||
steps => $c->param('steps') ? $c->param('steps') : '',
|
||||
@ -153,6 +161,7 @@ if ($c->param("delete_testcase_button")) {
|
||||
$testcase_id = $c->param("editform_testcase_id");
|
||||
my $testcase = Litmus::DB::Testcase->retrieve($testcase_id);
|
||||
if ($testcase) {
|
||||
Litmus::Auth::requireProductAdmin("manage_testcases.cgi", $testcase->product());
|
||||
$testcase->summary($c->param('summary'));
|
||||
$testcase->steps($c->param('steps') ? $c->param('steps') : '');
|
||||
$testcase->expected_results($c->param('results') ? $c->param('results') : '');
|
||||
@ -198,6 +207,60 @@ my $testcases = Litmus::FormWidget->getTestcases(0,'name');
|
||||
|
||||
my $authors = Litmus::FormWidget->getAuthors();
|
||||
|
||||
# only allow the user access to the products they are product admins for
|
||||
my %authorized_products;
|
||||
my @tmp_products;
|
||||
foreach my $b (@{$products}) {
|
||||
my %cur = %{$b};
|
||||
if (Litmus::Auth::getCurrentUser()->isProductAdmin($cur{product_id})) {
|
||||
push(@tmp_products, $b);
|
||||
$authorized_products{$cur{product_id}} = 1;
|
||||
}
|
||||
}
|
||||
$products = \@tmp_products;
|
||||
|
||||
# likewise for branches:
|
||||
my %authorized_branches;
|
||||
my @tmp_branches;
|
||||
foreach my $b (@{$branches}) {
|
||||
my %cur = %{$b};
|
||||
if ($authorized_products{$cur{product_id}}) {
|
||||
push(@tmp_branches, $b);
|
||||
$authorized_branches{$cur{branch_id}} = 1;
|
||||
}
|
||||
}
|
||||
$branches = \@tmp_branches;
|
||||
|
||||
# testgroups
|
||||
my @tmp_testgroups;
|
||||
foreach my $b (@{$testgroups}) {
|
||||
my %cur = %{$b};
|
||||
if ($authorized_products{$cur{product_id}}) {
|
||||
push(@tmp_testgroups, $b);
|
||||
}
|
||||
}
|
||||
$testgroups = \@tmp_testgroups;
|
||||
|
||||
# subgroups
|
||||
my @tmp_subgroups;
|
||||
foreach my $b (@{$subgroups}) {
|
||||
my %cur = %{$b};
|
||||
if ($authorized_products{$cur{product_id}}) {
|
||||
push(@tmp_subgroups, $b);
|
||||
}
|
||||
}
|
||||
$subgroups = \@tmp_subgroups;
|
||||
|
||||
# and, of course, testcases
|
||||
my @tmp_testcases;
|
||||
foreach my $b (@{$testcases}) {
|
||||
my %cur = %{$b};
|
||||
if ($authorized_products{$cur{product_id}}) {
|
||||
push(@tmp_testcases, $b);
|
||||
}
|
||||
}
|
||||
$testcases = \@tmp_testcases;
|
||||
|
||||
my $json = JSON->new(skipinvalid => 1, convblessed => 1);
|
||||
my $products_js = $json->objToJson($products);
|
||||
my $branches_js = $json->objToJson($branches);
|
||||
|
||||
@ -44,7 +44,8 @@ use JSON;
|
||||
use Time::Piece::MySQL;
|
||||
|
||||
Litmus->init();
|
||||
Litmus::Auth::requireAdmin("manage_testdays.cgi");
|
||||
Litmus::Auth::requireRunDayAdmin("manage_testdays.cgi");
|
||||
Litmus::Auth::requireProductAdmin("manage_testdays.cgi");
|
||||
|
||||
my $c = Litmus->cgi();
|
||||
print $c->header();
|
||||
@ -54,6 +55,7 @@ my $status;
|
||||
my $rv;
|
||||
my $rebuild_cache = 0;
|
||||
my $defaults;
|
||||
my $warning;
|
||||
|
||||
if ($c->param) {
|
||||
# Process testday changes.
|
||||
@ -62,6 +64,7 @@ if ($c->param) {
|
||||
my $testday_id = $c->param("testday_id");
|
||||
my $testday = Litmus::DB::TestDay->retrieve($testday_id);
|
||||
if ($testday) {
|
||||
Litmus::Auth::requireProductAdmin("manage_testdays.cgi", $testday->product());
|
||||
$rv = $testday->delete;
|
||||
if ($rv) {
|
||||
$status = "success";
|
||||
@ -82,7 +85,10 @@ if ($c->param) {
|
||||
start_timestamp => $c->param('edit_testday_form_start_timestamp'),
|
||||
finish_timestamp => $c->param('edit_testday_form_finish_timestamp'),
|
||||
);
|
||||
|
||||
|
||||
if ($c->param('product')) {
|
||||
Litmus::Auth::requireProductAdmin("manage_testdays.cgi", $c->param('product'));
|
||||
$hash{product_id} = $c->param('product');
|
||||
}
|
||||
if ($c->param('branch')) {
|
||||
@ -103,6 +109,15 @@ if ($c->param) {
|
||||
if ($new_testday) {
|
||||
$status = "success";
|
||||
$message = "Testday added successfully. New testday ID# is " . $new_testday->testday_id;
|
||||
|
||||
|
||||
# search for other testdays that overlap this one and let the user know about them:
|
||||
my @runs = Litmus::DB::TestRun->search_daterange($hash{start_timestamp},
|
||||
$hash{finish_timestamp});
|
||||
if (@runs) {
|
||||
$warning = 1;
|
||||
}
|
||||
|
||||
$defaults->{'testday_id'} = $new_testday->testday_id;
|
||||
$rebuild_cache=1;
|
||||
} else {
|
||||
@ -113,10 +128,12 @@ if ($c->param) {
|
||||
my $testday_id = $c->param("edit_testday_form_testday_id");
|
||||
my $testday = Litmus::DB::TestDay->retrieve($testday_id);
|
||||
if ($testday) {
|
||||
Litmus::Auth::requireProductAdmin("manage_testdays.cgi", $testday->product());
|
||||
$testday->description($c->param('edit_testday_form_desc'));
|
||||
$testday->start_timestamp($c->param('edit_testday_form_start_timestamp'));
|
||||
$testday->finish_timestamp($c->param('edit_testday_form_finish_timestamp'));
|
||||
if ($c->param('product')) {
|
||||
Litmus::Auth::requireProductAdmin("manage_testdays.cgi", $c->param('product'));
|
||||
$testday->product_id($c->param('product'));
|
||||
}
|
||||
if ($c->param('branch')) {
|
||||
@ -172,7 +189,8 @@ my $vars = {
|
||||
products => $products,
|
||||
branches => $branches,
|
||||
testdays => $testdays,
|
||||
locales => $locales,
|
||||
locales => $locales,
|
||||
warning => $warning,
|
||||
};
|
||||
|
||||
$vars->{'products_js'} = $products_js;
|
||||
|
||||
@ -71,7 +71,7 @@ if ($c->param("searchTestgroupList")) {
|
||||
|
||||
# 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');
|
||||
Litmus::Auth::requireProductAdmin('manage_testgroups.cgi');
|
||||
|
||||
if ($c->param("testgroup_id")) {
|
||||
$testgroup_id = $c->param("testgroup_id");
|
||||
@ -81,6 +81,7 @@ my $defaults;
|
||||
if ($c->param("delete_testgroup_button")) {
|
||||
my $testgroup = Litmus::DB::Testgroup->retrieve($testgroup_id);
|
||||
if ($testgroup) {
|
||||
Litmus::Auth::requireProductAdmin("manage_testgroups.cgi", $testgroup->product());
|
||||
$rv = $testgroup->delete_with_refs();
|
||||
if ($rv) {
|
||||
$status = "success";
|
||||
@ -95,6 +96,7 @@ if ($c->param("delete_testgroup_button")) {
|
||||
}
|
||||
} elsif ($c->param("clone_testgroup_button")) {
|
||||
my $testgroup = Litmus::DB::Testgroup->retrieve($testgroup_id);
|
||||
Litmus::Auth::requireProductAdmin("manage_testgroups.cgi", $testgroup->product());
|
||||
my $new_testgroup = $testgroup->clone;
|
||||
if ($new_testgroup) {
|
||||
$status = "success";
|
||||
@ -109,6 +111,7 @@ if ($c->param("delete_testgroup_button")) {
|
||||
requireField('branch', $c->param('branch'));
|
||||
my $enabled = $c->param('enabled') ? 1 : 0;
|
||||
if ($c->param("mode") eq "add") {
|
||||
Litmus::Auth::requireProductAdmin("manage_testgroups.cgi", $c->param('product'));
|
||||
my %hash = (
|
||||
name => $c->param('name'),
|
||||
product_id => $c->param('product'),
|
||||
@ -133,6 +136,7 @@ if ($c->param("delete_testgroup_button")) {
|
||||
$testgroup_id = $c->param("editform_testgroup_id");
|
||||
my $testgroup = Litmus::DB::Testgroup->retrieve($testgroup_id);
|
||||
if ($testgroup) {
|
||||
Litmus::Auth::requireProductAdmin("manage_testgroups.cgi", $testgroup->product());
|
||||
$testgroup->product_id($c->param('product'));
|
||||
$testgroup->branch_id($c->param('branch'));
|
||||
$testgroup->enabled($enabled);
|
||||
@ -170,6 +174,41 @@ my $branches = Litmus::FormWidget->getBranches();
|
||||
my $testgroups = Litmus::FormWidget->getTestgroups;
|
||||
my $subgroups = Litmus::FormWidget->getSubgroups(0,'name');
|
||||
|
||||
# only allow the user access to the products they are product admins for
|
||||
my %authorized_products;
|
||||
my @tmp_products;
|
||||
foreach my $b (@{$products}) {
|
||||
my %cur = %{$b};
|
||||
if (Litmus::Auth::getCurrentUser()->isProductAdmin($cur{product_id})) {
|
||||
push(@tmp_products, $b);
|
||||
$authorized_products{$cur{product_id}} = 1;
|
||||
}
|
||||
}
|
||||
$products = \@tmp_products;
|
||||
|
||||
# likewise for branches:
|
||||
my %authorized_branches;
|
||||
my @tmp_branches;
|
||||
foreach my $b (@{$branches}) {
|
||||
my %cur = %{$b};
|
||||
if ($authorized_products{$cur{product_id}}) {
|
||||
push(@tmp_branches, $b);
|
||||
$authorized_branches{$cur{branch_id}} = 1;
|
||||
}
|
||||
}
|
||||
$branches = \@tmp_branches;
|
||||
|
||||
# and of course limit the testgroups
|
||||
my @tmp_testgroups;
|
||||
foreach my $b (@{$testgroups}) {
|
||||
my %cur = %{$b};
|
||||
if ($authorized_products{$cur{product_id}}) {
|
||||
push(@tmp_testgroups, $b);
|
||||
}
|
||||
}
|
||||
$testgroups = \@tmp_testgroups;
|
||||
|
||||
|
||||
my $json = JSON->new(skipinvalid => 1, convblessed => 1);
|
||||
my $products_js = $json->objToJson($products);
|
||||
my $branches_js = $json->objToJson($branches);
|
||||
|
||||
@ -57,6 +57,8 @@ our \$db_pass = "";
|
||||
our \$user_cookiename = "litmus_login";
|
||||
our \$sysconfig_cookiename = "litmustestingconfiguration";
|
||||
|
||||
our \$sendmail_path = "/usr/sbin/sendmail";
|
||||
|
||||
our \$tr_host = "";
|
||||
our \$tr_name = "";
|
||||
our \$tr_user = "";
|
||||
@ -131,7 +133,7 @@ if ($reset_db) {
|
||||
# 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
|
||||
# NOTE: anything changed here must also be added to schema.pl for new
|
||||
# installations
|
||||
use Litmus::DBTools;
|
||||
my $dbtool = Litmus::DBTools->new($dbh);
|
||||
@ -256,23 +258,20 @@ $dbtool->AddKey("test_runs", 'version (version)', '');
|
||||
$dbtool->AddField("test_run_testgroups", "sort_order", "smallint(6) not null default '1'");
|
||||
$dbtool->AddKey("test_run_testgroups", 'sort_order (sort_order)', '');
|
||||
|
||||
# zll: upgrade to new-world group permission system
|
||||
# do this in a separate package to avoid namespace polution if we're
|
||||
# creating the intial db
|
||||
$dbtool->RenameField("users", "is_admin", "is_admin_old");
|
||||
package CreateAdminGroups;
|
||||
require 'Litmus/DB/SecurityGroup.pm';
|
||||
Litmus::DB::SecurityGroup->import();
|
||||
Litmus::DB::SecurityGroup->upgradeGroups();
|
||||
$dbtool->DropField("users", "is_admin_old");
|
||||
|
||||
package main;
|
||||
|
||||
|
||||
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;
|
||||
* any appropriate scripts in the migration/ subdir;
|
||||
|
||||
EOS
|
||||
|
||||
# javascript cache
|
||||
print "Rebuilding JS cache...";
|
||||
|
||||
@ -389,3 +389,30 @@ $table{users} =
|
||||
index(is_admin),
|
||||
index contact_info (email, realname, irc_nickname),
|
||||
fulltext index contact_info_fulltext (email, realname, irc_nickname)';
|
||||
|
||||
$table{security_groups} =
|
||||
'group_id mediumint not null primary key auto_increment,
|
||||
name varchar(255) not null,
|
||||
description varchar(255) not null,
|
||||
grouptype tinyint not null,
|
||||
isactive tinyint not null default 1,
|
||||
|
||||
unique index(name)';
|
||||
|
||||
$table{user_group_map} =
|
||||
'user_id int(11) not null,
|
||||
group_id mediumint not null,
|
||||
|
||||
unique(user_id, group_id)';
|
||||
|
||||
$table{group_product_map} =
|
||||
'group_id mediumint not null,
|
||||
product_id tinyint(4) not null,
|
||||
|
||||
unique(group_id, product_id)';
|
||||
|
||||
$table{password_resets} =
|
||||
'user_id int(11) not null,
|
||||
session_id int(11) not null,
|
||||
|
||||
index(user_id, session_id)';
|
||||
@ -41,9 +41,20 @@ var testgroups=[% testgroups_js %];
|
||||
|
||||
<div id="content">
|
||||
|
||||
[% INCLUDE admin/form_widgets/update_products.tmpl %]
|
||||
[% INCLUDE admin/form_widgets/update_platforms.tmpl %]
|
||||
[% INCLUDE admin/form_widgets/update_opsyses.tmpl %]
|
||||
[% IF defaultemail.isSuperUser %]
|
||||
[% INCLUDE admin/form_widgets/update_products.tmpl %]
|
||||
[% INCLUDE admin/form_widgets/update_platforms.tmpl %]
|
||||
[% INCLUDE admin/form_widgets/update_opsyses.tmpl %]
|
||||
[% END %]
|
||||
|
||||
[% IF ! defaultemail.isSuperUser %]
|
||||
<div class="login_important">
|
||||
Note: as you are not a Litmus super-administrator, you will only be
|
||||
permitted to edit branches. To manage products, platforms, or operating
|
||||
systems, please contact an administrator.
|
||||
</div>
|
||||
[% END %]
|
||||
|
||||
[% INCLUDE admin/form_widgets/update_branches.tmpl %]
|
||||
|
||||
</div> <!--END content-->
|
||||
|
||||
@ -20,6 +20,7 @@
|
||||
|
||||
[%# INTERFACE:
|
||||
# $user - the user object to edit
|
||||
# @groups - array of groups available on the system (required only for admins)
|
||||
#%]
|
||||
|
||||
[% includeselects=1 %]
|
||||
@ -78,11 +79,6 @@ function checkFormContents(f) {
|
||||
<td><input name="enabled" type="checkbox" value="1"
|
||||
[% IF user.enabled %] checked [% END %] /></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="headerleft">Is An Admin?</td>
|
||||
<td><input name="is_admin" type="checkbox" value="1"
|
||||
[% IF user.is_admin %] checked [% END %] /></td>
|
||||
</tr>
|
||||
[% END %]
|
||||
|
||||
<tr>
|
||||
@ -103,6 +99,26 @@ function checkFormContents(f) {
|
||||
<td class="headerleft">Confirm New Password:</td>
|
||||
<td><input name="edit_confirm_password" type="password" size="30" value="" /></td>
|
||||
</tr>
|
||||
|
||||
[% IF show_admin %]
|
||||
<tr>
|
||||
<td colspan="3"><hr/></td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td class="headerleft">Group Memberships:</td>
|
||||
<td>
|
||||
<table class="manage">
|
||||
[% FOREACH group=groups %]
|
||||
<tr>
|
||||
<td><input name="group_[%group.id | html %]" type="checkbox" value="1" [% IF user.inGroup(group) %] checked [%END%]></td>
|
||||
<td>[% group.name FILTER html %]</td>
|
||||
</tr>
|
||||
[% END %]
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
[% END %]
|
||||
|
||||
|
||||
[% IF ! show_admin %]
|
||||
|
||||
@ -19,7 +19,7 @@
|
||||
#%]
|
||||
|
||||
[%# INTERFACE:
|
||||
#
|
||||
# @groups - all valid security groups
|
||||
#%]
|
||||
|
||||
[% INCLUDE global/html_header.tmpl js_files=['js/SelectBoxes.js','js/FormValidation.js'] title='Edit Users' %]
|
||||
@ -34,7 +34,7 @@
|
||||
|
||||
<div class="section-full">
|
||||
|
||||
[% INCLUDE admin/edit_users/searchform.html.tmpl %]
|
||||
[% INCLUDE admin/edit_users/searchform.html.tmpl groups=groups %]
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
@ -19,14 +19,25 @@
|
||||
#%]
|
||||
|
||||
[%# INTERFACE:
|
||||
#
|
||||
# @groups - all valid security groups
|
||||
#%]
|
||||
|
||||
<p>You may search by email address, real name, or irc nickname.</p>
|
||||
<p>You may search by email address, real name, irc nickname, and group membership.</p>
|
||||
|
||||
<form action="edit_users.cgi" method="get" name="form" id="form">
|
||||
List users matching
|
||||
<input name="search_string" size="35" value="[% IF search_string %][% search_string | html %][% ELSE %][% user.email %][% END %]"/>
|
||||
<input name="search_string" size="35" value="[% IF search_string %][% search_string | html %][% END %]"/>
|
||||
<br /><br />
|
||||
And belonging to group(s):
|
||||
<table class="manage">
|
||||
[% FOREACH group=groups %]
|
||||
[% id = group.group_id %]
|
||||
<tr>
|
||||
<td><input name="group_[%group.id | html %]" type="checkbox" value="1" [% IF checked.$id %] checked [%END%]></td>
|
||||
<td>[% group.name FILTER html %]</td>
|
||||
</tr>
|
||||
[% END %]
|
||||
</table>
|
||||
<input type="submit" name="submit" value="Search" />
|
||||
</form>
|
||||
|
||||
|
||||
@ -10,7 +10,7 @@
|
||||
<table border="0" cellspacing="0" cellpadding="5">
|
||||
<tr>
|
||||
<td>
|
||||
[% INCLUDE form_widgets/select_testday_id.tmpl name="testday_id" placeholder=1 size=5 show_name=1 onchange="loadTestday();" %]
|
||||
[% INCLUDE form_widgets/select_testday_id.tmpl name="testday_id" placeholder=1 size=10 show_name=1 onchange="loadTestday();" %]
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
|
||||
@ -119,7 +119,11 @@ if (em.selectedIndex >= 0) {
|
||||
enableForm('edit_test_run_form');
|
||||
} else {
|
||||
disableForm('edit_test_run_form');
|
||||
changeProduct();
|
||||
}
|
||||
var suffix='_filter';
|
||||
changeProduct();filterList();
|
||||
|
||||
</script>
|
||||
|
||||
[% INCLUDE global/litmus_footer.tmpl %]
|
||||
|
||||
@ -41,6 +41,18 @@ var testgroups=[% testgroups_js %];
|
||||
|
||||
<div id="content">
|
||||
|
||||
[% IF warning %]
|
||||
<div class="error">
|
||||
<h1 class="errorHeading">Warning: Testday Conflict Detected</h1>
|
||||
<h4>
|
||||
Your recently created testday has dates that overlap one or
|
||||
more existing testdays. You should check for conflicts and coordinate with
|
||||
the administrators of the other testdays to ensure that the events are
|
||||
compatible.
|
||||
</h4>
|
||||
</div>
|
||||
[% END %]
|
||||
|
||||
[% INCLUDE admin/form_widgets/update_testdays.tmpl %]
|
||||
|
||||
</div> <!--END content-->
|
||||
|
||||
@ -72,6 +72,14 @@ function checkNewAccountFormContents(f) {
|
||||
comparePasswords(f.password,f.password_confirm)
|
||||
);
|
||||
}
|
||||
|
||||
function forgotPasswordForm(f) {
|
||||
document.getElementById('forgot_email').value =
|
||||
document.getElementById('login_email').value;
|
||||
return (
|
||||
checkEmail(f.email)
|
||||
);
|
||||
}
|
||||
</script>
|
||||
|
||||
<div id="page">
|
||||
@ -100,14 +108,20 @@ function checkNewAccountFormContents(f) {
|
||||
<table border=0>
|
||||
<tr>
|
||||
<td>Email:</td>
|
||||
<td><input name="email" type="text" size="25"></td>
|
||||
<td><input name="email" type="text" size="25" id="login_email"></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Password:</td>
|
||||
<td><input name="password" type="password" size="25"></td>
|
||||
</tr>
|
||||
</table>
|
||||
<br /><input type="submit" name="Submit" value="Login">
|
||||
<br />
|
||||
<input type="submit" name="Submit" value="Login"> <br /><br />
|
||||
</form>
|
||||
<form name="litmus_forgot_password" action="[% return_to | none %]" method="post" onSubmit="return forgotPasswordForm(this);">
|
||||
<input name="email" id="forgot_email" type="hidden">
|
||||
<input name="login_type" type="hidden" value="forgot_password">
|
||||
<input type="submit" name="forgot" value="Forgot Password">
|
||||
</form>
|
||||
</div>
|
||||
|
||||
|
||||
@ -0,0 +1,61 @@
|
||||
[%# ***** 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) 2007
|
||||
# the Initial Developer. All Rights Reserved.
|
||||
#
|
||||
# Contributor(s):
|
||||
# Zach Lipton <zach@zachlipton.com>
|
||||
#
|
||||
# ***** END LICENSE BLOCK *****
|
||||
#%]
|
||||
|
||||
[%# INTERFACE:
|
||||
# $user - the user to reset a password for
|
||||
#%]
|
||||
|
||||
[% INCLUDE global/html_header.tmpl %]
|
||||
[% INCLUDE global/litmus_header.tmpl %]
|
||||
|
||||
|
||||
<div id="page">
|
||||
|
||||
[% INCLUDE sidebar/sidebar.tmpl %]
|
||||
|
||||
<div id="content">
|
||||
|
||||
<h1 class="firstHeading">[% title | html %]</h1>
|
||||
|
||||
<div class="section-full">
|
||||
<div class="section-content">
|
||||
<div class="login_info">
|
||||
<h3>
|
||||
An email message has been sent to your registered email address.
|
||||
When you receive this message, please follow the enclosed link to
|
||||
reset your password.
|
||||
</h3>
|
||||
|
||||
If you need assistance with your login, please contact an operator in <a href="http://irc.mozilla.org/">irc.mozilla.org</a>, channel #qa.
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div> <!--END content-->
|
||||
|
||||
</div> <!--END page-->
|
||||
|
||||
[% INCLUDE global/html_footer.tmpl %]
|
||||
@ -0,0 +1,18 @@
|
||||
To: [% user.email %]
|
||||
|
||||
From: Litmus <litmus-daemon@litmus.mozilla.org>
|
||||
Subject: Litmus Password Reset
|
||||
|
||||
You, or someone claiming to be you, recently visited Litmus and asked
|
||||
to reset the password for the account owned by [% user.email %].
|
||||
|
||||
To reset your password, please click the following link:
|
||||
http://litmus.mozilla.org/login.cgi?resetPassword=[%token%]
|
||||
|
||||
(If you are having trouble, try copying and pasting the link into the Address
|
||||
Bar of your web browser.)
|
||||
|
||||
Thank you for using Litmus,
|
||||
|
||||
The Mozilla QA Team
|
||||
|
||||
@ -0,0 +1,91 @@
|
||||
[%# ***** 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) 2007
|
||||
# the Initial Developer. All Rights Reserved.
|
||||
#
|
||||
# Contributor(s):
|
||||
# Zach Lipton <zach@zachlipton.com>
|
||||
#
|
||||
# ***** END LICENSE BLOCK *****
|
||||
#%]
|
||||
|
||||
[%# INTERFACE:
|
||||
# $user - the user to reset a password for
|
||||
#%]
|
||||
|
||||
[% INCLUDE global/html_header.tmpl js_files = ['js/FormValidation.js'] %]
|
||||
[% INCLUDE global/litmus_header.tmpl %]
|
||||
|
||||
<script type="text/javascript">
|
||||
function checkForm(f) {
|
||||
return (comparePasswords(f.password,f.password_confirm));
|
||||
}
|
||||
</script>
|
||||
|
||||
|
||||
<div id="page">
|
||||
|
||||
[% INCLUDE sidebar/sidebar.tmpl %]
|
||||
|
||||
<div id="content">
|
||||
|
||||
<h1 class="firstHeading">[% title | html %]</h1>
|
||||
|
||||
<div class="section-full">
|
||||
<div class="section-content">
|
||||
<div class="login_info">
|
||||
<h3>
|
||||
Changing password for user: [%user.email | html%].
|
||||
</h3>
|
||||
<h3>
|
||||
Choose a new password below:
|
||||
</h3>
|
||||
</div>
|
||||
<div class="login_form" style="height: 100%; padding:15px;">
|
||||
<form name="reset_password" action="login.cgi" method="post" onSubmit="return checkForm(this);">
|
||||
<input name="login_type" type="hidden" value="doResetPassword">
|
||||
<input name="user" type="hidden" value="[% user.user_id | html %]">
|
||||
<input name="token" type="hidden" value="[% token | html %]">
|
||||
<table cellpadding="0" width="100%" border=0>
|
||||
<tr>
|
||||
<td>New Password:</td>
|
||||
<td><input name="password" type="password" size="25"></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Confirm Password:</td>
|
||||
<td><input name="password_confirm" type="password" size="25"></td>
|
||||
</tr>
|
||||
<tr height="10px">
|
||||
</tr>
|
||||
<tr>
|
||||
<td colspan="2"><input type="submit" name="Submit" value="Reset Password"></td>
|
||||
</tr>
|
||||
</table>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<br />
|
||||
If you need assistance with your login, please contact an operator in <a href="http://irc.mozilla.org/">irc.mozilla.org</a>, channel #qa.
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div> <!--END content-->
|
||||
|
||||
</div> <!--END page-->
|
||||
|
||||
[% INCLUDE global/html_footer.tmpl %]
|
||||
@ -258,10 +258,12 @@ Admin-specific limiting criteria go here. These criteria are not available to re
|
||||
<tr>
|
||||
<td colspan="2" class="heading">Display only results:</td>
|
||||
</tr>
|
||||
<!--
|
||||
<tr>
|
||||
<td class="heading"> From Trusted Sources:</td>
|
||||
<td><input type="radio" id="trusted_only" name="trusted_only" value="1" /> Trusted <input type="radio" id="trusted_only" name="trusted_only" value="0E0" /> Untrusted <input type="radio" id="trusted_only" name="trusted_only" value="all" checked /> All</td>
|
||||
</tr>
|
||||
-->
|
||||
<tr>
|
||||
<td class="heading"> By <a class='help' name="showVettingHelpText" onclick="toggleHelp(vettingHelpTitle,vettingHelpText);">Vetting Status: <img class="inline" src="images/info.png" alt="What is vetting?" /></a></td>
|
||||
<td><input type="radio" id="vetted_only" name="vetted_only" value="1" /> Vetted <input type="radio" id="vetted_only" name="vetted_only" value="0E0" /> Not Vetted <input type="radio" id="vetted_only" name="vetted_only" value="all" checked /> All</td>
|
||||
|
||||
@ -1,17 +1,23 @@
|
||||
[% IF show_admin==1 %]
|
||||
[% IF defaultemail && defaultemail.isInAdminGroup() %]
|
||||
<div class="pagetools">
|
||||
<div>
|
||||
<h3>Admin</h3>
|
||||
<ul>
|
||||
[% IF defaultemail.isRunDayAdmin %]
|
||||
<li><a href="manage_test_runs.cgi">Manage Test Runs</a></li>
|
||||
[% END %]
|
||||
<hr/>
|
||||
<li><a href="manage_testcases.cgi">Manage Testcases</a></li>
|
||||
<li><a href="manage_subgroups.cgi">Manage Subgroups</a></li>
|
||||
<li><a href="manage_testgroups.cgi">Manage Testgroups</a></li>
|
||||
<hr/>
|
||||
<li><a href="manage_categories.cgi">Manage Categories</a></li>
|
||||
<li><a href="manage_testdays.cgi">Manage Testdays</a></li>
|
||||
<li><a href="edit_users.cgi">Manage Users</a></li>
|
||||
[% IF defaultemail.isRunDayAdmin %]
|
||||
<li><a href="manage_testdays.cgi">Manage Testdays</a></li>
|
||||
[% END %]
|
||||
[% IF defaultemail.isSuperUser %]
|
||||
<li><a href="edit_users.cgi">Manage Users</a></li>
|
||||
[% END %]
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -70,7 +70,7 @@
|
||||
<td><b>Regression Bug ID #:</b></td>
|
||||
<td id="regression_bug_id_display[% IF ! show_edit %]_[% testcase.regression_bug_id | html %][% END %]">[% IF testcase.regression_bug_id %]<script>document.write('<a href="' + generateBugLink([% testcase.regression_bug_id %]) + '">[% testcase.regression_bug_id | html %]</a>');</script>[% ELSE %]None specified[% END %]</td>
|
||||
</tr>
|
||||
[% IF show_admin %]
|
||||
[% IF show_edit %]
|
||||
<tr>
|
||||
<td><b>Enabled?</b></td>
|
||||
<td><input id="enabled_display" name="enabled_display" type="checkbox" value="1" [% IF testcase.enabled %] checked[% END %] disabled></td>
|
||||
|
||||
@ -71,7 +71,7 @@
|
||||
<div id="finish_timestamp_text[% IF ! show_edit %]_[% test_run.test_run_id | html %][% END %]">[% test_run.finish_timestamp | html %]</div>
|
||||
</td>
|
||||
</tr>
|
||||
[% IF show_admin %]
|
||||
[% IF show_edit %]
|
||||
<tr>
|
||||
<td><b>Enabled?</b></td>
|
||||
<td><input id="enabled_display" name="enabled_display" type="checkbox" value="1" [% IF test_run.enabled %] checked[% END %] disabled></td>
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user