[smarcet] - initial commit

This commit is contained in:
Sebastian Marcet 2014-10-31 16:21:41 -03:00
commit c09eca8cc4
3357 changed files with 465405 additions and 0 deletions

46
.gitignore vendored Normal file
View File

@ -0,0 +1,46 @@
#assets
!assets/error-404.html
!assets/error-500.html
assets/*
sortablegridfield
framework
colorpicker
cms
translatable
vendor/
/openstack-marketing-portal/*
/blog/*
/cache/*
.htaccess
debug.log
openstack/_live-config.php
_ss_environment.php
simplepie/cache/*
silverstripe-cache/*
silverstripe-cache/
silverstripe-cache
/.buildpath
/.project
# PDT-specific
.buildpath
# Locally stored "Eclipse launch configurations"
*.launch
.settings/
.idea/
#composer
composer.lock
composer.phar
backup_scripts/cron-backup-config.php
logs
feeds/cache
logs/*
sapphire/thirdparty/htmlpurifier-4.4.0/library/HTMLPurifier/DefinitionCache/Serializer/HTML/
elections/input
blog

31
ICLA/_config.php Normal file
View File

@ -0,0 +1,31 @@
<?php
/**
* Copyright 2014 Openstack.org
* Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
**/
//decorators
Object::add_extension('Member', 'ICLAMemberDecorator');
Object::add_extension('Company', 'ICLACompanyDecorator');
Object::add_extension('SangriaPage_Controller', 'SangriaPageICLACompaniesExtension');
Object::add_extension('EditProfilePage_Controller', 'EditProfilePageICLAExtension');
PublisherSubscriberManager::getInstance()->subscribe('new_user_registered', function($member_id){
//check if user has pending invitations
$team_manager = new CCLATeamManager(new SapphireTeamInvitationRepository,
new SapphireCLAMemberRepository,
new TeamInvitationFactory,
new TeamFactory,
new CCLAValidatorFactory,
new SapphireTeamRepository,
SapphireTransactionManager::getInstance());
$team_manager->verifyInvitations($member_id, new TeamInvitationEmailSender(new SapphireTeamInvitationRepository));
});

8
ICLA/_config/routes.yml Normal file
View File

@ -0,0 +1,8 @@
---
Name: iclaroutes
After: 'framework/routes#coreroutes'
---
Director:
rules:
'api/v1/ccla': 'ICLARestfulAPI'
'team-invitations': 'TeamInvitationConfirmation_Controller'

View File

@ -0,0 +1,105 @@
<?php
/**
* Copyright 2014 Openstack.org
* Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
**/
/**
* Class BatchTask
*/
final class BatchTask
extends DataObject
implements IBatchTask {
static $create_table_options = array('MySQLDatabase' => 'ENGINE=InnoDB');
static $db = array(
'Name' => 'Text',
'LastResponse' => 'Text',
'LastRecordIndex' => 'Int',
'LastResponseDate' => 'SS_Datetime',
'TotalRecords' => 'Int',
);
/***
* @return string
*/
public function name()
{
return (string)$this->getField('Name');
}
/***
* @return int
*/
public function lastRecordProcessed()
{
return (int)$this->getField('LastRecordIndex');
}
/**
* @return string
*/
public function lastResponse()
{
return (string)$this->getField('LastResponse');
}
/**
* @return DateTime
*/
public function lastResponseDate()
{
return new DateTime($this->getField('LastResponseDate'));
}
/**
* @return int
*/
public function totalRecords()
{
return (int)$this->getField('TotalRecords');
}
/**
* @param string $response
* @return void
*/
public function updateResponse($response)
{
$this->setField('LastResponse', $response);
}
/**
* @return void
*/
public function updateLastRecord()
{
$last = $this->lastRecordProcessed();
$this->setField('LastRecordIndex', $last+1 );
}
/**
* @return int
*/
public function getIdentifier()
{
return (int)$this->getField('ID');
}
/**
* @param int $total_qty
* @return void
*/
public function initialize($total_qty){
$this->setField('LastRecordIndex', 0 );
$this->setField('TotalRecords', $total_qty );
}
}

View File

@ -0,0 +1,94 @@
<?php
/**
* Copyright 2014 Openstack.org
* Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
**/
/**
* Class ICLACompanyDecorator
*/
class ICLACompanyDecorator
extends DataExtension
{
//Add extra database fields
private static $db = array(
'CCLASigned' => 'Boolean',
'CCLADate' => 'SS_Datetime',
);
private static $defaults = array(
'CCLASigned' => FALSE,
);
private static $has_many = array(
'Teams' => 'Team'
);
/**
* @return void
*/
public function signICLA()
{
$this->owner->setField('CCLASigned',true);
$this->owner->setField('CCLADate', SS_Datetime::now()->Rfc2822());
}
/**
* @return void
*/
public function unsignICLA()
{
$this->owner->setField('CCLASigned',false);
$this->owner->setField('CCLADate', null);
}
/**
* @return bool
*/
public function isICLASigned()
{
return (bool)$this->owner->getField('CCLASigned');
}
/**
* @return Datetime
*/
public function ICLASignedDate()
{
$ss_datetime = $this->owner->getField('CCLADate');
return new DateTime($ss_datetime);
}
/**
* @return int
*/
public function getIdentifier()
{
return (int)$this->owner->getField('ID');
}
/**
* @return ITeam[]
*/
public function Teams()
{
return AssociationFactory::getInstance()->getOne2ManyAssociation($this->owner , 'Teams', new QueryObject)->toArray();
}
public function addTeam(ITeam $team)
{
AssociationFactory::getInstance()->getOne2ManyAssociation($this->owner , 'Teams', new QueryObject)->add($team);
}
}

View File

@ -0,0 +1,158 @@
<?php
/**
* Copyright 2014 Openstack.org
* Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
**/
/**
* Class ICLAMemberDecorator
*/
final class ICLAMemberDecorator
extends DataExtension
implements ICLAMember, PermissionProvider
{
//Add extra database fields
private static $db = array(
'CLASigned' => 'Boolean',
'LastCodeCommit' => 'SS_Datetime',
'GerritID' => 'Text',
);
private static $defaults = array(
'CLASigned' => FALSE,
);
private static $belongs_many_many = array(
'Teams' => 'Team'
);
/**
* @return string
*/
public function getGerritId()
{
return (string)$this->owner->getField('GerritID');
}
/**
* @return DateTime
*/
public function getLastCommitedDate()
{
return new DateTime($this->owner->getField('LastCodeCommit'));
}
/**
* @param int $gerrit_id
* @return void
*/
public function signICLA($gerrit_id)
{
$this->owner->setField('GerritID',$gerrit_id);
$this->owner->setField('CLASigned',true);
}
/**
* @return int
*/
public function getIdentifier()
{
return (int)$this->owner->getField('ID');
}
/**
* @param DateTime $date
* @return void
*/
public function updateLastCommitedDate(DateTime $date)
{
$this->owner->setField('LastCodeCommit', $date->getTimestamp() );
}
function getAdminPermissionSet(array &$res){
$companyId = $_REQUEST["CompanyId"];
if(isset($companyId) && is_numeric($companyId) && $companyId > 0){
// user could be ccla admin of only one company and company must have at least one team set
$ccla_group = Group::get()->filter('Code',ICLAMember::CCLAGroupSlug)->first();
if(!$ccla_group) return;
$query_groups = new SQLQuery();
$query_groups->addSelect("GroupID");
$query_groups->addFrom("Company_Administrators");
$query_groups->addWhere("MemberID = {$this->owner->ID} AND CompanyID <> {$companyId} AND GroupID = {$ccla_group->ID} ");
$groups = $query_groups->execute()->keyedColumn();
$company = Company::get()->byID($companyId);
if(count($groups) === 0 && $company->isICLASigned())
array_push($res, 'CCLA_ADMIN');
}
}
function providePermissions() {
return array(
ICLAMember::CCLAPermissionSlug => array(
'name' => 'CCLA Company Admin',
'category' => 'Company Management',
'help' => 'Allows to manage CCLA Company Members and Teams',
'sort' => 0
),
);
}
/**
* @return bool
*/
function isCCLAAdmin(){
$managed_companies = $this->owner->ManagedCompanies();
foreach($managed_companies as $company){
$groups = $company->getAdminGroupsByMember($this->getIdentifier());
if(is_null($groups) || count($groups)==0) continue;
if( array_key_exists(ICLAMember::CCLAGroupSlug , $groups)){
$company = $this->getManagedCCLACompany();
if(!$company) return false;
return $company->isICLASigned();
}
}
return false;
}
/**
* @return ICLACompany
*/
function getManagedCCLACompany(){
$managed_companies = $this->owner->ManagedCompanies();
foreach($managed_companies as $company){
$groups = $company->getAdminGroupsByMember($this->getIdentifier());
if(is_null($groups) || count($groups)==0) continue;
if( array_key_exists(ICLAMember::CCLAGroupSlug, $groups)){
return $company;
}
}
return false;
}
/**
* @return bool
*/
public function hasSignedCLA()
{
return (bool)$this->owner->getField('CLASigned');
}
}

View File

@ -0,0 +1,166 @@
<?php
/**
* Copyright 2014 Openstack.org
* Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
**/
/**
* Class Team
*/
final class Team
extends DataObject
implements ITeam
{
static $create_table_options = array('MySQLDatabase' => 'ENGINE=InnoDB');
static $db = array(
'Name' => 'Text',
);
static $has_one = array(
'Company' => 'Company',
);
static $has_many = array(
'Invitations' => 'TeamInvitation',
);
static $many_many = array(
'Members' => 'Member',
);
//Administrators Security Groups
static $many_many_extraFields = array(
'Members' => array(
'DateAdded' => "SS_DateTime",
),
);
public static $defaults = array(
"DateAdded" => 'now()',
);
/**
* @return int
*/
public function getIdentifier()
{
return (int)$this->getField('ID');
}
/**
* @return string
*/
public function getName()
{
return (string)$this->getField('Name');
}
/**
* @return ICLAMember[]
*/
public function getMembers()
{
return AssociationFactory::getInstance()->getMany2ManyAssociation($this , 'Members')->toArray();
}
/**
* @param ICLAMember $member
* @return void
*/
public function addMember(ICLAMember $member)
{
AssociationFactory::getInstance()->getMany2ManyAssociation($this , 'Members')->add($member, array('DateAdded'=> SS_Datetime::now()->Rfc2822()));
}
/**
* @param ICLAMember $member
* @return void
*/
public function removeMember(ICLAMember $member)
{
AssociationFactory::getInstance()->getMany2ManyAssociation($this , 'Members')->remove($member);
}
/**
* @return ITeamInvitation[]
*/
public function getInvitations(){
return AssociationFactory::getInstance()->getOne2ManyAssociation($this, 'Invitations')->toArray();
}
/**
* @return ITeamInvitation[]
*/
public function getUnconfirmedInvitations()
{
$query = new QueryObject();
$query->addAddCondition(QueryCriteria::equal('IsConfirmed', 0));
return AssociationFactory::getInstance()->getOne2ManyAssociation($this, 'Invitations' , $query)->toArray();
}
/**
* @return ICLACompany
*/
public function getCompany()
{
return AssociationFactory::getInstance()->getMany2OneAssociation($this, 'Company')->getTarget();
}
/**
* @param ICLAMember $member
* @return bool
*/
public function isInvite(ICLAMember $member)
{
$member_id = $member->getIdentifier();
$res = $this->Invitations(" MemberID = {$member_id} ");
return $res->Count() > 0;
}
/**
* @param ICLAMember $member
* @return bool
*/
public function isMember(ICLAMember $member)
{
$member_id = $member->getIdentifier();
$res = $this->Members(" MemberID = {$member_id} ");
return $res->Count() > 0;
}
/**
* @param ITeamInvitation $invitation
* @return void
*/
public function removeInvitation(ITeamInvitation $invitation){
AssociationFactory::getInstance()->getOne2ManyAssociation($this , 'Invitations')->remove($invitation);
}
/**
* @param string $name
* @return void
*/
public function updateName($name)
{
$this->setField('Name', $name);
}
public function clearMembers(){
AssociationFactory::getInstance()->getMany2ManyAssociation($this , 'Members')->removeAll();
}
public function clearInvitations(){
AssociationFactory::getInstance()->getOne2ManyAssociation($this , 'Invitations')->removeAll();
}
}

View File

@ -0,0 +1,124 @@
<?php
/**
* Copyright 2014 Openstack.org
* Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
**/
/**
* Class TeamInvitation
*/
final class TeamInvitation
extends DataObject
implements ITeamInvitation
{
static $create_table_options = array('MySQLDatabase' => 'ENGINE=InnoDB');
static $db = array(
'Email' => 'Text',
'FirstName' => 'Text',
'LastName' => 'Text',
'ConfirmationHash' => 'Text',
'IsConfirmed' => 'Boolean',
'ConfirmationDate' => 'SS_Datetime',
);
static $has_one = array(
'Team' => 'Team',
'Member' => 'Member',
);
/**
* @return int
*/
public function getIdentifier()
{
return (int)$this->getField('ID');
}
/**
* @return InviteInfoDTO
*/
public function getInviteInfo() {
return new InviteInfoDTO((string)$this->getField('FirstName'), (string)$this->getField('LastName'), (string)$this->getField('Email'));
}
/**
* @return bool
*/
public function isInviteRegisteredAsUser()
{
$member = $this->getMember();
return $member && $member->getIdentifier() > 0 ;
}
/**
* @return ITeam
*/
public function getTeam()
{
return AssociationFactory::getInstance()->getMany2OneAssociation($this, 'Team')->getTarget();
}
public function setTeam(ITeam $team){
AssociationFactory::getInstance()->getMany2OneAssociation($this, 'Team')->setTarget($team);
}
/**
* @return ICLAMember
*/
public function getMember()
{
return AssociationFactory::getInstance()->getMany2OneAssociation($this, 'Member')->getTarget();
}
public function setMember(ICLAMember $member){
AssociationFactory::getInstance()->getMany2OneAssociation($this, 'Member')->setTarget($member);
}
/**
* @return string
*/
public function generateConfirmationToken() {
$generator = new RandomGenerator();
$token = $generator->randomToken();
$hash = self::HashConfirmationToken($token);
$this->setField('ConfirmationHash',$hash);
return $token;
}
/**
* @param string $token
* @return bool
* @throws InvalidHashInvitationException
* @throws InvitationAlreadyConfirmedException
*/
public function doConfirmation($token)
{
$original_hash = $this->getField('ConfirmationHash');
if($this->IsConfirmed) throw new InvitationAlreadyConfirmedException;
if(self::HashConfirmationToken($token) === $original_hash){
$this->IsConfirmed = true;
$this->ConfirmationDate = SS_Datetime::now()->Rfc2822();
return true;
}
throw new InvalidHashInvitationException;
}
public static function HashConfirmationToken($token){
return md5($token);
}
public function updateInvite(ICLAMember $invite)
{
$this->setMember($invite);
}
}

