chaw / branches / master / models / project.php
history
<?php
/**
* Short description
*
* Long description
*
* Copyright 2008, Garrett J. Woodworth <gwoo@cakephp.org>
* Redistributions not permitted
*
* @copyright Copyright 2008, Garrett J. Woodworth
* @package chaw
* @subpackage chaw.models
* @since Chaw 0.1
* @license commercial
*
*/
class Project extends AppModel {
/**
* undocumented class variable
*
* @var string
*/
var $name = 'Project';
/**
* undocumented class variable
*
* @var string
*/
var $current = array();
/**
* undocumented class variable
*
* @var string
*/
var $Repo;
/**
* undocumented class variable
*
* @var string
*/
var $hooks = array(
'git' => array('pre-receive', 'post-receive'),
'svn' => array('pre-commit', 'post-commit')
);
/**
* undocumented class variable
*
* @var string
*/
var $repoTypes = array('Git', 'Svn');
/**
* undocumented class variable
*
* @var string
*/
var $messages = array('response' => null, 'debug' => null);
/**
* undocumented class variable
*
* @var string
*/
var $validate = array(
'name' => array(
'minimum' => array(
'rule' => array('minLength', 5),
'required' => true,
'message' => 'Must be at least 5 characters'
),
'unique' => array(
'rule' => 'isUnique',
'required' => true,
'message' => 'Required: Project must be unique'
)
),
'user_id' => array('notEmpty')
);
/**
* undocumented class variable
*
* @var string
*/
var $belongsTo = array('User');
/**
* undocumented class variable
*
* @var string
*/
var $hasMany = array('Permission');
/**
* undocumented class variable
*
* @var string
*/
var $__created = false;
/**
* undocumented function
*
* @param string $params
* @return void
*/
function initialize($params = array()) {
$this->recursive = -1;
$this->current = Configure::read('Project');
if (!empty($this->data['Project']['url'])) {
$params['project'] = $this->data['Project']['url'];
}
if (!empty($this->data['Project']['fork'])) {
$params['fork'] = $this->data['Project']['fork'];
}
if (!empty($params['project'])) {
extract($this->key($params));
$project = Cache::read($key, 'project');
if (empty($project)) {
$project = $this->find($conditions);
if (!empty($project)) {
Cache::write($key, $project, 'project');
}
}
}
if (empty($project)) {
$key = Configure::read('App.dir');
$project = Cache::read($key, 'project');
if (empty($project)) {
$project = $this->findById(1);
if (!empty($project)) {
Cache::write($key, $project, 'project');
}
}
}
if (!empty($this->data['Project'])) {
if (empty($project)) {
$project = array('Project' => array());
}
$project['Project'] = array_merge($project['Project'], $this->data['Project']);
}
if (empty($project['Project'])) {
Configure::write('Project', $this->current);
return false;
}
$this->current = array_merge($this->current, $project['Project']);
$repoType = strtolower($this->current['repo_type']);
if (!empty($this->data['Project']['remote'])) {
$this->current['remote'][$repoType] = $this->data['Project']['remote'];
}
if (is_string($this->current['remote'])) {
$this->current['remote'][$repoType] = $this->current['remote'];
}
$path = Configure::read("Content.{$repoType}");
$fork = null;
if (!empty($this->current['fork'])) {
$fork = 'forks' . DS . $this->current['fork'] . DS;
}
$this->current['repo'] = array(
'class' => 'repo.' . $this->current['repo_type'],
'type' => $repoType,
'chmod' => 0777,
'path' => $path . 'repo' . DS . $fork . $this->current['url'],
'working' => $path . 'working' . DS . $fork . $this->current['url'],
'remote' => is_string($this->current['remote']) ? $this->current['remote'] : $this->current['remote'][$repoType]
);
if ($repoType == 'git') {
$this->current['repo']['path'] .= '.git';
}
if (!empty($this->current['config']) && is_string($this->current['config']) && substr($this->current['config'], 0, 3) == "a:2") {
$this->current['config'] = unserialize($this->current['config']);
}
$this->id = $this->current['id'];
Configure::write('Project', $this->current);
App::import('Model', $this->current['repo']['class'], false);
$this->Repo = new $this->current['repo_type']($this->current['repo']);
return true;
}
/**
* undocumented function
*
* @return void
*/
function beforeValidate() {
if (!empty($this->data['Project']['name']) && empty($this->data['Project']['url'])) {
$this->data['Project']['url'] = Inflector::slug(strtolower($this->data['Project']['name']));
} else if (empty($this->data['Project']['name']) && !empty($this->data['Project']['url'])) {
$this->data['Project']['name'] = $this->current['name'];
}
if (!empty($this->data['Project']['id']) && $this->id == $this->data['Project']['id']) {
unset($this->validate['name']['minimum']);
}
return true;
}
/**
* undocumented function
*
* @return void
*/
function beforeSave() {
$this->createShell();
if (empty($this->data['Project']['fork'])) {
$this->data['Project']['fork'] = null;
}
if (empty($this->data['Project']['url'])) {
$this->invalidate('name', 'the project could not be created');
return false;
}
if (!empty($this->data['config'])) {
$this->data['Project']['config'] = array_merge($this->data['Project']['config'], $this->data['config']);
unset($this->data['config']);
}
if (!empty($this->data['Project']['config']) && is_array($this->data['Project']['config'])) {
$this->data['Project']['config'] = serialize($this->data['Project']['config']);
}
if (!empty($this->data['Project']['approved'])) {
if ($this->initialize() === false) {
return false;
}
if (!file_exists($this->current['repo']['path']) || !file_exists($this->current['repo']['working'])) {
$this->__created = $this->Repo->create(array(
'remote' => $this->current['repo']['remote'],
));
if ($this->__created !== true) {
$this->invalidate('repo_type', 'the repo could not be created');
return false;
}
}
}
if ($this->__created && !$this->id && (empty($this->data['Project']['username']) || empty($this->data['Project']['user_id']))) {
$this->invalidate('user', 'Invalid user');
return false;
}
return true;
}
/**
* undocumented function
*
* @param string $created
* @return void
*/
function afterSave($created) {
if (!empty($this->data['Project']['approved'])) {
$this->current['id'] = $this->id;
$hooksCreated = $this->createHooks($this->hooks[$this->Repo->type], array(
'project' => $this->data['Project']['url'],
'fork' => (!empty($this->data['Project']['fork'])) ? $this->data['Project']['fork'] : false,
'root' => Configure::read('Content.base')
));
if ($this->__created && $hooksCreated) {
foreach ($this->hooks[$this->Repo->type] as $hook) {
if ($hook === 'post-commit') {
$this->Repo->execute("env - {$this->Repo->path}/hooks/{$hook} {$this->Repo->path} 1");
}
if ($hook === 'post-receive') {
$this->Repo->execute("env - {$this->Repo->path}/hooks/{$hook} refs/heads/master");
}
}
}
$this->messages = array('response' => $this->Repo->response, 'debug' => $this->Repo->debug);
$Wiki = ClassRegistry::init('Wiki');
$Wiki->recursive = -1;
if (!$Wiki->field('slug', array('slug' => 'home', 'project_id' => $this->id))) {
$Wiki->addToTimeline = $this->addToTimeline;
$Wiki->create(array(
'slug' => 'home', 'active' => 1,
'project_id' => $this->id,
'last_changed_by' => $this->current['user_id'],
'content' => sprintf(__("##The home page for %s",true),$this->current['name'])
. "\n\n" . $this->current['description']
));
$Wiki->save();
}
$this->Permission->config($this->current);
if ($this->Permission->fileExists() !== true) {
$this->Permission->saveFile(array('Permission' => array(
'username' => "@admin"
)));
}
$this->permit(array(
'user' => $this->current['user_id'],
'group' => 'admin',
'count' => 1
));
if ($this->Repo->type == 'git' && $this->data['Project']['private'] == '0') {
touch($this->Repo->path . '/git-daemon-export-ok');
}
}
if (!empty($this->current['url'])) {
$conditions = array($this->current['url']);
$conditions[] = (!empty($this->current['fork'])) ? $this->current['fork'] : false;
$key = join('_', array_filter($conditions));
Cache::delete($key, 'project');
}
$this->__created = false;
}
/**
* undocumented function
*
* @return void
*/
function afterDelete() {
$CleanUp = new Folder($this->Repo->path);
if ($CleanUp->pwd() == $this->Repo->path && strpos($this->Repo->path, 'forks') !== false) {
$CleanUp->delete();
$CleanUp = new Folder($this->Repo->working);
if ($CleanUp->pwd() == $this->Repo->working) {
$CleanUp->delete();
}
$key = $this->key();
if (!empty($key)) {
Cache::delete($key['key'], 'project');
}
}
}
/**
* undocumented function
*
* @param string $hooks
* @param string $options
* @return void
*/
function createHooks($hooks, $options = array()) {
extract(array_merge(array('project' => null, 'fork' => null, 'root' => null), $options));
$result = array();
if (!empty($hooks)) {
foreach ((array)$hooks as $hook) {
if (!file_exists("{$this->Repo->path}/hooks/{$hook}")) {
$result[] = $this->Repo->hook($hook, array('project' => $project, 'fork' => $fork, 'root' => $root));
}
}
}
return $result;
}
/**
* undocumented function
*
* @param string $fields
* @param string $id
* @return void
*/
function read($fields = null, $id = null) {
$data = parent::read($fields, $id);
$data['Project']['config'] = unserialize($data['Project']['config']);
return $data;
}
/**
* undocumented function
*
* @param string $data
* @return void
*/
function createShell($data = array()) {
$template = CONFIGS . 'templates' . DS;
$chaw = Configure::read('Content.base');
if (file_exists($template . 'chaw') && !file_exists($chaw . 'chaw')) {
$console = array_pop(Configure::corePaths('cake')) . 'console' . DS;
ob_start();
include($template . 'chaw');
$data = ob_get_clean();
$File = new File($chaw . 'chaw', true, 0775);
@chmod($File->pwd(), 0775);
return $File->write($data);
}
return true;
}
/**
* undocumented function
*
* @param string $data
* @return void
*/
function fork($data = array()) {
$this->set($data);
if (empty($this->Repo)) {
return false;
}
$hasFork = $this->find(array(
'fork' => $this->data['Project']['fork'],
'url' => $this->current['url']
));
if (!empty($hasFork)) {
return false;
}
if ($this->Repo->fork($this->data['Project']['fork'], array('remote' => $this->current['repo']['remote']))) {
$this->__created = true;
$this->data['Project']['project_id'] = $this->id;
$this->data['Project']['name'] = $this->data['Project']['fork'] . "'s fork of " . $this->data['Project']['name'];
$this->data['Project']['username'] = $this->data['Project']['fork'];
$this->data['Project']['users_count'] = 1;
}
if (!empty($this->data['Project']['id'])) {
$this->id = null;
unset($this->data['Project']['id'], $this->data['Project']['created'], $this->data['Project']['modified']);
}
if ($data = $this->save()) {
$this->id = $data['Project']['project_id'];
$this->permit(array(
'user' => $data['Project']['user_id'],
'id' => $data['Project']['project_id'],
));
return $data;
}
return false;
}
/**
* undocumented function
*
* @return void
*/
function forks() {
$forks = $this->find('all', array(
'conditions' => array('Project.project_id' => $this->id),
'recursive' => -1
));
return Set::extract('/Project/id', $forks);
}
/**
* undocumented function
*
* @param string $id
* @param string $include
* @return void
*/
function all($id = null, $include = true) {
if (!$id) {
$id = $this->id;
}
if (!empty($this->current['fork'])) {
$id = $this->current['project_id'];
}
$conditions = array('Project.project_id' => $id);
if ($include) {
$conditions = array(
'OR' => array('Project.id' => $id, 'Project.project_id' => $id)
);
}
return $this->find('all', compact('conditions'));
}
/**
* undocumented function
*
* @param string $conditions
* @return void
*/
function users($conditions = array()) {
$scope = array('Permission.project_id' => $this->id, 'User.username !=' => null);
if (!empty($conditions)) {
$scope = array_merge($scope, (array)$conditions);
}
$users = $this->Permission->find('all', array(
'fields' => array('User.id', 'User.username'),
'conditions' => $scope
));
if (empty($users)) {
return array();
}
return array_filter(Set::combine($users, '/User/id', '/User/username'));
}
/**
* undocumented function
*
* @param string $user
* @param string $group
* @return void
*/
function permit($user, $group = null) {
$id = $this->id;
$count = 'Project.users_count + 1';
if (is_array($user)) {
extract($user);
}
$user = $this->Permission->user($user);
if (!$user || !$id) {
return false;
}
if (!$this->Permission->field('id', array('project_id' => $id, 'user_id' => $user))) {
$this->Permission->create(array(
'project_id' => $id,
'user_id' => $user,
'group' => $group
));
$this->Permission->save();
$this->recursive = -1;
$this->updateAll(
array('Project.users_count' => $count),
array('Project.id' => $id)
);
}
}
/**
* undocumented function
*
* @param string $data
* @param string $options
* @return void
*/
function isUnique($data, $options = array()) {
if (!empty($data['name'])) {
$test = $this->findByUrl(Inflector::slug(strtolower($data['name'])));
if (!empty($test) && $test['Project']['id'] != $this->id) {
return false;
}
return true;
}
if (!empty($data['url'])) {
$reserved = array('forks', 'users', 'comments', 'commits', 'dashboard', 'pages', 'permissions', 'repo', 'source', 'tickets', 'timeline', 'versions', 'wiki');
if (in_array($data['url'], $reserved)) {
$this->invalidate('name');
return false;
}
$test = $this->findByUrl($data['url']);
if (in_array($data['url'], $reserved) || !empty($test) && $test['Project']['id'] != $this->id) {
$this->invalidate('name');
return false;
}
return true;
}
}
/**
* undocumented function
*
* @param string $key
* @return void
*/
function ticket($key = null) {
if ($key == null) {
foreach ($this->current['config']['ticket'] as $key => $ticket) {
$array = array_map('trim', explode(',', $this->current['config']['ticket'][$key]));
$data[$key] = array_combine($array, $array);
}
return $data;
}
if (!empty($this->current['config']['ticket'][$key])) {
$data = array_map('trim', explode(',', $this->current['config']['ticket'][$key]));
return array_combine($data, $data);
}
}
/**
* undocumented function
*
* @param string $key
* @return void
*/
function groups($key = null) {
$result = array();
if (!empty($this->current['config']['groups'])) {
$groups = array_map('trim', explode(',', $this->current['config']['groups']));
$Inflector = Inflector::getInstance();
$groups = array_map(array($Inflector, 'slug'), $groups, array_fill(0, count($groups), '-'));
$result = array_combine($groups, $groups);
}
if (!isset($result['admin'])) {
$result['admin'] = 'admin';
}
if (!isset($result['user'])) {
$result['user'] = 'user';
}
arsort($result);
return $result;
}
/**
* undocumented function
*
* @return void
*/
function repoTypes() {
return array_combine($this->repoTypes, $this->repoTypes);
}
/**
* undocumented function
*
* @return void
*/
function from() {
$baseDomain = env('HTTP_BASE');
if ($baseDomain[0] === '.') {
$baseDomain = substr($baseDomain, 1);
}
$from = sprintf('<noreply@%s>', $baseDomain);
return $from;
}
/**
* undocumented function
*
* @param string $params
* @return void
*/
function key($params = array()) {
if (empty($params)) {
$params = $this->current;
}
if (empty($params['project'])) {
if (empty($params['url'])) {
return array();
}
$params['project'] = $params['url'];
}
$conditions['fork'] = null;
if (!empty($params['fork'])) {
$conditions['fork'] = $params['fork'];
}
$conditions['url'] = $params['project'];
$key = join('_', array_filter(array_values($conditions)));
return compact('key', 'conditions');
}
}
?>