3 * FusionForge file release system
5 * Copyright 2002, Tim Perdue/GForge, LLC
6 * Copyright 2009, Roland Mas
7 * Copyright (C) 2011-2012 Alain Peyrat - Alcatel-Lucent
8 * Copyright 2011, Franck Villaume - Capgemini
9 * Copyright 2012, Franck Villaume - TrivialDev
11 * This file is part of FusionForge. FusionForge is free software;
12 * you can redistribute it and/or modify it under the terms of the
13 * GNU General Public License as published by the Free Software
14 * Foundation; either version 2 of the Licence, or (at your option)
17 * FusionForge is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
22 * You should have received a copy of the GNU General Public License along
23 * with FusionForge; if not, write to the Free Software Foundation, Inc.,
24 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
27 require_once $gfcommon.'include/Error.class.php';
28 require_once $gfcommon.'frs/FRSRelease.class.php';
30 function get_frs_packages($Group) {
32 $res = db_query_params ('SELECT * FROM frs_package WHERE group_id=$1',
33 array ($Group->getID())) ;
34 if (db_numrows($res) > 0) {
35 while($arr = db_fetch_array($res)) {
36 $ps[]=new FRSPackage($Group, $arr['package_id'], $arr);
43 * Gets a FRSPackage object from the given package id
45 * @param int the package id
46 * @param array the DB handle if passed in (optional)
47 * @return object the FRSPackage object
49 function frspackage_get_object($package_id, $data=false) {
50 global $FRSPACKAGE_OBJ;
51 if (!isset($FRSPACKAGE_OBJ['_'.$package_id.'_'])) {
53 //the db result handle was passed in
55 $res = db_query_params ('SELECT * FROM frs_package WHERE package_id=$1',
56 array ($package_id)) ;
57 if (db_numrows($res)<1) {
60 $data = db_fetch_array($res);
62 $Group = group_get_object($data['group_id']);
63 $FRSPACKAGE_OBJ['_'.$package_id.'_']= new FRSPackage($Group,$data['package_id'],$data);
65 return $FRSPACKAGE_OBJ['_'.$package_id.'_'];
68 class FRSPackage extends Error {
71 * Associative array of data from db.
73 * @var array $data_array.
76 var $package_releases;
83 var $Group; //group object
88 * @param object The Group object to which this FRSPackage is associated.
89 * @param int The package_id.
90 * @param array The associative array of data.
91 * @return boolean success.
93 function FRSPackage(&$Group, $package_id=false, $arr=false) {
95 if (!$Group || !is_object($Group)) {
96 $this->setError('FRSPackage:: No Valid Group Object');
99 if ($Group->isError()) {
100 $this->setError('FRSPackage:: '.$Group->getErrorMessage());
103 $this->Group =& $Group;
106 if (!$arr || !is_array($arr)) {
107 if (!$this->fetchData($package_id)) {
111 $this->data_array =& $arr;
112 if ($this->data_array['group_id'] != $this->Group->getID()) {
113 $this->setError('Group_id in db result does not match Group Object');
114 $this->data_array=null;
118 // Add an is_public check here
126 * create - create a new FRSPackage in the database.
128 * @param string The name of this package.
129 * @param boolean Whether it's public or not. 1=public 0=private.
130 * @return boolean success.
132 function create($name, $is_public = 1) {
134 if (strlen($name) < 3) {
135 $this->setError(_('FRSPackage Name Must Be At Least 3 Characters'));
138 if (!util_is_valid_filename($name)) {
139 $this->setError(_('FRSPackage::Update: Package Name can only be alphanumeric or "-" "_" "+" "." "~"'));
141 if (!forge_check_perm ('frs', $this->Group->getID(), 'write')) {
142 $this->setPermissionDeniedError();
146 $res = db_query_params ('SELECT * FROM frs_package WHERE group_id=$1 AND name=$2',
147 array ($this->Group->getID(),
148 htmlspecialchars($name))) ;
149 if (db_numrows($res)) {
150 $this->setError('FRSPackage::create() Error Adding Package: Name Already Exists');
155 $result = db_query_params ('INSERT INTO frs_package(group_id,name,status_id,is_public) VALUES ($1,$2,$3,$4)',
156 array ($this->Group->getId(),
157 htmlspecialchars($name),
161 $this->setError('FRSPackage::create() Error Adding Package: '.db_error());
165 $this->package_id=db_insertid($result,'frs_package','package_id');
166 if (!$this->fetchData($this->package_id)) {
171 //make groupdir if it doesn't exist
172 $groupdir = forge_get_config('upload_dir').'/'.$this->Group->getUnixName();
173 if (!is_dir($groupdir)) {
177 $newdirlocation = $groupdir.'/'.$this->getFileName();
178 if (!is_dir($newdirlocation)) {
179 @mkdir($newdirlocation);
182 // this 2 should normally silently fail (because it's called with the apache user) but if it's root calling the create() method, then the owner and group for the directory should be changed
183 @chown($newdirlocation, forge_get_config('apache_user'));
184 @chgrp($newdirlocation, forge_get_config('apache_group'));
191 * fetchData - re-fetch the data for this Package from the database.
193 * @param int The package_id.
194 * @return boolean success.
196 function fetchData($package_id) {
197 $res = db_query_params ('SELECT * FROM frs_package WHERE package_id=$1 AND group_id=$2',
199 $this->Group->getID())) ;
200 if (!$res || db_numrows($res) < 1) {
201 $this->setError('FRSPackage::fetchData() Invalid package_id'.db_error());
204 $this->data_array = db_fetch_array($res);
205 db_free_result($res);
210 * getGroup - get the Group object this FRSPackage is associated with.
212 * @return object The Group object.
214 function &getGroup() {
219 * getID - get this package_id.
221 * @return int The id of this package.
224 return $this->data_array['package_id'];
228 * getName - get the name of this package.
230 * @return string The name of this package.
233 return $this->data_array['name'];
237 * getFileName - get the filename of this package.
239 * @return string The name of this package.
241 function getFileName() {
242 return util_secure_filename($this->data_array['name']);
246 * getStatus - get the status of this package.
248 * @return int The status.
250 function getStatus() {
251 return $this->data_array['status_id'];
255 * isPublic - whether non-group-members can view.
257 * @return boolean is_public.
259 function isPublic() {
260 return $this->data_array['is_public'];
264 * setMonitor - Add the current user to the list of people monitoring this package.
266 * @return boolean success.
268 function setMonitor() {
269 if (!session_loggedin()) {
270 $this->setError(_('You can only monitor if you are logged in'));
273 $result = db_query_params ('SELECT * FROM filemodule_monitor WHERE user_id=$1 AND filemodule_id=$2',
277 if (!$result || db_numrows($result) < 1) {
279 User is not already monitoring thread, so
280 insert a row so monitoring can begin
282 $result = db_query_params ('INSERT INTO filemodule_monitor (filemodule_id,user_id) VALUES ($1,$2)',
283 array ($this->getID(),
287 $this->setError('Unable to add monitor: '.db_error());
296 * stopMonitor - Remove the current user from the list of people monitoring this package.
298 * @return boolean success.
300 function stopMonitor() {
301 if (!session_loggedin()) {
302 $this->setError(_('You can only monitor if you are logged in'));
305 return db_query_params ('DELETE FROM filemodule_monitor WHERE user_id=$1 AND filemodule_id=$2',
311 * getMonitorCount - Get the count of people monitoring this package
313 * @return int the count
315 function getMonitorCount() {
316 $res = db_result(db_query_params ('select count(*) as count from filemodule_monitor where filemodule_id=$1',
317 array ($this->getID())), 0, 0);
319 $this->setError('FRSPackage::getMonitorCount() Error On querying monitor count: '.db_error());
326 * isMonitoring - Is the current user in the list of people monitoring this package.
328 * @return boolean is_monitoring.
330 function isMonitoring() {
331 if (!session_loggedin()) {
335 $result = db_query_params ('SELECT * FROM filemodule_monitor WHERE user_id=$1 AND filemodule_id=$2',
339 if (!$result || db_numrows($result) < 1) {
347 * getMonitorIDs - Return an array of user_id's of the list of people monitoring this package.
349 * @return array The array of user_id's.
351 function &getMonitorIDs() {
352 $res = db_query_params ('SELECT user_id FROM filemodule_monitor WHERE filemodule_id=$1',
353 array ($this->getID())) ;
354 return util_result_column_to_array($res);
358 * update - update an FRSPackage in the database.
360 * @param string The name of this package.
361 * @param int The status_id of this package from frs_status table.
362 * @param int public or private : 1 or 0
363 * @return boolean success.
365 function update($name, $status, $is_public = 1) {
366 if (strlen($name) < 3) {
367 $this->setError(_('FRSPackage Name Must Be At Least 3 Characters'));
371 if (!forge_check_perm('frs', $this->Group->getID(), 'write')) {
372 $this->setPermissionDeniedError();
375 if($this->getName()!=htmlspecialchars($name)) {
376 $res = db_query_params ('SELECT * FROM frs_package WHERE group_id=$1 AND name=$2',
377 array ($this->Group->getID(),
378 htmlspecialchars($name))) ;
379 if (db_numrows($res)) {
380 $this->setError('FRSPackage::update() Error Updating Package: Name Already Exists');
385 $res = db_query_params('UPDATE frs_package SET name=$1, status_id=$2, is_public=$3 WHERE group_id=$4 AND package_id=$5',
386 array (htmlspecialchars($name),
389 $this->Group->getID(),
391 if (!$res || db_affected_rows($res) < 1) {
392 $this->setError('FRSPackage::update() Error On Update: '.db_error());
397 $olddirname = $this->getFileName();
398 if(!$this->fetchData($this->getID())){
399 $this->setError("FRSPackage::update() Error Updating Package: Couldn't fetch data");
403 $newdirname = $this->getFileName();
404 $olddirlocation = forge_get_config('upload_dir').'/'.$this->Group->getUnixName().'/'.$olddirname;
405 $newdirlocation = forge_get_config('upload_dir').'/'.$this->Group->getUnixName().'/'.$newdirname;
407 if(($olddirname!=$newdirname)){
408 if(is_dir($newdirlocation)){
409 $this->setError('FRSPackage::update() Error Updating Package: Directory Already Exists');
413 if(!@rename($olddirlocation,$newdirlocation)) {
414 $this->setError("FRSPackage::update() Error Updating Package: Couldn't rename dir");
421 $this->createNewestReleaseFilesAsZip();
426 * getReleases - gets Release objects for all the releases in this package.
428 * return array Array of FRSRelease Objects.
430 function &getReleases() {
431 if (!is_array($this->package_releases) || count($this->package_releases) < 1) {
432 $this->package_releases=array();
433 $res = db_query_params ('SELECT * FROM frs_release WHERE package_id=$1',
434 array ($this->getID())) ;
435 while ($arr = db_fetch_array($res)) {
436 $this->package_releases[]=new FRSRelease($this,$arr['release_id'],$arr);
439 return $this->package_releases;
443 * delete - delete this package and all its related data.
445 * @param bool I'm Sure.
446 * @param bool I'm REALLY sure.
447 * @return bool true/false;
449 function delete($sure, $really_sure) {
450 if (!$sure || !$really_sure) {
451 $this->setMissingParamsError(_('Please tick all checkboxes.'));
454 if (!forge_check_perm ('frs', $this->Group->getID(), 'write')) {
455 $this->setPermissionDeniedError();
458 $r =& $this->getReleases();
459 for ($i=0; $i<count($r); $i++) {
460 if (!is_object($r[$i]) || $r[$i]->isError() || !$r[$i]->delete($sure, $really_sure)) {
461 $this->setError('Release Error: '.$r[$i]->getName().':'.$r[$i]->getErrorMessage());
465 $dir=forge_get_config('upload_dir').'/'.
466 $this->Group->getUnixName() . '/' .
467 $this->getFileName().'/';
469 // double-check we're not trying to remove root dir
470 if (util_is_root_dir($dir)) {
471 $this->setError('Package::delete error: trying to delete root dir');
474 $this->deleteNewestReleaseFilesAsZip();
479 db_query_params ('DELETE FROM frs_package WHERE package_id=$1 AND group_id=$2',
480 array ($this->getID(),
481 $this->Group->getID())) ;
486 * Function that selects the newest release.
487 * The newest release is the release with the highest ID
489 * @return object FRSRelease
492 function getNewestRelease() {
493 $result = db_query_params('SELECT MAX(release_id) AS release_id FROM frs_release WHERE package_id=$1',
494 array ($this->getID())) ;
496 if ($result && db_numrows($result) == 1) {
497 $row = db_fetch_array($result);
498 return frsrelease_get_object($row['release_id']);
500 $this->setError('FRSRelease:: No valid max release id');
505 public function getNewestReleaseZipName() {
506 return $this->getFileName()."-latest.zip";
509 public function getNewestReleaseZipPath () {
510 return forge_get_config('upload_dir').'/'.$this->Group->getUnixName().'/'.$this->getFileName().'/'.$this->getNewestReleaseZipName();
513 public function createNewestReleaseFilesAsZip(){
514 $release = $this->getNewestRelease();
516 $zip = new ZipArchive();
517 $zipPath = $this->getNewestReleaseZipPath();
518 $filesPath = forge_get_config('upload_dir').'/'.$this->Group->getUnixName().'/'.$this->getFileName().'/'.$release->getFileName();
520 if ($zip->open($zipPath, ZIPARCHIVE::OVERWRITE)!==true) {
521 exit_error(_('Cannot open the file archive.').' '.$zipPath.'.');
524 $files = $release->getFiles();
526 foreach ($files as $f) {
527 $filePath = $filesPath.'/'.$f->getName();
528 $zip->addFile($filePath,$f->getName());
535 public function deleteNewestReleaseFilesAsZip() {
536 if (file_exists($this->getNewestReleaseZipPath()))
537 unlink($this->getNewestReleaseZipPath());
544 // c-file-style: "bsd"