View File

@ -0,0 +1,23 @@
<?php
/**
* Copyright 2014 Openstack.org
* Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
**/
/**
* Class UnauthorizedRestfullAPIException
*/
final class UnauthorizedRestfullAPIException extends Exception {
public function __construct($message){
parent::__construct($message);
}
}

View File

@ -0,0 +1,30 @@
<?php
/**
* Copyright 2014 Openstack.org
* Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
**/
/**
* Class BatchTaskFactory
*/
final class BatchTaskFactory implements IBatchTaskFactory {
/**
* @param string $task_name
* @param int $total_record_qty
* @return IBatchTask
*/
public function buildBatchTask($task_name, $total_record_qty) {
$task = new BatchTask();
$task->Name = $task_name;
$task->initialize($total_record_qty);
return $task;
}
}

View File

@ -0,0 +1,66 @@
<?php
/**
* Copyright 2014 Openstack.org
* Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
**/
/**
* Class CCLAValidatorFactory
*/
final class CCLAValidatorFactory implements ICCLAValidatorFactory {
/**
* @param array $data
* @return IValidator
*/
public function buildValidatorForTeamInvitation(array $data)
{
$rules = array(
'first_name' => 'required|text',
'last_name' => 'required|text',
'email' => 'required|email',
'team_id' => 'required|integer',
'member_id' => 'sometimes|integer',
);
$messages = array(
'first_name.required' => ':attribute is required',
'first_name.text' => ':attribute should be valid text.',
'last_name.required' => ':attribute is required',
'email.email' => ':attribute should be valid email.',
'email.required' => ':attribute is required',
'team_id.required' => ':attribute is required',
'team_id.integer ' => ':attribute should be valid integer.',
'member_id.integer' => ':attribute should be valid integer.',
);
return ValidatorService::make($data, $rules, $messages);
}
/**
* @param array $data
* @return ValidatorService
*/
public function buildValidatorForTeam(array $data){
$rules = array(
'name' => 'required|text',
'company_id' => 'required|integer',
);
$messages = array(
'name.required' => ':attribute is required',
'name.text' => ':attribute should be valid text.',
'company_id.required' => ':attribute is required',
'company_id.integer' => ':attribute should be valid integer.',
);
return ValidatorService::make($data, $rules, $messages);
}
}

View File

@ -0,0 +1,32 @@
<?php
/**
* Copyright 2014 Openstack.org
* Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
**/
/**
* Class TeamFactory
*/
final class TeamFactory implements ITeamFactory {
/**
* @param array $team_data
* @return ITeam
*/
public function buildTeam(array $team_data)
{
$team = new Team();
$team->Name = $team_data['name'];
$team->CompanyID = (int)$team_data['company_id'];
$team->Company = new Company() ;
$team->Company->ID = (int)$team_data['company_id'];
return $team;
}
}

View File

@ -0,0 +1,37 @@
<?php
/**
* Copyright 2014 Openstack.org
* Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
**/
/**
* Class TeamInvitationFactory
*/
final class TeamInvitationFactory implements ITeamInvitationFactory{
/**
* @param InvitationDTO $invitation_dto
* @return ITeamInvitation
*/
public function buildInvitation(InvitationDTO $invitation_dto)
{
$invitation = new TeamInvitation();
$invitation->FirstName = $invitation_dto->getFirstName();
$invitation->LastName = $invitation_dto->getLastName();
$invitation->Email = $invitation_dto->getEmail();
$invitation->setTeam($invitation_dto->getTeam());
$member = $invitation_dto->getMember();
if($member){
$invitation->setMember($member);
}
return $invitation;
}
}

View File

@ -0,0 +1,32 @@
<?php
/**
* Copyright 2014 Openstack.org
* Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
**/
final class SapphireBatchTaskRepository
extends SapphireRepository
implements IBatchTaskRepository{
public function __construct(){
parent::__construct(new BatchTask());
}
/***
* @param string $name
* @return IBatchTask
*/
public function findByName($name)
{
$query = new QueryObject;
$query->addAddCondition(QueryCriteria::equal('Name',$name));
return $this->getBy($query);
}
}

View File

@ -0,0 +1,103 @@
<?php
/**
* Copyright 2014 Openstack.org
* Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
**/
/**
* Class SapphireCLAMemberRepository
*/
final class SapphireCLAMemberRepository
extends SapphireRepository
implements ICLAMemberRepository {
public function __construct(){
$entity = new ICLAMemberDecorator;
$entity->setOwner(new Member);
parent::__construct($entity);
}
/***
* @return int[]
*/
function getAllGerritIds() {
$gerrit_ids = DB::query('SELECT GerritID FROM Member WHERE GerritID IS NOT NULL;');
$res = array();
foreach ($gerrit_ids as $id) {
$gerrit_id = (string) $id['GerritID'];
$res[$gerrit_id] = $gerrit_id;
}
return $res;
}
/**
* @param int $offset
* @param int $limit
* @return ICLAMember[]
*/
function getAllICLAMembers($offset, $limit)
{
$query = new QueryObject;
$query->addAddCondition(QueryCriteria::equal('CLASigned',true));
return $this->getAll($query, $offset, $limit);
}
/**
* @param string $email
* @return ICLAMember
*/
public function findByEmail($email){
$query = new QueryObject;
$query->addAddCondition(QueryCriteria::equal('Email',$email));
return $this->getBy($query);
}
/**
* @param string $email
* @param int $offset
* @param int $limit
* @return array
*/
function getAllIClaMembersByEmail($email, $offset, $limit)
{
$query = new QueryObject;
$query->addAddCondition(QueryCriteria::equal('CLASigned',true));
$query->addAddCondition(QueryCriteria::like('Email',$email));
return $this->getAll($query, $offset, $limit);
}
/**
* @param string $first_name
* @param int $offset
* @param int $limit
* @return array
*/
function getAllIClaMembersByFirstName($first_name, $offset, $limit)
{
$query = new QueryObject;
$query->addAddCondition(QueryCriteria::equal('CLASigned',true));
$query->addAddCondition(QueryCriteria::like('FirstName',$first_name));
return $this->getAll($query, $offset, $limit);
}
/**
* @param string $last_name
* @param int $offset
* @param int $limit
* @return array
*/
function getAllIClaMembersByLastName($last_name, $offset, $limit)
{
$query = new QueryObject;
$query->addAddCondition(QueryCriteria::equal('CLASigned',true));
$query->addAddCondition(QueryCriteria::like('Surname',$last_name));
return $this->getAll($query, $offset, $limit);
}
}

View File

@ -0,0 +1,27 @@
<?php
/**
* Copyright 2014 Openstack.org
* Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
**/
/**
* Class SapphireICLACompanyRepository
*/
final class SapphireICLACompanyRepository
extends SapphireRepository
implements ICLACompanyRepository {
public function __construct(){
$entity = new ICLACompanyDecorator;
$entity->setOwner(new Company);
parent::__construct($entity);
}
}

View File

@ -0,0 +1,75 @@
<?php
/**
* Copyright 2014 Openstack.org
* Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
**/
/**
* Class SapphireTeamInvitationRepository
*/
final class SapphireTeamInvitationRepository
extends SapphireRepository
implements ITeamInvitationRepository
{
public function __construct(){
parent::__construct(new TeamInvitation);
}
/**
* @param string $token
* @return bool
*/
public function existsConfirmationToken($token)
{
$query = new QueryObject;
$query->addAddCondition(QueryCriteria::equal('ConfirmationHash',TeamInvitation::HashConfirmationToken($token)));
return !is_null( $this->getBy($query));
}
/**
* @param string $token
* @return ITeamInvitation
*/
public function findByConfirmationToken($token)
{
$query = new QueryObject;
$query->addAddCondition(QueryCriteria::equal('ConfirmationHash',TeamInvitation::HashConfirmationToken($token)));
return $this->getBy($query);
}
/**
* @param string $email
* @param bool $all
* @return ITeamInvitation[]
*/
public function findByInviteEmail($email, $all = false)
{
$query = new QueryObject;
$query->addAddCondition(QueryCriteria::equal('Email',$email));
if(!$all)
$query->addAddCondition(QueryCriteria::isNull('ConfirmationHash'));
list($res, $size) = $this->getAll($query,0,1000);
return $res;
}
/**
* @param string $email
* @param ITeam $team
* @return ITeamInvitation
*/
public function findByInviteEmailAndTeam($email, ITeam $team){
$query = new QueryObject;
$query->addAddCondition(QueryCriteria::equal('Email',$email));
$query->addAddCondition(QueryCriteria::equal('TeamID',$team->getIdentifier()));
return $this->getBy($query);
}
}

View File

@ -0,0 +1,49 @@
<?php
/**
* Copyright 2014 Openstack.org
* Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
**/
/***
* Class SapphireTeamRepository
*/
final class SapphireTeamRepository extends SapphireRepository
implements ITeamRepository
{
public function __construct(){
parent::__construct(new Team);
}
/**
* @param int $company_id
* @return ITeam[]
*/
public function getByCompany($company_id) {
$query = new QueryObject(new Team);
$query->addAddCondition(QueryCriteria::equal('CompanyID', $company_id));
list($list, $size) = $this->getAll($query, 0, 1000);
return $list;
}
/**
* @param string $name
* @param int $company_id
* @return ITeam
*/
public function getByNameAndCompany($name, $company_id)
{
$query = new QueryObject(new Team);
$query->addAddCondition(QueryCriteria::equal('CompanyID', $company_id));
$query->addAddCondition(QueryCriteria::equal('Name', $name));
return $this->getBy($query);
}
}

View File

@ -0,0 +1,39 @@
<?php
/**
* Copyright 2014 Openstack.org
* Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
**/
/**
* Class AbstractRestfulServiceRequestor
*/
abstract class AbstractRestfulServiceRequestor {
/**
* @param string $url
* @param null|string $user
* @param null|string $password
* @return mixed
*/
protected function doRequest($url, $user = null, $password = null){
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
if(!empty($user) && !empty($password)){
curl_setopt($ch, CURLOPT_HTTPAUTH, CURLAUTH_DIGEST);
curl_setopt($ch, CURLOPT_USERPWD, sprintf("%s:%s", $user, $password));
}
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0);
$response = curl_exec($ch);
curl_close($ch);
return $response;
}
}

View File

@ -0,0 +1,84 @@
<?php
/**
* Copyright 2014 Openstack.org
* Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
**/
/**
* Class GerritAPI
*/
final class GerritAPI
extends AbstractRestfulServiceRequestor
implements IGerritAPI {
/**
* @var string
*/
private $user;
/**
* @var string
*/
private $password;
/**
* @var string
*/
private $domain;
/**
* @param string $domain
* @param string $user
* @param string $password
*/
public function __construct($domain, $user, $password){
$this->domain = $domain;
$this->user = $user;
$this->password = $password;
}
/**
* @param string $group_id
* @return array|mixed
* @throws UnauthorizedRestfullAPIException
*/
public function listAllMembersFromGroup($group_id){
$url = sprintf("%s/a/groups/%s/members", $this->domain, $group_id);
$json = $this->fixGerritJsonResponse($this->doRequest($url, $this->user, $this->password));
if(strtolower($json)==='unauthorized')
throw new UnauthorizedRestfullAPIException($json);
return json_decode($json, true);
}
/**
* @param string $gerrit_user_id
* @return DateTime
*/
public function getUserLastCommit($gerrit_user_id){
$url = sprintf("%s/changes/?q=status:merged+owner:%s&n=1", $this->domain, $gerrit_user_id);
$json = $this->fixGerritJsonResponse($this->doRequest($url));
$response = json_decode($json, true);
if(is_array($response) && count($response) > 0){
$response = $response[0];
$last_committed_date = $response['updated'];
$last_committed_date = explode('.',$last_committed_date);
if(is_array($last_committed_date) && count($last_committed_date) > 0){
return DateTime::createFromFormat('Y-m-d H:i:s', $last_committed_date[0]);
}
}
return null;
}
private function fixGerritJsonResponse($json){
$json = str_replace(")]}'",'',$json);
return $json;
}
}

View File

@ -0,0 +1,68 @@
<?php
/**
* Copyright 2014 Openstack.org
* Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
**/
/**
* Class TeamInvitationEmailSender
*/
final class TeamInvitationEmailSender implements ITeamInvitationSender {
/**
* @var ITeamInvitationRepository
*/
private $team_invitation_repository;
/**
* @param ITeamInvitationRepository $team_invitation_repository
*/
public function __construct(ITeamInvitationRepository $team_invitation_repository){
$this->team_invitation_repository = $team_invitation_repository;
}
/**
* @param ITeamInvitation $invitation
* @return void
*/
public function sendInvitation(ITeamInvitation $invitation) {
$invite_dto = $invitation->getInviteInfo();
$email_to = $invite_dto->getEmail();
//to avoid accidentally send undesired emails....
if(defined('CCLA_DEBUG_EMAIL'))
$email_to = CCLA_DEBUG_EMAIL;
$email = EmailFactory::getInstance()->buildEmail(CCLA_TEAM_INVITATION_EMAIL_FROM, $email_to , "You Have been Invited to Team ".$invitation->getTeam()->getName());
$template_data = array(
'FirstName' => $invite_dto->getFirstName(),
'LastName' => $invite_dto->getLastName(),
'TeamName' => $invitation->getTeam()->getName(),
'CompanyName' => $invitation->getTeam()->getCompany()->Name
);
if($invitation->isInviteRegisteredAsUser()){
$email->setTemplate('TeamInvitation_RegisteredUser');
do{
$token = $invitation->generateConfirmationToken();
} while ($this->team_invitation_repository->existsConfirmationToken($token));
$template_data['ConfirmationLink'] = sprintf('%s/team-invitations/%s/confirm', Director::protocolAndHost(), $token);
}
else{
$email->setTemplate('TeamInvitation_UnRegisteredUser');
$template_data['RegistrationLink'] = sprintf('%s/join/register', Director::protocolAndHost());
}
$email->populateTemplate($template_data);
$email->send();
}
}

View File

@ -0,0 +1,35 @@
<?php
/**
* Copyright 2014 Openstack.org
* Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
**/
/**
* Class PullCLAFromGerritTask
*/
final class PullCLAFromGerritTask extends CliController {
function process(){
set_time_limit(0);
$manager = new ICLAManager (
new GerritAPI(GERRIT_BASE_URL, GERRIT_USER, GERRIT_PASSWORD),
new SapphireBatchTaskRepository,
new SapphireCLAMemberRepository,
new BatchTaskFactory,
SapphireTransactionManager::getInstance()
);
$members_updated = $manager->processICLAGroup(ICLA_GROUP_ID, PULL_ICLA_DATA_FROM_GERRIT_BATCH_SIZE);
echo $members_updated;
}
}

View File

@ -0,0 +1,35 @@
<?php
/**
* Copyright 2014 Openstack.org
* Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
**/
/**
* Class UpdateLastCommittedDateTask
*/
final class UpdateLastCommittedDateTask extends CliController {
function process(){
set_time_limit(0);
$manager = new ICLAManager (
new GerritAPI(GERRIT_BASE_URL, GERRIT_USER, GERRIT_PASSWORD),
new SapphireBatchTaskRepository,
new SapphireCLAMemberRepository,
new BatchTaskFactory,
SapphireTransactionManager::getInstance()
);
$members_updated = $manager->updateLastCommittedDate(PULL_LAST_COMMITTED_DATA_FROM_GERRIT_BATCH_SIZE);
echo $members_updated;
}
}

View File

@ -0,0 +1,335 @@
<?php
/**
* Copyright 2014 Openstack.org
* Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
**/
/**
* Class ICLARestfulAPI
*/
final class ICLARestfulAPI
extends AbstractRestfulJsonApi {
/**
* @var ICLACompanyRepository
*/
private $company_repository;
/**
* @var CCLACompanyService
*/
private $company_manager;
/**
* @var ICLAMemberRepository
*/
private $member_repository;
/**
* @var CCLATeamManager
*/
private $team_manager;
/**
* @var ITeamInvitationRepository
*/
private $invitation_repository;
public function __construct(){
parent::__construct();
$this->company_repository = new SapphireICLACompanyRepository;
$this->member_repository = new SapphireCLAMemberRepository;
$this->invitation_repository = new SapphireTeamInvitationRepository;
$this->company_manager = new CCLACompanyService($this->company_repository, SapphireTransactionManager::getInstance());
$this->team_manager = new CCLATeamManager(
$this->invitation_repository,
$this->member_repository,
new TeamInvitationFactory,
new TeamFactory,
new CCLAValidatorFactory,
new SapphireTeamRepository,
SapphireTransactionManager::getInstance());
//filters...
$this_var = $this;
$this->addBeforeFilter('signCompanyCCLA','check_sign',function ($request) use($this_var){
if(!Permission::check("SANGRIA_ACCESS"))
return $this_var->permissionFailure();
});
$this->addBeforeFilter('unsignCompanyCCLA','check_unsign',function ($request) use($this_var){
if(!Permission::check("SANGRIA_ACCESS"))
return $this_var->permissionFailure();
});
$this->addBeforeFilter('searchCCLAMembers','check_members_search',function() use($this_var){
return $this_var->checkCCLAdmin();
});
$this->addBeforeFilter('addInvitation','check_add_invitation',function() use($this_var){
return $this_var->checkCCLAdmin();
});
$this->addBeforeFilter('deleteInvitation','check_delete_invitation',function() use($this_var){
return $this_var->checkCCLAdmin();
});
}
/**
* @return SS_HTTPResponse
*/
public function checkCCLAdmin(){
$member = Member::currentUser();
if(!$member) return $this->permissionFailure();
if(!$member->isCCLAAdmin()) return $this->permissionFailure();
}
const ApiPrefix = 'api/v1/ccla';
protected function isApiCall()
{
$request = $this->getRequest();
if(is_null($request)) return false;
return strpos(strtolower($request->getURL()),self::ApiPrefix) !== false;
}
/**
* @return bool
*/
protected function authorize()
{
return true;
return;
}
/**
* @var array
*/
static $url_handlers = array(
'PUT companies/$COMPANY_ID/sign' => 'signCompanyCCLA',
'DELETE companies/$COMPANY_ID/sign' => 'unsignCompanyCCLA',
'GET members' => 'searchCCLAMembers',
'POST invitations' => 'addInvitation',
'DELETE teams/$TEAM_ID/memberships/$ID/$STATUS' => 'resignMembership',
'POST teams' => 'addTeam',
'DELETE teams/$TEAM_ID' => 'deleteTeam',
'PUT teams/$TEAM_ID' => 'updateTeamName',
);
/**
* @var array
*/
static $allowed_actions = array(
'signCompanyCCLA',
'unsignCompanyCCLA',
'searchCCLAMembers',
'addInvitation',
'resignMembership',
'confirmTeamInvitation',
'addTeam',
'deleteTeam',
'updateTeamName',
);
public function addInvitation(){
$data = $this->getJsonRequest();
try{
$entity = $this->team_manager->sendInvitation($data, new TeamInvitationEmailSender($this->invitation_repository));
return $this->created($entity->getIdentifier());
}
catch(NotFoundEntityException $ex1){
SS_Log::log($ex1,SS_Log::NOTICE);
return $this->notFound($ex1->getMessage());
}
catch(EntityValidationException $ex2){
SS_Log::log($ex2,SS_Log::NOTICE);
return $this->validationError($ex2->getMessages());
}
catch(TeamMemberAlreadyExistsException $ex3){
SS_Log::log($ex3,SS_Log::NOTICE);
return $this->validationError(array( array('attribute'=>'error', 'message' => $ex3->getMessage())));
}
catch(MemberNotSignedCCLAException $ex4){
SS_Log::log($ex4,SS_Log::NOTICE);
return $this->validationError(array( array('attribute'=>'error', 'message' => $ex4->getMessage())));
}
catch(Exception $ex){
SS_Log::log($ex,SS_Log::ERR);
return $this->serverError();
}
if (!$data) return $this->serverError();
}
public function resignMembership(){
$id = (int)$this->request->param('ID');
$team_id = (int)$this->request->param('TEAM_ID');
$status = $this->request->param('STATUS');
try{
$this->team_manager->resignMembership($team_id, $id, $status);
return $this->deleted();
}
catch(NotFoundEntityException $ex1){
SS_Log::log($ex1,SS_Log::NOTICE);
return $this->notFound($ex1->getMessage());
}
catch(Exception $ex){
SS_Log::log($ex,SS_Log::ERR);
return $this->serverError();
}
}
public function signCompanyCCLA(){
$company_id = (int)$this->request->param('COMPANY_ID');
try{
$res = $this->company_manager->signCCLA($company_id);
return $this->ok(array('sign_date' => $res));
}
catch(NotFoundEntityException $ex1){
SS_Log::log($ex1,SS_Log::NOTICE);
return $this->notFound($ex1->getMessage());
}
catch(Exception $ex){
SS_Log::log($ex,SS_Log::ERR);
return $this->serverError();
}
}
public function unsignCompanyCCLA(){
$company_id = (int)$this->request->param('COMPANY_ID');
try{
$this->company_manager->unsignCCLA($company_id);
return $this->ok();
}
catch(NotFoundEntityException $ex1){
SS_Log::log($ex1,SS_Log::NOTICE);
return $this->notFound($ex1->getMessage());
}
catch(Exception $ex){
SS_Log::log($ex,SS_Log::ERR);
return $this->serverError();
}
}
public function searchCCLAMembers(){
$params = $this->request->getVars();
$field = $params['field'];
$term = $params['term'];
try{
$res = array();
switch($field){
case 'email':
list($list, $size) = $this->member_repository->getAllIClaMembersByEmail($term,0,25);
break;
case 'fname':
list($list, $size) = $this->member_repository->getAllIClaMembersByFirstName($term,0,25);
break;
case 'lname':
list($list, $size) = $this->member_repository->getAllIClaMembersByLastName($term,0,25);
break;
default:
return $this->validationError('criteria not supported!');
break;
}
foreach($list as $member){
$label = sprintf('%s - (%s) - %s',$member->getFullName(), $member->Email, $member->LastVisited);
array_push($res, array( 'label' => $label,
'value' => $member->getIdentifier(),
'email' => $member->Email,
'first_name' => $member->FirstName,
'last_name' => $member->Surname));
}
return $this->ok($res);
}
catch(NotFoundEntityException $ex1){
SS_Log::log($ex1,SS_Log::NOTICE);
return $this->notFound($ex1->getMessage());
}
catch(Exception $ex){
SS_Log::log($ex,SS_Log::ERR);
return $this->serverError();
}
}
//Teams
public function addTeam(){
$data = $this->getJsonRequest();
if (!$data) return $this->serverError();
try{
$entity = $this->team_manager->registerTeam($data);
return $this->created($entity->getIdentifier());
}
catch(TeamAlreadyExistsException $ex1){
SS_Log::log($ex1,SS_Log::NOTICE);
return $this->validationError(array( array('attribute'=>'error', 'message' => 'Team Already exist on Company!')));
}
catch(EntityValidationException $ex2){
SS_Log::log($ex2,SS_Log::NOTICE);
return $this->validationError($ex2->getMessages());
}
catch(Exception $ex){
SS_Log::log($ex,SS_Log::ERR);
return $this->serverError();
}
}
public function updateTeamName(){
$data = $this->getJsonRequest();
if (!$data) return $this->serverError();
$team_id = (int)$this->request->param('TEAM_ID');
try{
$this->team_manager->updateTeam($team_id, $data);
return $this->updated();
}
catch(TeamAlreadyExistsException $ex1){
SS_Log::log($ex1,SS_Log::NOTICE);
return $this->validationError(array( array('attribute'=>'error', 'message' => 'Team Already exist on Company!')));
}
catch(EntityValidationException $ex2){
SS_Log::log($ex2,SS_Log::NOTICE);
return $this->validationError($ex2->getMessages());
}
catch(NotFoundEntityException $ex3){
SS_Log::log($ex3,SS_Log::NOTICE);
return $this->validationError(array( array('attribute'=>'error', 'message' => 'Team does not exist on Company!')));
}
catch(Exception $ex){
SS_Log::log($ex,SS_Log::ERR);
return $this->serverError();
}
}
public function deleteTeam(){
$team_id = (int)$this->request->param('TEAM_ID');
try{
$this->team_manager->removeTeam($team_id);
return $this->deleted();
}
catch(EntityValidationException $ex2){
SS_Log::log($ex2,SS_Log::NOTICE);
return $this->validationError($ex2->getMessages());
}
catch(NotFoundEntityException $ex3){
SS_Log::log($ex3,SS_Log::NOTICE);
return $this->validationError(array( array('attribute'=>'error', 'message' => 'Team does not exist on Company!')));
}
catch(Exception $ex){
SS_Log::log($ex,SS_Log::ERR);
return $this->serverError();
}
}
}

View File

@ -0,0 +1,85 @@
<?php
/**
* Copyright 2014 Openstack.org
* Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
**/
/**
* Class TeamInvitationConfirmation_Controller
*/
final class TeamInvitationConfirmation_Controller extends AbstractController {
/**
* @var array
*/
static $url_handlers = array(
'GET $CONFIRMATION_TOKEN/confirm' => 'confirmTeamInvitation',
);
/**
* @var array
*/
static $allowed_actions = array(
'confirmTeamInvitation',
);
/**
* @var ICLAMemberRepository
*/
private $member_repository;
/**
* @var CCLATeamManager
*/
private $team_manager;
/**
* @var ITeamInvitationRepository
*/
public function __construct(){
parent::__construct();
$this->member_repository = new SapphireCLAMemberRepository;
$this->invitation_repository = new SapphireTeamInvitationRepository;
$this->team_manager = new CCLATeamManager(
$this->invitation_repository,
$this->member_repository,
new TeamInvitationFactory,
new TeamFactory,
new CCLAValidatorFactory,
new SapphireTeamRepository,
SapphireTransactionManager::getInstance());
}
/**
* @return string|void
*/
public function confirmTeamInvitation(){
$token = $this->request->param('CONFIRMATION_TOKEN');
try{
$current_member = Member::currentUser();
if(is_null($current_member))
return Director::redirect("Security/login?BackURL=" . urlencode($_SERVER['REQUEST_URI']));
$team = $this->team_manager->confirmInvitation($token, $current_member);
return $this->renderWith( array('TeamInvitationConfirmation_successfull','Page') , array('TeamName' => $team->getName() , 'CompanyName' => $team->getCompany()->Name ) );
}
catch(InvitationBelongsToAnotherMemberException $ex1){
SS_Log::log($ex1,SS_Log::ERR);
$invitation = $this->invitation_repository->findByConfirmationToken($token);
return $this->renderWith(array('TeamInvitationConfirmation_belongs_2_another_user','Page'), array('UserName' => $invitation->getMember()->Email));
}
catch(Exception $ex){
SS_Log::log($ex,SS_Log::ERR);
return $this->renderWith(array('TeamInvitationConfirmation_error','Page'));
}
}
}

View File

@ -0,0 +1,47 @@
<?php
/**
* Copyright 2014 Openstack.org
* Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
**/
/**
* Class CLAICLAGroupsCreationTask
*/
final class CLAICLAGroupsCreationTask extends MigrationTask {
protected $title = "CCLA/ICLA Migration";
protected $description = "Creates CLA/ICLA Security Groups";
function up(){
echo "Starting Migration Proc ...<BR>";
//check if migration already had ran ...
$migration = Migration::get()->filter('Name',$this->title)->first();
if (!$migration) {
$g = new Group();
$g->setTitle('CCLA Admin');
$g->setDescription('Company CCLA Admin');
$g->setSlug(ICLAMemberDecorator::CCLAGroupSlug);
$g->write();
Permission::grant($g->getIdentifier(),ICLAMemberDecorator::CCLAPermissionSlug);
$migration = new Migration();
$migration->Name = $this->title;
$migration->Description = $this->description;
$migration->Write();
}
echo "Ending Migration Proc ...<BR>";
}
function down() {
}
}

View File

@ -0,0 +1,74 @@
<?php
/**
* Copyright 2014 Openstack.org
* Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
**/
/***
* Class CCLACompanyService
*/
final class CCLACompanyService {
/**
* @var ICLACompanyRepository
*/
private $company_repository;
/**
* @var ITransactionManager
*/
private $tx_manager;
public function __construct(ICLACompanyRepository $company_repository, ITransactionManager $tx_manager){
$this->company_repository = $company_repository;
$this->tx_manager = $tx_manager;
}
/**
* @param int $company_id
* @return DateTime
*/
public function signCCLA($company_id){
$company_repository = $this->company_repository;
return $this->tx_manager->transaction(function() use($company_id, $company_repository){
$company = $company_repository->getById($company_id);
if(!$company)
throw new NotFoundEntityException('Company',sprintf(' id %s',$company_id));
if(!$company->isICLASigned())
$company->signICLA();
return $company->ICLASignedDate();
});
}
/**
* @param int $company_id
* @return void
*/
public function unsignCCLA($company_id){
$company_repository = $this->company_repository;
return $this->tx_manager->transaction(function() use($company_id, $company_repository){
$company = $company_repository->getById($company_id);
if(!$company)
throw new NotFoundEntityException('Company',sprintf(' id %s',$company_id));
if($company->isICLASigned())
$company->unsignICLA();
});
}
}

View File

@ -0,0 +1,263 @@
<?php
/**
* Copyright 2014 Openstack.org
* Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
**/
/**
* Class CCLATeamManager
*/
final class CCLATeamManager {
/**
* @var ITeamInvitationRepository
*/
private $invitation_repository;
/**
* @var ITransactionManager
*/
private $tx_manager;
/**
* @var ITeamRepository
*/
private $team_repository;
/**
* @var ITeamInvitationFactory
*/
private $invitation_factory;
/**
* @var ICCLAValidatorFactory
*/
private $validator_factory;
/**
* @var ICLAMemberRepository
*/
private $member_repository;
/**
* @var ITeamFactory
*/
private $team_factory;
public function __construct(ITeamInvitationRepository $invitation_repository,
ICLAMemberRepository $member_repository,
ITeamInvitationFactory $invitation_factory,
ITeamFactory $team_factory,
ICCLAValidatorFactory $validator_factory,
ITeamRepository $team_repository,
ITransactionManager $tx_manager){
$this->invitation_repository = $invitation_repository;
$this->tx_manager = $tx_manager;
$this->team_repository = $team_repository;
$this->member_repository = $member_repository;
$this->invitation_factory = $invitation_factory;
$this->validator_factory = $validator_factory;
$this->team_factory = $team_factory;
}
/**
* @param array $data
* @param ITeamInvitationSender $invitation_sender
* @return ITeamInvitation
*/
public function sendInvitation(array $data, ITeamInvitationSender $invitation_sender){
$team_repository = $this->team_repository;
$invitation_factory = $this->invitation_factory;
$validator_factory = $this->validator_factory;
$member_repository = $this->member_repository;
$invitation_repository = $this->invitation_repository;
return $this->tx_manager->transaction(function() use($data, $invitation_repository, $team_repository, $invitation_factory , $validator_factory, $member_repository, $invitation_sender){
$validator = $validator_factory->buildValidatorForTeamInvitation($data);
if ($validator->fails()) {
throw new EntityValidationException($validator->messages());
}
$team = $team_repository->getById((int)$data['team_id']);
if(!$team) throw new NotFoundEntityException('Team',sprintf('id %s',$data['team_id']));
$member = false;
//is a already selected ICLA/CCLA Member
if(isset($data['member_id'])){
$member = $member_repository->getById((int)$data['member_id']);
if(!$member) throw new NotFoundEntityException('Member',sprintf('id %s',$data['member_id']));
}
else {
$member = $member_repository->findByEmail(trim($data['email']));
if($member && !$member->hasSignedCLA())
throw new MemberNotSignedCCLAException('This user has not yet signed the ICLA. Please ensure they have followed the appropriate steps outlined here: https://wiki.openstack.org/wiki/How_To_Contribute#Contributor_License_Agreement');
}
if($member && ($team->isMember($member) || $team->isInvite($member)))
throw new TeamMemberAlreadyExistsException('Member Already exists on Team!');
$invitation = $invitation_factory->buildInvitation(new InvitationDTO($data['first_name'], $data['last_name'], $data['email'], $team, $member ));
$invitation_repository->add($invitation);
$invitation_sender->sendInvitation($invitation);
return $invitation;
});
}
public function verifyInvitations($member_id, ITeamInvitationSender $invitation_sender){
$member_repository = $this->member_repository;
$invitation_repository = $this->invitation_repository;
return $this->tx_manager->transaction(function() use($member_id, $invitation_repository, $member_repository, $invitation_sender){
$member = $member_repository->getById($member_id);
if(!$member) throw new NotFoundEntityException('Member',sprintf('id %s',$member_id));
foreach($invitation_repository->findByInviteEmail($member->Email) as $invitation){
$invitation->updateInvite($member);
$invitation_sender->sendInvitation($invitation);
}
});
}
/**
* @param int $team_id
* @param int $id
* @param string $status
* @throws NotFoundEntityException
*/
public function resignMembership($team_id, $id, $status){
$team_repository = $this->team_repository;
$member_repository = $this->member_repository;
$invitation_repository = $this->invitation_repository;
$this->tx_manager->transaction(function() use($team_id,$id , $status ,$team_repository, $member_repository, $invitation_repository){
$team = $team_repository->getById($team_id);
if(!$team) throw new NotFoundEntityException('Team',sprintf('id %s',$team_id));
switch($status){
case 'member':{
$member = $member_repository->getById($id);
if(!$member) throw new NotFoundEntityException('Member',sprintf('id %s',$id));
$team->removeMember($member);
$team->removeInvitation($invitation_repository->findByInviteEmailAndTeam($member->Email, $team));
}
break;
default:{
$invitation = $invitation_repository->getById($id);
if(!$invitation) throw new NotFoundEntityException('TeamInvitation',sprintf('id %s',$id));
$team->removeInvitation($invitation);
}
break;
}
});
}
/**
* @param string $token
* @param ICLAMember $member
* @return ITeam
*/
public function confirmInvitation($token, ICLAMember $member){
$invitation_repository = $this->invitation_repository;
return $this->tx_manager->transaction(function() use($token, $member, $invitation_repository){
$invitation = $invitation_repository->findByConfirmationToken($token);
if(!$invitation)
throw new NotFoundEntityException('TeamInvitation', sprintf('token %s',$token));
if($invitation->getMember()->getIdentifier() !== $member->getIdentifier())
throw new InvitationBelongsToAnotherMemberException;
$invitation->doConfirmation($token);
$invitation->getTeam()->addMember($invitation->getMember());
return $invitation->getTeam();
});
}
/**
* @param array $team_data
* @return ITeam
*/
public function registerTeam(array $team_data){
$validator_factory = $this->validator_factory;
$team_repository = $this->team_repository;
$team_factory = $this->team_factory;
return $this->tx_manager->transaction(function() use($team_data, $validator_factory, $team_repository, $team_factory){
$validator = $validator_factory->buildValidatorForTeam($team_data);
if ($validator->fails()) {
throw new EntityValidationException($validator->messages());
}
$team = $team_factory->buildTeam($team_data);
if($team_repository->getByNameAndCompany($team->getName(),$team->getCompany()->getIdentifier()))
throw new TeamAlreadyExistsException;
$team_repository->add($team);
return $team;
});
}
/**
* @param int $team_id
* @param array $data
* @return ITeam
*/
public function updateTeam($team_id, $data){
$validator_factory = $this->validator_factory;
$team_repository = $this->team_repository;
$team_factory = $this->team_factory;
return $this->tx_manager->transaction(function() use($team_id, $data , $validator_factory, $team_repository, $team_factory){
$team = $team_repository->getById($team_id);
if(!$team)
throw new NotFoundEntityException('Team', sprintf(' id %s',$team_id ));
$old_team = $team_repository->getByNameAndCompany($team->getName(),$team->getCompany()->getIdentifier());
if($old_team->getIdentifier()!=$team_id)
throw new TeamAlreadyExistsException;
$team->updateName($data['name']);
return $team;
});
}
/**
* @param int $team_id
*/
public function removeTeam($team_id){
$team_repository = $this->team_repository;
$this->tx_manager->transaction(function() use($team_id, $team_repository){
$team = $team_repository->getById($team_id);
if(!$team)
throw new NotFoundEntityException('Team', sprintf(' id %s',$team_id ));
$team->clearMembers();
$team->clearInvitations();
$team_repository->delete($team);
});
}
}

View File

@ -0,0 +1,59 @@
<?php
/**
* Copyright 2014 Openstack.org
* Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
**/
/***
* Interface IBatchTask
*/
interface IBatchTask extends IEntity {
/***
* @return string
*/
public function name();
/***
* @return int
*/
public function lastRecordProcessed();
/**
* @return string
*/
public function lastResponse();
/**
* @return DateTime
*/
public function lastResponseDate();
/**
* @return int
*/
public function totalRecords();
/**
* @param string $response
* @return void
*/
public function updateResponse($response);
/**
* @return void
*/
public function updateLastRecord();
/**
* @param int $total_qty
* @return void
*/
public function initialize($total_qty);
}

View File

@ -0,0 +1,24 @@
<?php
/**
* Copyright 2014 Openstack.org
* Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
**/
/**
* Interface IBatchTaskFactory
*/
interface IBatchTaskFactory {
/**
* @param string $task_name
* @param int $total_record_qty
* @return IBatchTask
*/
public function buildBatchTask($task_name, $total_record_qty);
}

View File

@ -0,0 +1,23 @@
<?php
/**
* Copyright 2014 Openstack.org
* Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
**/
/**
* Interface IBatchTaskRepository
*/
interface IBatchTaskRepository extends IEntityRepository {
/***
* @param string $name
* @return IBatchTask
*/
public function findByName($name);
}

View File

@ -0,0 +1,29 @@
<?php
/**
* Copyright 2014 Openstack.org
* Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
**/
/**
* Interface ICCLAValidatorFactory
*/
interface ICCLAValidatorFactory {
/**
* @param array $data
* @return IValidator
*/
public function buildValidatorForTeamInvitation(array $data);
/**
* @param array $data
* @return ValidatorService
*/
public function buildValidatorForTeam(array $data);
}

View File

@ -0,0 +1,45 @@
<?php
/**
* Copyright 2014 Openstack.org
* Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
**/
/**
* Interface ICLACompany
*/
interface ICLACompany extends IEntity {
/**
* @return void
*/
public function signICLA();
/**
* @return void
*/
public function unsignICLA();
/**
* @return bool
*/
public function isICLASigned();
/**
* @return DateTime
*/
public function ICLASignedDate();
/**
* @return ITeam[]
*/
public function Teams();
public function addTeam(ITeam $team);
}

View File

@ -0,0 +1,19 @@
<?php
/**
* Copyright 2014 Openstack.org
* Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
**/
/**
* Interface ICLACompanyRepository
*/
interface ICLACompanyRepository extends IEntityRepository {
}

View File

@ -0,0 +1,168 @@
<?php
/**
* Copyright 2014 Openstack.org
* Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
**/
/**
* Class ICLAManager
*/
final class ICLAManager {
const ICLAGroupTaskName = 'ICLAGroupTask';
const UpdateLastCommittedDateTaskName = 'UpdateLastCommittedDateTaskName ';
/**
* @var IGerritAPI
*/
private $gerrit_api;
/**
* @var IBatchTaskRepository
*/
private $batch_repository;
/**
* @var ICLAMemberRepository
*/
private $member_repository;
/**
* @var ITransactionManager
*/
private $tx_manager;
/**
* @var IBatchTaskFactory
*/
private $batch_task_factory;
/**
* @param IGerritAPI $gerrit_api
* @param IBatchTaskRepository $batch_repository
* @param ICLAMemberRepository $member_repository
* @param IBatchTaskFactory $batch_task_factory
* @param ITransactionManager $tx_manager
*/
public function __construct(IGerritAPI $gerrit_api,
IBatchTaskRepository $batch_repository,
ICLAMemberRepository $member_repository,
IBatchTaskFactory $batch_task_factory,
ITransactionManager $tx_manager){
$this->gerrit_api = $gerrit_api;
$this->batch_repository = $batch_repository;
$this->member_repository = $member_repository;
$this->batch_task_factory = $batch_task_factory;
$this->tx_manager = $tx_manager;
}
/**
* @param string $icla_group_id
* @param int $batch_size
* @return int
*/
public function processICLAGroup($icla_group_id, $batch_size){
$batch_repository = $this->batch_repository;
$member_repository = $this->member_repository;
$gerrit_api = $this->gerrit_api;
$batch_task_factory = $this->batch_task_factory;
return $this->tx_manager->transaction(function() use($icla_group_id, $batch_size, $member_repository, $batch_repository, $gerrit_api, $batch_task_factory) {
$task = $batch_repository->findByName(ICLAManager::ICLAGroupTaskName);
$members_ids_on_icla = $member_repository->getAllGerritIds();
if(!$task){
// query gerrit service
$icla_members_response = $gerrit_api->listAllMembersFromGroup($icla_group_id);
$task = $batch_task_factory->buildBatchTask(ICLAManager::ICLAGroupTaskName, count($icla_members_response));
$batch_repository->add($task);
$task->updateResponse(json_encode($icla_members_response));
}
else if($task->lastRecordProcessed() == $task->totalRecords()){
$icla_members_response = $gerrit_api->listAllMembersFromGroup($icla_group_id);
if(count($icla_members_response) == count(json_decode($task->lastResponse(), true))) return;//nothing to process..
$task->initialize(count($icla_members_response));
$task->updateResponse(json_encode($icla_members_response));
}
$members = json_decode($task->lastResponse(), true);
$updated_members = 0;
for($i = 0; $i < $batch_size && ( ($task->lastRecordProcessed()) < $task->totalRecords() ); $i++){
$index = $task->lastRecordProcessed();
$gerrit_info = $members[$index];
$email = @$gerrit_info['email'];
$gerrit_id = @$gerrit_info['_account_id'];
if(!empty($email) && !empty($gerrit_id) ){
if(!array_key_exists($gerrit_id, $members_ids_on_icla)){
$member = $member_repository->findByEmail($email);
if($member){
$member->signICLA($gerrit_id);
++$updated_members;
}
}
}
$task->updateLastRecord();
}
return $updated_members;
});
}
public function updateLastCommittedDate($batch_size){
$batch_repository = $this->batch_repository;
$member_repository = $this->member_repository;
$gerrit_api = $this->gerrit_api;
$batch_task_factory = $this->batch_task_factory;
return $this->tx_manager->transaction(function() use($batch_size, $member_repository, $batch_repository, $gerrit_api, $batch_task_factory) {
$task = $batch_repository->findByName(ICLAManager::UpdateLastCommittedDateTaskName);
$last_index = 0;
$members = array();
$updated_members = 0;
if($task){
$last_index = $task->lastRecordProcessed();
list($members,$total_size) = $member_repository->getAllICLAMembers($last_index, $batch_size);
if($task->lastRecordProcessed() == $task->totalRecords()) $task->initialize($total_size);
}
else{
list($members,$total_size) = $member_repository->getAllICLAMembers($last_index, $batch_size);
$task = $batch_task_factory->buildBatchTask(ICLAManager::UpdateLastCommittedDateTaskName, $total_size);
$batch_repository->add($task);
}
foreach($members as $member){
$last_commit_date = $gerrit_api->getUserLastCommit($member->getGerritId());
if(!is_null($last_commit_date) && $last_commit_date){
$member->updateLastCommitedDate($last_commit_date);
++$updated_members;
}
$task->updateLastRecord();
}
return $updated_members;
});
}
}

View File

@ -0,0 +1,59 @@
<?php
/**
* Copyright 2014 Openstack.org
* Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
**/
/**
* Interface ICLAMember
*/
interface ICLAMember extends IEntity {
const CCLAGroupSlug = 'ccla-admin';
const CCLAPermissionSlug = 'CCLA_ADMIN';
/**
* @return string
*/
public function getGerritId();
/**
* @return DateTime
*/
public function getLastCommitedDate();
/**
* @param int $gerrit_id
* @return void
*/
public function signICLA($gerrit_id);
/**
* @param DateTime $date
* @return void
*/
public function updateLastCommitedDate(DateTime $date);
/**
* @return bool
*/
public function isCCLAAdmin();
/**
* @return ICLACompany
*/
public function getManagedCCLACompany();
/**
* @return bool
*/
public function hasSignedCLA();
}

View File

@ -0,0 +1,55 @@
<?php
/**
* Copyright 2014 Openstack.org
* Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
**/
/**
* Interface ICLAMemberRepository
*/
interface ICLAMemberRepository extends IMemberRepository {
/***
* @return int[]
*/
function getAllGerritIds();
/**
* @param int $offset
* @param int $limit
* @return ICLAMember[]
*/
function getAllICLAMembers($offset, $limit);
/**
* @param string $email
* @param int $offset
* @param int $limit
* @return array
*/
function getAllIClaMembersByEmail($email, $offset, $limit);
/**
* @param string $first_name
* @param int $offset
* @param int $limit
* @return array
*/
function getAllIClaMembersByFirstName($first_name, $offset, $limit);
/**
* @param string $last_name
* @param int $offset
* @param int $limit
* @return array
*/
function getAllIClaMembersByLastName($last_name, $offset, $limit);
}

View File

@ -0,0 +1,29 @@
<?php
/**
* Copyright 2014 Openstack.org
* Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
**/
/**
* Interface IGerritAPI
*/
interface IGerritAPI {
/**
* @param string $group_id
* @return array
*/
public function listAllMembersFromGroup($group_id);
/**
* @param string $gerrit_user_id
* @return DateTime
*/
public function getUserLastCommit($gerrit_user_id);
}

View File

@ -0,0 +1,23 @@
<?php
/**
* Copyright 2014 Openstack.org
* Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
**/
/**
* Interface IMemberRepository
*/
interface IMemberRepository extends IEntityRepository {
/**
* @param string $email
* @return ICLAMember
*/
public function findByEmail($email);
}

83
ICLA/code/model/ITeam.php Normal file
View File

@ -0,0 +1,83 @@
<?php
/**
* Copyright 2014 Openstack.org
* Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
**/
/**
* Interface ITeam
*/
interface ITeam extends IEntity {
/**
* @return string
*/
public function getName();
/**
* @param string $name
* @return void
*/
public function updateName($name);
/**
* @return ICLAMember[]
*/
public function getMembers();
/**
* @param ICLAMember $member
* @return void
*/
public function addMember(ICLAMember $member);
/**
* @param ICLAMember $member
* @return void
*/
public function removeMember(ICLAMember $member);
/**
* @return ITeamInvitation[]
*/
public function getInvitations();
/**
* @return ITeamInvitation[]
*/
public function getUnconfirmedInvitations();
/**
* @return ICLACompany
*/
public function getCompany();
/**
* @param ICLAMember $member
* @return bool
*/
public function isInvite(ICLAMember $member);
/**
* @param ICLAMember $member
* @return bool
*/
public function isMember(ICLAMember $member);
/**
* @param ITeamInvitation $invitation
* @return void
*/
public function removeInvitation(ITeamInvitation $invitation);
public function clearMembers();
public function clearInvitations();
}

View File

@ -0,0 +1,23 @@
<?php
/**
* Copyright 2014 Openstack.org
* Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
**/
/**
* Interface ITeamFactory
*/
interface ITeamFactory {
/**
* @param array $team_data
* @return ITeam
*/
public function buildTeam(array $team_data);
}

View File

@ -0,0 +1,53 @@
<?php
/**
* Copyright 2014 Openstack.org
* Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
**/
/**
* Interface ITeamInvitation
*/
interface ITeamInvitation extends IEntity {
/**
* @return InviteInfoDTO
*/
public function getInviteInfo();
/**
* @return bool
*/
public function isInviteRegisteredAsUser();
/**
* @return ITeam
*/
public function getTeam();
/**
* @return string
*/
public function generateConfirmationToken();
/**
* @param string $token
* @return bool
* @throws InvalidHashInvitationException
* @throws InvitationAlreadyConfirmedException
*/
public function doConfirmation($token);
/**
* @return ICLAMember
*/
public function getMember();
public function updateInvite(ICLAMember $invite);
}

View File

@ -0,0 +1,23 @@
<?php
/**
* Copyright 2014 Openstack.org
* Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
**/
/**
* Interface ITeamInvitationFactory
*/
interface ITeamInvitationFactory {
/**
* @param InvitationDTO $invitation_dto
* @return ITeamInvitation
*/
public function buildInvitation(InvitationDTO $invitation_dto);
}

View File

@ -0,0 +1,43 @@
<?php
/**
* Copyright 2014 Openstack.org
* Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
**/
/**
* Interface ITeamInvitationRepository
*/
interface ITeamInvitationRepository extends IEntityRepository {
/**
* @param string $token
* @return bool
*/
public function existsConfirmationToken($token);
/**
* @param string $token
* @return ITeamInvitation
*/
public function findByConfirmationToken($token);
/**
* @param string $email
* @param bool $all
* @return ITeamInvitation[]
*/
public function findByInviteEmail($email, $all = false);
/**
* @param string $email
* @param ITeam $team
* @return ITeamInvitation
*/
public function findByInviteEmailAndTeam($email, ITeam $team);
}

View File

@ -0,0 +1,24 @@
<?php
/**
* Copyright 2014 Openstack.org
* Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
**/
/**
* Interface ITeamInvitationSender
*/
interface ITeamInvitationSender {
/**
* @param ITeamInvitation $invitation
* @return void
*/
public function sendInvitation(ITeamInvitation $invitation);
}

View File

@ -0,0 +1,30 @@
<?php
/**
* Copyright 2014 Openstack.org
* Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
**/
/**
* Interface ITeamRepository
*/
interface ITeamRepository extends IEntityRepository {
/**
* @param int $company_id
* @return ITeam[]
*/
public function getByCompany($company_id);
/**
* @param string $name
* @param int $company_id
* @return ITeam
*/
public function getByNameAndCompany($name, $company_id);
}

View File

@ -0,0 +1,55 @@
<?php
/**
* Copyright 2014 Openstack.org
* Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
**/
/**
* Class InvitationDTO
*/
final class InvitationDTO extends InviteInfoDTO {
/**
* @var ITeam
*/
private $team;
/**
* @var ICLAMember
*/
private $member;
/**
* @param string $first_name
* @param string $last_name
* @param string $email
* @param ITeam $team
* @param ICLAMember $member
*/
public function __construct($first_name, $last_name, $email, ITeam $team, ICLAMember $member = null){
parent::__construct($first_name, $last_name, $email);
$this->team = $team;
$this->member = $member;
}
/*
* @return ITeam
*/
public function getTeam(){
return $this->team;
}
/**
* @return ICLAMember
*/
public function getMember(){
return $this->member;
}
}

View File

@ -0,0 +1,65 @@
<?php
/**
* Copyright 2014 Openstack.org
* Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
**/
/**
* Class InviteInfoDTO
*/
class InviteInfoDTO {
/**
* @var string
*/
protected $first_name;
/**
* @var string
*/
protected $last_name;
/**
* @var string
*/
protected $email;
/**
* @param string $first_name
* @param string $last_name
* @param string $email
*/
public function __construct($first_name, $last_name, $email){
$this->first_name = $first_name;
$this->last_name = $last_name;
$this->email = $email;
}
/**
* @return string
*/
public function getFirstName(){
return $this->first_name;
}
/**
* @return string
*/
public function getLastName(){
return $this->last_name;
}
/**
* @return string
*/
public function getEmail(){
return $this->email;
}
}

View File

@ -0,0 +1,19 @@
<?php
/**
* Copyright 2014 Openstack.org
* Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
**/
/**
* Class InvalidHashInvitationException
*/
final class InvalidHashInvitationException extends Exception {
}

View File

@ -0,0 +1,19 @@
<?php
/**
* Copyright 2014 Openstack.org
* Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
**/
/**
* Class InvitationAlreadyConfirmedException
*/
final class InvitationAlreadyConfirmedException extends Exception {
}

View File

@ -0,0 +1,19 @@
<?php
/**
* Copyright 2014 Openstack.org
* Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
**/
/**
* Class InvitationBelongsToAnotherMemberException
*/
final class InvitationBelongsToAnotherMemberException extends Exception {
}

View File

@ -0,0 +1,20 @@
<?php
/**
* Copyright 2014 Openstack.org
* Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
**/
/**
* Class MemberNotSignedCCLAException
*/
final class MemberNotSignedCCLAException extends Exception {
}

View File

@ -0,0 +1,19 @@
<?php
/**
* Copyright 2014 Openstack.org
* Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
**/
/**
* Class TeamAlreadyExistsException
*/
final class TeamAlreadyExistsException extends Exception {
}

View File

@ -0,0 +1,19 @@
<?php
/**
* Copyright 2014 Openstack.org
* Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
**/
/**
* Class TeamMemberAlreadyExistsException
*/
final class TeamMemberAlreadyExistsException extends Exception {
}

View File

@ -0,0 +1,89 @@
<?php
/**
* Copyright 2014 Openstack.org
* Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
**/
/**
* Class SangriaPageICLACompaniesExtension
*/
final class SangriaPageICLACompaniesExtension extends Extension {
private static $allowed_actions = array('ViewICLACompanies','exportCCLACompanies');
/**
* @var ICLACompanyRepository
*/
private $company_repository;
public function __construct(){
parent::__construct();
$this->company_repository = new SapphireICLACompanyRepository();
}
public function onBeforeInit(){
Config::inst()->update(get_class($this->owner), 'allowed_actions', array('ViewICLACompanies','exportCCLACompanies'));
}
public function getQuickActionsExtensions(&$html){
$view = new SSViewer('SangriaPage_ICLALinks');
$html .= $view->process($this->owner);
}
public function ViewICLACompanies(){
Requirements::css('ICLA/css/sangia.ccla.companies.css');
Requirements::javascript('ICLA/js/sangia.ccla.companies.js');
return $this->owner->getViewer('ViewICLACompanies')->process($this->owner);
}
public function getCompanies(){
$query = new QueryObject;
$query->addOrder(QueryOrder::asc('Name'));
list($list,$size) = $this->company_repository->getAll($query,0,1000);
return new ArrayList($list);
}
public function exportCCLACompanies(){
//clean output buffer
ob_end_clean();
// file name for download
$filename = "companies_ccla" . date('Ymd') . ".xls";
header("Content-Disposition: attachment; filename=\"$filename\"");
header("Content-Type: application/vnd.ms-excel");
$query = new QueryObject;
$query->addOrder(QueryOrder::asc('Name'));
list($list,$size) = $this->company_repository->getAll($query,0,1000);
$data = array();
foreach($list as $company){
$row = array();
$row['CompanyName'] = $company->Name;
$row['CCLADate'] = $company->isICLASigned()? $company->CCLADate:'N/A';
$row['CCLASigned'] = $company->isICLASigned()? 'True':'False';
array_push($data, $row);
}
$flag = false;
foreach($data as $row) {
if(!$flag) {
// display field/column names as first row
echo implode("\t", array_keys($row)) . "\n";
$flag = true;
}
array_walk($row, array($this,'cleanData'));
echo implode("\t", array_values($row)) . "\n";
}
}
function cleanData(&$str)
{
$str = preg_replace("/\t/", "\\t", $str);
$str = preg_replace("/\r?\n/", "\\n", $str);
if(strstr($str, '"')) $str = '"' . str_replace('"', '""', $str) . '"';
}
}

View File

@ -0,0 +1,110 @@
<?php
/**
* Copyright 2014 Openstack.org
* Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
**/
/**
* Class EditProfilePageICLAExtension
*/
final class EditProfilePageICLAExtension extends Extension {
/**
* @var ITeamRepository
*/
private $team_repository;
public function __construct(){
$this->team_repository = new SapphireTeamRepository;
}
public function onBeforeInit(){
Config::inst()->update(get_class($this), 'allowed_actions', array('CCLATeamAdmin'));
}
public function getNavActionsExtensions(&$html){
$view = new SSViewer('EditProfilePage_ICLANav');
$html .= $view->process($this->owner);
}
public function CCLATeamAdmin(){
Requirements::javascript('marketplace/code/ui/admin/js/utils.js');
Requirements::customScript('var company_id = '.$this->getCompanyID().';');
Requirements::javascript('ICLA/js/edit.profile.ccla.teams.js');
Requirements::javascript(Director::protocol()."ajax.aspnetcdn.com/ajax/jquery.validate/1.11.1/jquery.validate.min.js");
Requirements::javascript(Director::protocol()."ajax.aspnetcdn.com/ajax/jquery.validate/1.11.1/additional-methods.min.js");
Requirements::javascript("themes/openstack/javascript/jquery.validate.custom.methods.js");
Requirements::css('ICLA/css/edit.profile.ccla.teams.css');
return $this->owner->getViewer('CCLATeamAdmin')->process($this->owner);
}
public function getTeamsDLL($id='add_member_team'){
$current_member = Member::currentUser();
if(!$current_member) return false;
$company = $current_member->getManagedCCLACompany();
if(!$company) return false;
$res = $this->team_repository->getByCompany($company->getIdentifier());
$res = new ArrayList($res);
$ddl = new DropdownField($id,null, $res->map("ID", "Name"));
$ddl->setEmptyString('-- Select a Team --');
return $ddl;
}
public function getTeamMembers(){
$current_member = Member::currentUser();
if(!$current_member) return false;
$company = $current_member->getManagedCCLACompany();
if(!$company) return false;
$teams = $this->team_repository->getByCompany($company->getIdentifier());
$members = array();
foreach($teams as $team){
foreach($team->getMembers() as $team_member){
array_push($members, new TeamMemberViewModel($team_member->FirstName, $team_member->Surname, $team_member->Email, $team->getIdentifier() ,$team->getName(),'member', $team_member->getIdentifier() ,$team_member->DateAdded));
}
foreach($team->getUnconfirmedInvitations() as $team_invitation){
$info = $team_invitation->getInviteInfo();
$status = $team_invitation->isInviteRegisteredAsUser()? 'needs-confirmation':'needs-registration';
array_push($members, new TeamMemberViewModel($info->getFirstName(), $info->getLastName(), $info->getEmail(), $team->getIdentifier() , $team->getName(), $status, $team_invitation->getIdentifier(),$team_invitation->Created ));
}
}
usort($members, array($this,'cmp_team_members'));
return new ArrayList($members);
}
public function cmp_team_members($a, $b){
$name1 = $a->getFirstName().' '.$a->getLastName();
$name2 = $b->getFirstName().' '.$b->getLastName();
if ($name1 == $name2) {
return 0;
}
return ($name1 < $name2) ? -1 : 1;
}
public function getCompanyName(){
$current_member = Member::currentUser();
if(!$current_member) return false;
$company = $current_member->getManagedCCLACompany();
if(!$company) return false;
return $company->Name;
}
public function getCompanyID(){
$current_member = Member::currentUser();
if(!$current_member) return false;
$company = $current_member->getManagedCCLACompany();
if(!$company) return false;
return $company->ID;
}
}

View File

@ -0,0 +1,107 @@
<?php
/**
* Copyright 2014 Openstack.org
* Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
**/
/**
* Class TeamMemberViewModel
*/
final class TeamMemberViewModel extends ViewableData {
/**
* @var string
*/
private $first_name;
/**
* @var string
*/
private $last_name;
/**
* @var string
*/
private $email;
/**
* @var string
*/
private $team_name;
/**
* @var string
*/
private $status;
/**
* @var int
*/
private $id;
/**
* @var int
*/
private $team_id;
private $date_added;
/**
* @param string $first_name
* @param string $last_name
* @param string $email
* @param string $team_name
* @param int $team_id
* @param string $status
* @param int $id
* @param $date_added
*/
public function __construct($first_name, $last_name, $email, $team_id, $team_name, $status, $id, $date_added){
$this->first_name = $first_name;
$this->last_name = $last_name;
$this->email = $email;
$this->team_name = $team_name;
$this->team_id = $team_id;
$this->status = $status;
$this->id = $id;
$this->date_added = $date_added;
}
/**
* @return string
*/
public function getStatus(){
return $this->status;
}
public function getFirstName(){
return $this->first_name;
}
public function getLastName(){
return $this->last_name;
}
public function getEmail(){
return $this->email;
}
public function getId(){
return $this->id;
}
public function getTeamName(){
return $this->team_name;
}
public function getTeamId(){
return $this->team_id;
}
public function getDateAdded(){
return $this->date_added;
}
}

View File

@ -0,0 +1,52 @@
#ccla_teams {
border: 1px solid #ccc;
border-collapse: collapse;
clear: both;
}
#ccla_teams thead th {
background: none repeat scroll 0 0 #FFFFFF;
}
.status-base {
border-radius: 50%;
width: 15px;
height: 15px;
cursor: pointer;
}
.member {
background: green;
}
.needs-confirmation {
background: yellow;
}
.needs-registration {
background: red;
}
label.error {
width: auto !important;
}
input.error {
padding: 0 !important;
}
.ui-autocomplete {
z-index: 999999999999999999!important;
}
.status-legend{
float:left;
padding-left: 5px;
padding-right: 5px;
}
.status-legend-container{
padding-top: 5px;
padding-bottom: 5px;
}

View File

@ -0,0 +1,13 @@
#ccla-companies-table {
border: 1px solid #ccc;
border-collapse: collapse;
clear: both;
}
#ccla-companies-table thead th {
background: none repeat scroll 0 0 #FFFFFF;
}
.row-0{
background-color:#dcdcdc;
}

View File

@ -0,0 +1,300 @@
/**
* Copyright 2014 Openstack.org
* Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
**/
jQuery(document).ready(function($) {
var form = $('#ccla_teams_form');
var form_validator = form.validate({
rules: {
add_member_email : {
required:true,
email:true
},
add_member_lname : {
required:true,
ValidPlainText:true
},
add_member_fname : {
required:true,
ValidPlainText:true
},
add_member_team:{
required:true
}
},
onfocusout: false,
focusCleanup: true,
focusInvalid: false,
invalidHandler: function(form, validator) {
if (!validator.numberOfInvalids())
return;
var element = $(validator.errorList[0].element);
if(!element.is(":visible")){
element = element.parent();
}
$('html, body').animate({
scrollTop: element.offset().top
}, 2000);
},
errorPlacement: function(error, element) {
if(!element.is(":visible")){
element = element.parent();
}
error.insertAfter(element);
}
});
$('#add_member_email').autocomplete({
source: 'api/v1/ccla/members?field=email',
minLength: 2,
select: function (event, ui) {
$("#add_member_email" ).val(ui.item.email);
$("#add_member_lname" ).val(ui.item.last_name);
$("#add_member_fname" ).val(ui.item.first_name);
$('#add_member_row').attr("data-member-id", ui.item.value);
return false;
},
focus: function( event, ui ) {
$("#add_member_email" ).val(ui.item.email);
$("#add_member_lname" ).val(ui.item.last_name);
$("#add_member_fname" ).val(ui.item.first_name);
return false;
}
})
$('#add_member_lname').autocomplete({
source: 'api/v1/ccla/members?field=lname',
minLength: 2,
select: function (event, ui) {
$("#add_member_email" ).val(ui.item.email);
$("#add_member_lname" ).val(ui.item.last_name);
$("#add_member_fname" ).val(ui.item.first_name);
$('#add_member_row').attr("data-member-id", ui.item.value);
return false;
},
focus: function( event, ui ) {
$("#add_member_email" ).val(ui.item.email);
$("#add_member_lname" ).val(ui.item.last_name);
$("#add_member_fname" ).val(ui.item.first_name);
return false;
}
})
$('#add_member_fname').autocomplete({
source: 'api/v1/ccla/members?field=fname',
minLength: 2,
select: function (event, ui) {
$("#add_member_email" ).val(ui.item.email);
$("#add_member_lname" ).val(ui.item.last_name);
$("#add_member_fname" ).val(ui.item.first_name);
$('#add_member_row').attr("data-member-id", ui.item.value);
return false;
},
focus: function( event, ui ) {
$("#add_member_email" ).val(ui.item.email);
$("#add_member_lname" ).val(ui.item.last_name);
$("#add_member_fname" ).val(ui.item.first_name);
return false;
}
})
$('.delete_member').live('click',function(event){
event.preventDefault();
event.stopPropagation();
if(confirm('Are you sure?')){
var button = $(this);
if(button.prop('disabled')){
return false;
}
button.prop('disabled',true);
var id = button.attr('data-id');
var status = button.attr('data-status');
var team_id = button.attr('data-team-id');
$.ajax({
type: 'DELETE',
url: 'api/v1/ccla/teams/'+team_id+'/memberships/'+id+'/'+status,
contentType: "application/json; charset=utf-8",
dataType: "json",
success: function (data,textStatus,jqXHR) {
var row = button.parent().parent();
row.remove();
},
error: function (jqXHR, textStatus, errorThrown) {
ajaxError(jqXHR, textStatus, errorThrown);
button.prop('disabled',false);
}
});
}
return false;
});
$('#add_member').click(function(event){
event.preventDefault();
event.stopPropagation();
var button = $(this);
if(button.prop('disabled')){
return false;
}
var is_valid = form.valid();
if(!is_valid){
return false;
}
//save
var invitation = {
email : $("#add_member_email" ).val(),
first_name : $("#add_member_fname" ).val(),
last_name : $("#add_member_lname" ).val(),
team_id : $("#add_member_team" ).val()
};
var member_id = $('#add_member_row').attr("data-member-id");
if(typeof(member_id) !== "undefined")
invitation.member_id = member_id;
button.prop('disabled',true);
$.ajax({
type: 'POST',
url: 'api/v1/ccla/invitations',
data: JSON.stringify(invitation),
contentType: "application/json; charset=utf-8",
dataType: "json",
success: function (data,textStatus,jqXHR) {
button.prop('disabled',false);
$("#add_member_email" ).val('');
$("#add_member_fname" ).val('');
$("#add_member_lname" ).val('');
$("#add_member_team" ).val('');
$('#add_member_row').attr("data-member-id",'');
location.reload();
},
error: function (jqXHR, textStatus, errorThrown) {
ajaxError(jqXHR, textStatus, errorThrown);
button.prop('disabled',false);
}
});
return false;
});
$('#select_edit_team').change(function(event){
var team_id = $(this).val();
if(team_id!=''){
$('#edit_team_name').val($('option:selected', this).text());
$('#add_team').hide();
$('#save_team').show();
$('#delete_team').show();
}
else{
$('#add_team').show();
$('#save_team').hide();
$('#delete_team').hide();
$('#edit_team_name').val('');
}
});
$('#save_team').click(function(event){
$('#add_team').show();
$('#save_team').hide();
$('#delete_team').hide();
var button = $(this);
var team_id = $('#select_edit_team').val();
var team = {name : $('#edit_team_name').val()};
if(team.name.trim()===''){
alert('You must provide a valid team name!');
return false;
}
$('#edit_team_name').val('');
$.ajax({
type: 'PUT',
url: 'api/v1/ccla/teams/'+team_id,
data: JSON.stringify(team),
contentType: "application/json; charset=utf-8",
dataType: "json",
success: function (data,textStatus,jqXHR) {
location.reload();
},
error: function (jqXHR, textStatus, errorThrown) {
ajaxError(jqXHR, textStatus, errorThrown);
button.prop('disabled',false);
}
});
});
$('#add_team').click(function(event){
var button = $(this);
var team = { name: $('#edit_team_name').val() , company_id : company_id};
if(team.name.trim()===''){
alert('You must provide a valid team name!');
return false;
}
$('#edit_team_name').val('');
$('#add_team').show();
$('#save_team').hide();
$('#delete_team').hide();
button.prop('disabled',true);
$.ajax({
type: 'POST',
url: 'api/v1/ccla/teams',
data: JSON.stringify(team),
contentType: "application/json; charset=utf-8",
dataType: "json",
success: function (data,textStatus,jqXHR) {
location.reload();
},
error: function (jqXHR, textStatus, errorThrown) {
ajaxError(jqXHR, textStatus, errorThrown);
button.prop('disabled',false);
}
});
});
$('#delete_team').click(function(event){
if(confirm('Are you sure? this will clear all memberships and all pending invitations as well.')){
$('#edit_team_name').val('');
$('#add_team').show();
$('#save_team').hide();
$('#delete_team').hide();
var button = $(this);
button.prop('disabled',true);
var team_id = $('#select_edit_team').val();
$.ajax({
type: 'DELETE',
url: 'api/v1/ccla/teams/'+team_id,
contentType: "application/json; charset=utf-8",
dataType: "json",
success: function (data,textStatus,jqXHR) {
location.reload();
},
error: function (jqXHR, textStatus, errorThrown) {
ajaxError(jqXHR, textStatus, errorThrown);
button.prop('disabled',false);
}
});
}
});
});

View File

@ -0,0 +1,48 @@
/**
* Copyright 2014 Openstack.org
* Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
**/
jQuery(document).ready(function($) {
$('.ccla_checkbox').click(function(event){
var sign = $(this).is(":checked");
if(!sign && !confirm("Are you sure...?")){
event.preventDefault();
event.stopPropagation();
return false;
}
var company_id = $(this).attr('data-company-id');
var url = 'api/v1/ccla/companies/'+company_id+'/sign';
var verb = sign?'PUT':'DELETE';
$.ajax({
async:true,
type: verb,
url: url,
dataType: "json",
success: function (data,textStatus,jqXHR) {
var td = $('#ccla_date_'+company_id);
if(sign){
var date = data.sign_date.date;
td.html(date);
}
else{
td.html('');
}
},
error: function (jqXHR, textStatus, errorThrown) {
alert( "Request failed: " + textStatus );
}
});
});
});

24
ICLA/readme.txt Normal file
View File

@ -0,0 +1,24 @@
** Scheduled tasks
make cache folder writable to all
sudo chmod 777 -R tmp/path/to/ss/cache/folder
add to _ss_environment.php file following global:
global $_FILE_TO_URL_MAPPING;
$_FILE_TO_URL_MAPPING['/path/to/project'] = 'http://localhost';
PullCLAFromGerritTask:
pulls gerrit endpoint https://gerrit-review.googlesource.com/Documentation/rest-api-groups.html#group-members
using icla group id, and update all members on Member table with gerrit id and icla signed
* php /path/to/project/sapphire/cli-script.php /PullCLAFromGerritTask
UpdateLastCommitedDateTask:
pulls from gerrit the last commit date for all users with icla signed and update on member table
* php /path/to/project/sapphire/cli-script.php /UpdateLastCommittedDateTask

View File

@ -0,0 +1,25 @@
$SetCurrentTab(6)
<% require themedCSS(profile-section) %>
<h1>$Title</h1>
<% if CurrentMember %>
<% include ProfileNav %>
<% if CurrentMember.isCCLAAdmin %>
<fieldset>
<% include EditProfilePage_Teams %>
<br>
<br>
<% include EditProfilePage_TeamMembers %>
</fieldset>
<% else %>
<p>You are not allowed to administer ICCLA/CCLA Team Members</p>
<% end_if %>
<% else %>
<p>In order to edit your community profile, you will first need to
<a href="/Security/login/?BackURL=%2Fprofile%2F">login as a member</a>. Don't have an account?
<a href="/join/">Join The Foundation</a>
</p>
<p>
<a class="roundedButton" href="/Security/login/?BackURL=%2Fprofile%2F">Login</a>
<a href="/join/" class="roundedButton">Join The Foundation</a>
</p>
<% end_if %>

View File

@ -0,0 +1,3 @@
<% if CurrentMember.isCCLAAdmin %>
<a href="{$Link}CCLATeamAdmin" <% if CurrentTab=6 %>class="active"<% end_if %> >CCLA Team Administration</a>
<% end_if %>

View File

@ -0,0 +1,57 @@
<h2>$CompanyName Team Members Administration</h2>
<form name="ccla_teams_form" id="ccla_teams_form">
<div class="status-legend-container">
<div style="float:left" class="status-base needs-registration"></div><div class="status-legend">Needs Registration</div>
<div style="float:left" class="status-base needs-confirmation"></div><div class="status-legend">Needs Confirmation</div>
<div style="float:left" class="status-base member"></div><div class="status-legend">Is Member</div>
</div>
<table id="ccla_teams">
<thead>
<tr>
<th>First Name</th>
<th>Last Name</th>
<th>Email</th>
<th>Team</th>
<th>Date Added</th>
<th>&nbsp;</th>
<th>&nbsp;</th>
</tr>
<tr id="add_member_row">
<td>
<input type="text" id="add_member_fname" name="add_member_fname">
</td>
<td>
<input type="text" id="add_member_lname" name="add_member_lname">
</td>
<td>
<input type="text" id="add_member_email" name="add_member_email">
</td>
<td>
$TeamsDLL
</td>
<td colspan="3">
<button id="add_member">Add</button>
</td>
</tr>
</thead>
<tfoot>
</tfoot>
<tbody>
<% if TeamMembers %>
<% loop TeamMembers %>
<tr data-id="{$Id}">
<td>$FirstName</td>
<td>$LastName</td>
<td>$Email</td>
<td>$TeamName</td>
<td>$DateAdded</td>
<td><div class="status-base {$Status}" title="{$Status}"></div></td>
<td><button class="delete_member" data-team-id="{$TeamId}" data-id="{$Id}" data-status="{$Status}">Delete</button></td>
</tr>
<% end_loop %>
<% end_if %>
</tbody>
</table>
</form>

View File

@ -0,0 +1,6 @@
<h2>$CompanyName Teams Administration</h2>
<input type="text" name="edit_team_name" id="edit_team_name">
<button id="add_team" >Add</button>
<button id="save_team" style="display:none;">Save</button>
<button id="delete_team" style="display:none;">Delete</button>
$getTeamsDLL('select_edit_team')

View File

@ -0,0 +1,6 @@
<p> $FirstName $LastName, a request has been made by $CompanyName
to add you to their Corporate CLA. In order to confirm the invitation please click on following link
<a href="{$ConfirmationLink}">Confirm Membership</a>.
</p>
Thank you,<BR>
The OpenStack Team.<BR>

View File

@ -0,0 +1,5 @@
<p> Hello, $FirstName $LastName, you have been invited to $CompanyName $TeamName Team.
In order to be able to join to this team, please register first with an OpenstackID
<a href="{$RegistrationLink}">Register</a>.
The OpenStack Team.
</p>

View File

@ -0,0 +1,4 @@
<h2>CLA/ICLA Companies</h2>
<ul>
<li><a href="$Top.Link(ViewICLACompanies)">View CLA/ICLA Companies</a></li>
</ul>

View File

@ -0,0 +1,25 @@
<h2>CLA/ICLA Companies</h2>
<% if Companies %>
<a href="$Link(exportCCLACompanies)">export to excel</a>
<table id="ccla-companies-table">
<thead>
<tr>
<th>Company Name</th>
<th>CCLA Date</th>
<th>CCLA Signed</th>
</tr>
</thead>
<tbody>
<% loop Companies %>
<tr class="row-{$Modulus(2)}">
<td>$Name</td>
<td id="ccla_date_{$ID}">$CCLADate</td>
<td>
<input type="checkbox" class="ccla_checkbox" data-company-id="{$ID}" id="ccla_signed_checkbox_{$ID}" name="ccla_signed_checkbox_{$ID}" <% if isICLASigned %> checked <% end_if %>>
</td>
</tr>
<% end_loop %>
</tbody>
</table>
<% end_if %>

View File

@ -0,0 +1,3 @@
<p>
Team Membership confirmation belongs to user $UserName. Logout and try to login as that user in order to confirm.
</p>

View File

@ -0,0 +1,3 @@
<p>
There was an error on your Team Membership confirmation.
</p>

View File

@ -0,0 +1,6 @@
<p>
You have been added successfully to $CompanyName $TeamName Team!
Congratulations.
<a href="/profile">Go to your Profile</a>
The Open Stack Team.
</p>

View File

@ -0,0 +1,51 @@
<?php
/**
* Copyright 2014 Openstack.org
* Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
**/
/**
* Class ICLAManagerTest
*/
final class ICLAManagerTest extends SapphireTest {
/**
* @expectedException UnauthorizedRestfullAPIException
*/
public function testprocessICLAGroupUnauthorizedRestfullAPIException(){
$manager = new ICLAManager (
new GerritAPI('https://review.openstack.org', 'smarcet', ''),
new SapphireBatchTaskRepository,
new SapphireCLAMemberRepository,
new BatchTaskFactory,
SapphireTransactionManager::getInstance()
);
$manager->processICLAGroup('a49e4febb69477d0aa5737038c1802dd6cab67c5',10);
$this->setExpectedException('UnauthorizedRestfullAPIException');
}
public function testprocessICLAGroup(){
$manager = new ICLAManager (
new GerritAPI('https://review.openstack.org', 'smarcet', 'TwxKcgZurLX6'),
new SapphireBatchTaskRepository,
new SapphireCLAMemberRepository,
new BatchTaskFactory,
SapphireTransactionManager::getInstance()
);
$manager->processICLAGroup('a49e4febb69477d0aa5737038c1802dd6cab67c5',10);
}
}

65
README.md Normal file
View File

@ -0,0 +1,65 @@
## Overview
The OpenStack Foundation Website
WHAT IS IT?
openstack.org runs a PHP web application called Silverstripe, and we've made several improvements to meet the specific needs of OpenStack. More about the Silverstripe CMS is available here: http://silverstripe.org/
This repository is designed to help other project members develop, test, and contribute to the openstack.org website project. Note that this project is only for code that powers the public openstack.org website. To participate in building the actual OpenStack software, go to:
http://wiki.openstack.org/HowToContribute
WHY RELEASE THE SOURCE?
The OpenStack.org website helps promote OpenStack, the open source cloud computing platform. We felt it only make sense to share the code that powers our website so that other open source projects might benefit, and so that developers in our community might help us improve the code that powers the website dedicated to promoting their favorite open source project.
A REMINDER ON TRADEMARKS:
In light of the trademarks held by the OpenStack Foundation, it is important that you not use the code to build a website or webpage that could be confused with the openstack.org website, including by building a site or page with the same look and feel of the openstack.org site or by using trademarks that are the same as or similar to marks found on the openstack.org site. For the rules regarding other uses of OpenStack trademarks, see the OpenStack Trademark Policy http://www.openstack.org/brand/openstack-trademark-policy/ and the OpenStack Brand Guide http://www.openstack.org/brand/. Please contact logo@openstack.org with any questions.
LICENSE:
Unless otherwise noted, all code is released under the APACHE 2.0 License
http://www.apache.org/licenses/LICENSE-2.0.html
WHO DO I CONTACT WITH QUESTIONS?
For now we will continue to use Lanchpad bugs to track issues: https://bugs.launchpad.net/openstack-org/
WHAT'S INCLUDED
Included in this repository are:
Third Party:
- The Silverstripe CMS v 3.1.x (for easy of deployment)
WHAT'S NOT INCLUDED
- Images - You'll note many missing images throughout the site. This is due to one of the following: trademark restrictions (see above), copyright restrictions, OpenStack sponsors, file size restrictions.
REQUIREMENTS FOR DEPLOYING OPENSTACK.ORG
To run the openstack.org website, the server environment needs:
- Apache 1.3 or greater
- PHP 5.2.0 or greater
- MySQL 5.0 or greater
INSTALLATION
openstack.org website uses composer (https://getcomposer.org/) to manage all dependencies
to install run following commands
* curl -sS https://getcomposer.org/installer | php
* php composer.phar install
* php composer.phar dump-autoload --optimize
* chmod 777 -R vendor/ezyang/htmlpurifier/library/HTMLPurifier/DefinitionCache/Serializer
DATABASE
OpenStack will provide a db dump on a weekly basis, purged of protected data. The dump can be found https://mycloud.rackspace.com/cloud/920805/files#object-store%2CcloudFiles%2CDFW/www.openstack.org-cron-db-backups-purged/. The database will create one default admin user. All other data will need to be populated by the user.
TODO:
We need detailed installation instructions to run the site locally on LAMP or MAMP.
SUBMITTING PATCHES:
We welcome patches and will be reviewing those as they come in initially, and plan to move to gerrit for reviews in the future.

View File

@ -0,0 +1,18 @@
<?php
/**
* Copyright 2014 Openstack.org
* Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
**/
define('CHANGE_PASSWORD_EMAIL_FROM','noreply@openstack.org');
define('CHANGE_PASSWORD_EMAIL_SUBJECT','OpenStack Profile Password Recovery');
Object::useCustomClass('Member_ForgotPasswordEmail', 'CustomMember_ForgotPasswordEmail');

View File

@ -0,0 +1,7 @@
---
Name: changepasswordoutes
After: 'framework/routes#coreroutes'
---
Director:
rules:
'Security//$Action/$ID/$OtherID': 'CustomPasswordController'

View File

@ -0,0 +1,27 @@
<?php
/**
* Copyright 2014 Openstack.org
* Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
**/
/**
* Class CustomMember_ForgotPasswordEmail
*/
final class CustomMember_ForgotPasswordEmail extends Member_ForgotPasswordEmail {
protected $from = ''; // setting a blank from address uses the site's default administrator email
protected $subject = '';
protected $ss_template = 'CustomForgotPasswordEmail';
function __construct() {
parent::__construct();
$this->subject = _t('Member.SUBJECTPASSWORDRESET', "Your password reset link", PR_MEDIUM, 'Email subject');
}
}

View File

@ -0,0 +1,69 @@
<?php
/**
* Copyright 2014 Openstack.org
* Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
**/
/**
* Class PasswordManager
*/
final class PasswordManager {
/**
* @param int $member_id
* @param string $token
* @throws InvalidPasswordResetLinkException
* @return bool
*/
public function verifyToken($member_id, $token){
if (is_null($member_id) || $member_id == 0 || empty($token)){
throw new InvalidPasswordResetLinkException;
}
//get member
$member = Member::get()->byId($member_id);
//check if token already was used...
if(!$member || !$member->validateAutoLoginToken($token)){
throw new InvalidPasswordResetLinkException;
}
$current_member = Member::currentUser();
if($current_member && $member->ID !== $current_member->ID){
throw new InvalidPasswordResetLinkException;
}
return $member->encryptWithUserSettings($token);
}
/**
* @param string $token
* @param string $password
* @param string $password_confirmation
* @throws InvalidResetPasswordTokenException
* @throws EmptyPasswordException
* @throws InvalidPasswordException
* @throws PasswordMismatchException
*/
public function changePassword($token, $password, $password_confirmation){
if(empty($token)) throw new InvalidResetPasswordTokenException;
$member = Member::member_from_autologinhash($token);
if(!$member) throw new InvalidResetPasswordTokenException;
if(empty($password)) throw new EmptyPasswordException;
if($password !== $password_confirmation) throw new PasswordMismatchException;
$isValid = $member->changePassword($password);
if(!$isValid->valid()) throw new InvalidPasswordException($isValid->starredList());
$member->logIn();
//invalidate former auto login token
$member->generateAutologinTokenAndStoreHash();
//send confirmation email
$email = EmailFactory::getInstance()->buildEmail(CHANGE_PASSWORD_EMAIL_FROM, $member->Email, CHANGE_PASSWORD_EMAIL_SUBJECT);
$email->setTemplate('ChangedPasswordEmail');
$email->populateTemplate(array('MemberName' => $member->getFullName()));
$email->send();
}
}

View File

@ -0,0 +1,18 @@
<?php
/**
* Copyright 2014 Openstack.org
* Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
**/
/**
* Class EmptyPasswordException
*/
final class EmptyPasswordException extends Exception {
}

View File

@ -0,0 +1,18 @@
<?php
/**
* Copyright 2014 Openstack.org
* Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
**/
/**
* Class InvalidPasswordException
*/
final class InvalidPasswordException extends Exception {
}

View File

@ -0,0 +1,18 @@
<?php
/**
* Copyright 2014 Openstack.org
* Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
**/
/**
* Class InvalidPasswordResetLinkException
*/
final class InvalidPasswordResetLinkException extends Exception {
}

View File

@ -0,0 +1,18 @@
<?php
/**
* Copyright 2014 Openstack.org
* Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
**/
/**
* Class InvalidResetPasswordTokenException
*/
final class InvalidResetPasswordTokenException extends Exception {
}

View File

@ -0,0 +1,18 @@
<?php
/**
* Copyright 2014 Openstack.org
* Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
**/
/**
* Class PasswordMismatchException
*/
final class PasswordMismatchException extends Exception {
}

View File

@ -0,0 +1,69 @@
<?php
/**
* Copyright 2014 Openstack.org
* Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
**/
final class CustomChangePasswordForm extends ChangePasswordForm {
/**
* @var PasswordManager
*/
private $password_manager;
function __construct($controller, $name, $fields = null, $actions = null){
parent::__construct($controller, $name, $fields, $actions);
$this->fields->removeByName('OldPassword');
$this->password_manager = new PasswordManager;
}
/**
* Change the password
*
* @param array $data The user submitted data
*/
function doChangePassword(array $data) {
try{
$token = Session::get('AutoLoginHash');
$this->password_manager->changePassword($token,@$data['NewPassword1'],@$data['NewPassword2']);
Session::clear('AutoLoginHash');
if (isset($_REQUEST['BackURL']) && $_REQUEST['BackURL'] // absolute redirection URLs may cause spoofing
&& Director::is_site_url($_REQUEST['BackURL'])) {
Controller::curr()->redirect($_REQUEST['BackURL']);
}
else {
// Redirect to default location - the login form saying "You are logged in as..."
// $redirectURL = HTTP::setGetVar('BackURL', Director::absoluteBaseURL(), Security::Link('login'));
$redirectURL = '/direct-after-login/';
Controller::curr()->redirect($redirectURL);
}
}
catch(InvalidResetPasswordTokenException $ex1){
Session::clear('AutoLoginHash');
Controller::curr()->redirect('loginpage');
}
catch(EmptyPasswordException $ex2){
$this->clearMessage();
$this->sessionMessage(_t('Member.EMPTYNEWPASSWORD', "The new password can't be empty, please try again"),"bad");
Controller::curr()->redirectBack();
}
catch(PasswordMismatchException $ex3){
$this->clearMessage();
$this->sessionMessage(_t('Member.ERRORNEWPASSWORD', "You have entered your new password differently, try again"),"bad");
Controller::curr()->redirectBack();
}
catch(InvalidPasswordException $ex4){
$this->clearMessage();
$this->sessionMessage(sprintf(_t('Member.INVALIDNEWPASSWORD', "We couldn't accept that password: %s"), nl2br("\n".$ex4->getMessage())),"bad");
Controller::curr()->redirectBack();
}
}
}

View File

@ -0,0 +1,82 @@
<?php
/**
* Copyright 2014 Openstack.org
* Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
**/
/***
* Class CustomPasswordController
*/
class CustomPasswordController extends Security {
private static $allowed_actions = array(
'changepassword',
'ChangePasswordForm',
);
/**
* @var PasswordManager
*/
private $password_manager;
public function __construct(){
parent::__construct();
$this->password_manager = new PasswordManager;
}
/**
* Factory method for the lost password form
*
* @return Form Returns the lost password form
*/
public function ChangePasswordForm() {
return new CustomChangePasswordForm($this, 'ChangePasswordForm');
}
/**
* @return string
*/
public function changepassword() {
$tmpPage = new Page();
$tmpPage->Title = _t('Security.CHANGEPASSWORDHEADER', 'Change your password');
$tmpPage->URLSegment = 'Security';
$tmpPage->ID = -1; // Set the page ID to -1 so we dont get the top level pages as its children
$controller = new Page_Controller($tmpPage);
$controller->init();
try{
$former_hash = Session::get('AutoLoginHash');
if(!empty($former_hash)){
// Subsequent request after the "first load with hash"
$customisedController = $controller->customise(array(
'Content' =>
'<p>' .
_t('Security.ENTERNEWPASSWORD', 'Please enter a new password.') .
'</p>',
'Form' => $this->ChangePasswordForm(),
));
}
else{
$new_hash = $this->password_manager->verifyToken((int)@$_REQUEST['m'], @$_REQUEST['t']);
Session::set('AutoLoginHash', $new_hash);
return $this->redirect($this->Link('changepassword'));
}
}
catch(InvalidPasswordResetLinkException $ex1){
$customisedController = $controller->customise(
array('Content' =>
sprintf('<p>This link is no longer valid as a newer request for a password reset has been made. Please check your mailbox for the most recent link</p><p>You can request a new one <a href="%s">here',
$this->Link('lostpassword'))
)
);
}
return $customisedController->renderWith(array('Security_changepassword', 'Security', $this->stat('template_main'), 'ContentController'));
}
}

View File

@ -0,0 +1,6 @@
$MemberName,<br>
<p>
Your OpenStack.org Member Profile password was just reset. If you did not take this action, please email <a href="mailto:info@openstack.org">info@openstack.org</a> with your memberID and concerns.
</p>
Thank you,<br>
OpenStack Foundation Staff<br>

View File

@ -0,0 +1,8 @@
<div id="content-body">
<h1 id="page-title">$MenuTitle.XML</h1>
<% if CurrentMember %>
<div class="loggedInBox">You are logged in as: <strong>$CurrentMember.Name</strong>&nbsp; &nbsp; <a class="roundedButton" href="{$Link}logout/">Logout</a></p>
<% end_if %>
$Content
$Form
</div>

View File

@ -0,0 +1,4 @@
<p><% _t('HELLO', 'Hi') %> $FirstName,</p>
<p><% _t('TEXT1', 'Here is your') %> <a href="$PasswordResetLink"><% _t('TEXT2', 'password reset link') %></a> for the OpenStack website.</p>

23
composer.json Normal file
View File

@ -0,0 +1,23 @@
{
"name": "silverstripe/installer",
"description": "The SilverStripe Framework Installer",
"require": {
"php": ">=5.3.2",
"silverstripe/cms": "3.1.5",
"silverstripe/framework": "3.1.5",
"silverstripe/translatable": "2.0.3",
"ezyang/htmlpurifier": "dev-master",
"undefinedoffset/sortablegridfield":"dev-master",
"tractorcow/silverstripe-colorpicker":"3.0.*@dev"
},
"autoload": {
"classmap": [
"geoip/code",
"html2pdf_v4.03"
]
},
"config": {
"process-timeout": 600
},
"minimum-stability": "dev"
}

13
datepicker/_config.php Normal file
View File

@ -0,0 +1,13 @@
<?php
/**
* Copyright 2014 Openstack.org
* Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
**/

View File

@ -0,0 +1,96 @@
<?php
/**
* Copyright 2014 Openstack.org
* Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
**/
require_once 'Zend/Date.php';
class JQueryUIDatePickerField extends TextField {
private $data_dependant;
protected $locale = null;
protected $valueObj = null;
public function __construct($name, $title = null, $value = '', $form = null,$data_dependant=""){
$this->data_dependant = $data_dependant;
if(!$this->locale) {
$this->locale = i18n::get_locale();
}
parent::__construct($name, $title, $value, 6, $form);
}
function Field() {
$this->addExtraClass('DatePickerField');
Requirements::block(SAPPHIRE_DIR .'/thirdparty/jquery/jquery.js');
Requirements::css("themes/openstack/javascript/jquery-ui-1.10.3.custom/css/smoothness/jquery-ui-1.10.3.custom.min.css");
Requirements::javascript('themes/openstack/javascript/jquery-2.0.3.min.js');
Requirements::javascript('themes/openstack/javascript/jquery-migrate-1.2.1.min.js');
Requirements::javascript("themes/openstack/javascript/jquery-ui-1.10.3.custom/js/jquery-ui-1.10.3.custom.min.js");
Requirements::javascript("datepicker/javascript/datepicker.js");
$attributes = array(
'type' => 'text',
'class' => 'text' . ($this->extraClass() ? $this->extraClass() : ''),
'id' => $this->id(),
'name' => $this->Name(),
'value' => $this->Value(),
'tabindex' => $this->getTabIndex(),
'maxlength' => ($this->maxLength) ? $this->maxLength : null,
'size' => ($this->maxLength) ? min( $this->maxLength, 10 ) : null,
);
if(!empty($this->data_dependant)){
$attributes["data-dependant-on"] = $this->data_dependant;
}
if($this->disabled) $attributes['disabled'] = 'disabled';
return $this->createTag('input', $attributes);
}
/**
* Sets the internal value to ISO date format.
*
* @param String|Array $val
*/
function setValue($val) {
if(empty($val)) {
$this->value = null;
$this->valueObj = null;
} else {
// Quick fix for overzealous Zend validation, its case sensitive on month names (see #5990)
if(is_string($val)) $val = ucwords(strtolower($val));
// load ISO date from database (usually through Form->loadDataForm())
if(!empty($val) && Zend_Date::isDate($val, 'yyyy-MM-dd')) {
$this->valueObj = new Zend_Date($val, 'yyyy-MM-dd');
$this->value = $this->valueObj->get('yyyy-MM-dd', $this->locale);
}
else {
$this->value = $val;
$this->valueObj = null;
}
}
}
/**
* @return String ISO 8601 date, suitable for insertion into database
*/
function dataValue() {
if($this->valueObj) {
return $this->valueObj->toString('yyyy-MM-dd');
} else {
return null;
}
}
}

View File

@ -0,0 +1,54 @@
/**
* Copyright 2014 Openstack.org
* Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
**/
var DatePickerFieldHandler = function(){
var $ = jQuery;
this.initAll = function(){
var fnc = this.initById;
$('.DatePickerField').each(function(){
fnc('#' + $(this).attr('id'));
});
}
this.initById = function(id){
var date_picker = $(id);
date_picker.datepicker({
dateFormat: 'yy-mm-dd',
onSelect:function(text,inst){
var dependant = $(this).attr('data-dependant-on');
if(dependant){
var date_dependant = $('#'+dependant);
date_dependant.val($(this).val());
}
}
});
}
}
datePickerFieldHandler = new DatePickerFieldHandler();
//check if prototype wrapper is required.
if(typeof Behaviour == 'object'){
Behaviour.register({
'.DatePickerField' : {
initialise : function(){
datePickerFieldHandler.initById('#' + this.id);
}
}
});
}
jQuery(document).ready(function(){
datePickerFieldHandler.initAll();
});

17
elections/_config.php Normal file
View File

@ -0,0 +1,17 @@
<?php
/**
* Copyright 2014 Openstack.org
* Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
**/
Object::add_extension('Member', 'FoundationMember');
define('REVOCATION_NOTIFICATION_EMAIL_SUBJECT','OpenStack Foundation notice: your Foundation Membership will end in 30 days.');
define('ELECTION_VOTERS_INGEST_PATH','elections/input');

View File

@ -0,0 +1,7 @@
---
Name: electionroutes
After: 'framework/routes#coreroutes'
---
Director:
rules:
'revocation-notifications' : 'RevocationNotificationAction_Controller'

View File

@ -0,0 +1,49 @@
<?php
/**
* Copyright 2014 Openstack.org
* Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
**/
/**
* Class Election
*/
final class Election extends DataObject implements IElection {
static $create_table_options = array('MySQLDatabase' => 'ENGINE=InnoDB');
static $db = array(
'ElectionsOpen' => 'Date', // The day elections start
'ElectionsClose' => 'Date', // The day they close
);
/**
* @return DateTime
*/
public function startDate()
{
return new DateTime($this->getField('ElectionsOpen'));
}
/**
* @return DateTime
*/
public function endDate()
{
return new DateTime($this->getField('ElectionsClose'));
}
/**
* @return int
*/
public function getIdentifier()
{
return (int)$this->getField('ID');
}
}

View File

@ -0,0 +1,108 @@
<?php
/**
* Copyright 2014 Openstack.org
* Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
**/
/**
* Class FoundationMember
*/
final class FoundationMember
extends DataExtension
implements IFoundationMember, ICommunityMember {
static $has_many = array(
'RevocationNotifications' => 'FoundationMemberRevocationNotification',
'Votes' => 'Vote'
);
/**
* @return int
*/
public function getIdentifier()
{
return (int)$this->owner->getField('ID');
}
public function convert2SiteUser(){
$this->resign();
$this->owner->addToGroupByCode(IFoundationMember::CommunityMemberGroupSlug);
}
public function isFoundationMember(){
$res = false;
$res = $this->owner->inGroup(IFoundationMember::FoundationMemberGroupSlug);
$legal_agreements = DataObject::get("LegalAgreement", " LegalDocumentPageID=422 AND MemberID =" . $this->owner->ID);
$res = $res && $legal_agreements->count() > 0;
return $res;
}
public function upgradeToFoundationMember(){
if(!$this->isFoundationMember()){
// Assign the member to be part of the foundation group
$this->owner->addToGroupByCode(IFoundationMember::FoundationMemberGroupSlug);
// Set up member with legal agreement for becoming an OpenStack Foundation Member
$legalAgreement = new LegalAgreement();
$legalAgreement->MemberID = $this->owner->ID;
$legalAgreement->LegalDocumentPageID = 422;
$legalAgreement->write();
return true;
}
return false;
}
/**
* @param int $latest_election_id
* @return bool
*/
public function hasPendingRevocationNotifications($latest_election_id)
{
}
/**
*
*/
public function resign(){
// Remove member from Foundation group
foreach($this->owner->Groups() as $g){
$this->owner->Groups()->remove($g->ID);
}
// Remove member mamaged companies
foreach($this->owner->ManagedCompanies() as $c){
$this->owner->ManagedCompanies()->remove($c->ID);
}
// Remove Member's Legal Agreements
$legal_agreements = $this->owner->LegalAgreements();
if($legal_agreements)
foreach($legal_agreements as $document) {
$document->delete();
}
// Remove Member's Affiliations
$affiliations = $this->owner->Affiliations();
if($legal_agreements)
foreach($affiliations as $affiliation) {
$affiliation->delete();
}
}
/**
* @return bool
*/
public function isCommunityMember() {
$group = $this->owner->inGroup(IFoundationMember::CommunityMemberGroupSlug);
$is_speaker = DataObject::get_one('Speaker', 'MemberID = '. $this->owner->ID);
$is_foundation_member = $this->isFoundationMember();
return $group || $is_speaker || $is_foundation_member;
}
}

View File

@ -0,0 +1,187 @@
<?php
/**
* Copyright 2014 Openstack.org
* Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
**/
/**
* Class FoundationMemberRevocationNotification
*/
final class FoundationMemberRevocationNotification
extends DataObject
implements IFoundationMemberRevocationNotification {
static $create_table_options = array('MySQLDatabase' => 'ENGINE=InnoDB');
static $db = array(
'Action' => "Enum('None, Renew, Revoked, Resign','None')",
'ActionDate' => 'SS_Datetime',
'SentDate' => 'SS_Datetime',
'Hash' => 'Text',
);
static $has_one = array(
'LastElection' => 'Election',
'Recipient' => 'Member',
);
protected function onBeforeWrite() {
parent::onBeforeWrite();
$this->setField('SentDate',gmdate('Y-m-d H:i:s'));
}
/**
* @return int
*/
public function getIdentifier()
{
return (int)$this->getField('ID');
}
/**
* @return string
*/
public function action()
{
return (string)$this->getField('Action');
}
/**
* @return DateTime
*/
public function actionDate()
{
if($this->isExpired() && $this->action()=='None')
return $this->expirationDate();
$date = $this->getField('ActionDate');
return new DateTime($date);
}
/**
* @return DateTime
*/
public function sentDate()
{
$date = $this->getField('SentDate');
return new DateTime($date);
}
/**
* @return bool
*/
public function isExpired()
{
$date = new DateTime('now',new DateTimeZone("UTC"));
$date = $date->sub(new DateInterval('P'.IFoundationMemberRevocationNotification::DaysBeforeRevocation.'D'));
$sent_date = $this->sentDate();
return $sent_date <= $date;
}
/**
* @param IElection $latest_election
* @return void
*/
public function renew(IElection $latest_election)
{
AssociationFactory::getInstance()->getMany2OneAssociation($this,'LastElection')->setTarget($latest_election);
$this->setField('Action','Renew');
$this->setField('ActionDate',gmdate('Y-m-d H:i:s'));
}
/**
* @return void
*/
public function revoke()
{
$member = $this->recipient();
$member->convert2SiteUser();
$this->setField('Action','Revoked');
$this->setField('ActionDate',gmdate('Y-m-d H:i:s'));
}
public function resign(){
$member = $this->recipient();
$member->resign();
$this->setField('Action','Resign');
$this->setField('ActionDate',gmdate('Y-m-d H:i:s'));
}
/**
* @return IFoundationMember
*/
public function recipient()
{
return AssociationFactory::getInstance()->getMany2OneAssociation($this,'Recipient')->getTarget();
}
/**
* @return string
*/
public function hash()
{
return (string)$this->getField('Hash');
}
/**
* @return string
*/
public function generateHash()
{
$generator = new RandomGenerator();
$token = $generator->randomToken();
$hash = self::HashConfirmationToken($token);
$this->setField('Hash',$hash);
return $token;
}
public static function HashConfirmationToken($token){
return md5($token);
}
/**
* @return IElection
*/
public function latestElection()
{
return AssociationFactory::getInstance()->getMany2OneAssociation($this,'LastElection')->getTarget();
}
/**
* @return int
*/
public function remainingDays() {
$send_date = $this->sentDate();
$void_date = $send_date->add(new DateInterval('P'.IFoundationMemberRevocationNotification::DaysBeforeRevocation.'D'));
$diff = (int)$void_date->diff($send_date)->format("%a");
return IFoundationMemberRevocationNotification::DaysBeforeRevocation - $diff;
}
/**
* @return DateTime
*/
public function expirationDate()
{
$sent_date = $this->sentDate();
$void_date = $sent_date->add(new DateInterval('P'.IFoundationMemberRevocationNotification::DaysBeforeRevocation.'D'));
return $void_date;
}
/**
* @return bool
*/
public function isValid()
{
if($this->isExpired()) return false;
$action = $this->getField('Action');
return $action == 'None';
}
}

View File

@ -0,0 +1,67 @@
<?php
/**
* Copyright 2014 Openstack.org
* Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
**/
/**
* Class Vote
*/
final class Vote
extends DataObject
implements IVote {
static $create_table_options = array('MySQLDatabase' => 'ENGINE=InnoDB');
static $db = array(
);
static $has_one = array(
'Voter' => 'Member',
'Election' => 'Election',
);
static $indexes = array(
'Voter_Election' => array('type'=>'unique', 'value'=>'VoterID,ElectionID'),
);
/**
* @return int
*/
public function getIdentifier()
{
return (int)$this->getField('ID');
}
/**
* @return IFoundationMember
*/
public function voter()
{
return AssociationFactory::getInstance()->getMany2OneAssociation($this,'Voter')->getTarget();
}
/**
* @return IElection
*/
public function election()
{
return AssociationFactory::getInstance()->getMany2OneAssociation($this,'Election')->getTarget();
}
/**
* @return DateTime
*/
public function date()
{
// TODO: Implement date() method.
}
}

View File

@ -0,0 +1,44 @@
<?php
/**
* Copyright 2014 Openstack.org
* Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
**/
/**
* Class VoterFile
*/
final class VoterFile extends DataObject implements IVoterFile {
static $create_table_options = array('MySQLDatabase' => 'ENGINE=InnoDB');
static $db = array(
'FileName' => 'Varchar(255)',
);
static $indexes = array(
'FileName' => array('type'=>'unique', 'value'=>'FileName'),
);
/**
* @return int
*/
public function getIdentifier()
{
return (int)$this->getField('ID');
}
/**
* @return string
*/
public function name()
{
return (string)$this->getField('FileName');
}
}

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