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-2013, 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 array $package_id 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;
89 * @param bool $package_id
91 * @internal param \The $object Group object to which this FRSPackage is associated.
92 * @internal param \The $int package_id.
93 * @internal param \The $array associative array of data.
96 function __construct(&$Group, $package_id = false, $arr = false) {
98 if (!$Group || !is_object($Group)) {
99 $this->setError(_('No Valid Group Object'));
102 if ($Group->isError()) {
103 $this->setError('FRSPackage: '.$Group->getErrorMessage());
106 $this->Group =& $Group;
109 if (!$arr || !is_array($arr)) {
110 if (!$this->fetchData($package_id)) {
114 $this->data_array =& $arr;
115 if ($this->data_array['group_id'] != $this->Group->getID()) {
116 $this->setError(_('group_id in db result does not match Group Object'));
117 $this->data_array = null;
121 // Add an is_public check here
128 * create - create a new FRSPackage in the database.
131 * @param int $is_public
132 * @internal param \The $string name of this package.
133 * @internal param \Whether $boolean it's public or not. 1=public 0=private.
134 * @return boolean success.
136 function create($name, $is_public = 1) {
138 if (strlen($name) < 3) {
139 $this->setError(_('FRSPackage Name Must Be At Least 3 Characters'));
142 if (!util_is_valid_filename($name)) {
143 $this->setError(_('Package Name can only be alphanumeric'));
145 if (!forge_check_perm ('frs', $this->Group->getID(), 'write')) {
146 $this->setPermissionDeniedError();
150 $res = db_query_params ('SELECT * FROM frs_package WHERE group_id=$1 AND name=$2',
151 array ($this->Group->getID(),
152 htmlspecialchars($name))) ;
153 if (db_numrows($res)) {
154 $this->setError(_('Error Adding Package: Name Already Exists'));
159 $result = db_query_params ('INSERT INTO frs_package(group_id,name,status_id,is_public) VALUES ($1,$2,$3,$4)',
160 array ($this->Group->getId(),
161 htmlspecialchars($name),
165 $this->setError(_('Error Adding Package: ').db_error());
169 $this->package_id=db_insertid($result,'frs_package','package_id');
170 if (!$this->fetchData($this->package_id)) {
175 //make groupdir if it doesn't exist
176 $groupdir = forge_get_config('upload_dir').'/'.$this->Group->getUnixName();
177 if (!is_dir($groupdir)) {
181 $newdirlocation = $groupdir.'/'.$this->getFileName();
182 if (!is_dir($newdirlocation)) {
183 @mkdir($newdirlocation);
186 // 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
187 @chown($newdirlocation, forge_get_config('apache_user'));
188 @chgrp($newdirlocation, forge_get_config('apache_group'));
195 * fetchData - re-fetch the data for this Package from the database.
197 * @param int $package_id The package_id.
198 * @return boolean success.
200 function fetchData($package_id) {
201 $res = db_query_params ('SELECT * FROM frs_package WHERE package_id=$1 AND group_id=$2',
203 $this->Group->getID())) ;
204 if (!$res || db_numrows($res) < 1) {
205 $this->setError(_('Invalid package_id'));
208 $this->data_array = db_fetch_array($res);
209 db_free_result($res);
214 * getGroup - get the Group object this FRSPackage is associated with.
216 * @return object The Group object.
218 function &getGroup() {
223 * getID - get this package_id.
225 * @return int The id of this package.
228 return $this->data_array['package_id'];
232 * getName - get the name of this package.
234 * @return string The name of this package.
237 return $this->data_array['name'];
241 * getFileName - get the filename of this package.
243 * @return string The name of this package.
245 function getFileName() {
246 return util_secure_filename($this->data_array['name']);
250 * getStatus - get the status of this package.
252 * @return int The status.
254 function getStatus() {
255 return $this->data_array['status_id'];
259 * isPublic - whether non-group-members can view.
261 * @return boolean is_public.
263 function isPublic() {
264 return $this->data_array['is_public'];
268 * setMonitor - Add the current user to the list of people monitoring this package.
270 * @return boolean success.
272 function setMonitor() {
273 if (!session_loggedin()) {
274 $this->setError(_('You can only monitor if you are logged in.'));
277 $result = db_query_params ('SELECT * FROM filemodule_monitor WHERE user_id=$1 AND filemodule_id=$2',
281 if (!$result || db_numrows($result) < 1) {
283 User is not already monitoring thread, so
284 insert a row so monitoring can begin
286 $result = db_query_params ('INSERT INTO filemodule_monitor (filemodule_id,user_id) VALUES ($1,$2)',
287 array ($this->getID(),
291 $this->setError(_('Unable to add monitor: ').db_error());
300 * stopMonitor - Remove the current user from the list of people monitoring this package.
302 * @return boolean success.
304 function stopMonitor() {
305 if (!session_loggedin()) {
306 $this->setError(_('You can only monitor if you are logged in.'));
309 return db_query_params ('DELETE FROM filemodule_monitor WHERE user_id=$1 AND filemodule_id=$2',
315 * getMonitorCount - Get the count of people monitoring this package
317 * @return int the count
319 function getMonitorCount() {
320 $res = db_result(db_query_params ('select count(*) as count from filemodule_monitor where filemodule_id=$1',
321 array ($this->getID())), 0, 0);
323 $this->setError(_('Error On querying monitor count: ').db_error());
330 * isMonitoring - Is the current user in the list of people monitoring this package.
332 * @return boolean is_monitoring.
334 function isMonitoring() {
335 if (!session_loggedin()) {
339 $result = db_query_params ('SELECT * FROM filemodule_monitor WHERE user_id=$1 AND filemodule_id=$2',
343 if (!$result || db_numrows($result) < 1) {
351 * getMonitorIDs - Return an array of user_id's of the list of people monitoring this package.
353 * @return array The array of user_id's.
355 function &getMonitorIDs() {
356 $res = db_query_params ('SELECT user_id FROM filemodule_monitor WHERE filemodule_id=$1',
357 array ($this->getID())) ;
358 return util_result_column_to_array($res);
362 * update - update an FRSPackage in the database.
364 * @param string The name of this package.
365 * @param int The status_id of this package from frs_status table.
366 * @param int public or private : 1 or 0
367 * @return boolean success.
369 function update($name, $status, $is_public = 1) {
370 if (strlen($name) < 3) {
371 $this->setError(_('FRSPackage Name Must Be At Least 3 Characters'));
375 if (!forge_check_perm('frs', $this->Group->getID(), 'write')) {
376 $this->setPermissionDeniedError();
379 if($this->getName()!=htmlspecialchars($name)) {
380 $res = db_query_params ('SELECT * FROM frs_package WHERE group_id=$1 AND name=$2',
381 array ($this->Group->getID(),
382 htmlspecialchars($name))) ;
383 if (db_numrows($res)) {
384 $this->setError(_('Error Updating Package: Name Already Exists'));
389 $res = db_query_params('UPDATE frs_package SET name=$1, status_id=$2, is_public=$3 WHERE group_id=$4 AND package_id=$5',
390 array (htmlspecialchars($name),
393 $this->Group->getID(),
395 if (!$res || db_affected_rows($res) < 1) {
396 $this->setError(sprintf(_('Error On Update: %s'), db_error()));
401 $olddirname = $this->getFileName();
402 if(!$this->fetchData($this->getID())){
403 $this->setError(_("Error Updating Package: Couldn't fetch data"));
407 $newdirname = $this->getFileName();
408 $olddirlocation = forge_get_config('upload_dir').'/'.$this->Group->getUnixName().'/'.$olddirname;
409 $newdirlocation = forge_get_config('upload_dir').'/'.$this->Group->getUnixName().'/'.$newdirname;
411 if(($olddirname!=$newdirname)){
412 if(is_dir($newdirlocation)){
413 $this->setError(_('Error Updating Package: Directory Already Exists'));
417 if(!@rename($olddirlocation,$newdirlocation)) {
418 $this->setError(_("Error Updating Package: Couldn't rename dir"));
425 $this->createNewestReleaseFilesAsZip();
430 * getReleases - gets Release objects for all the releases in this package.
432 * return array Array of FRSRelease Objects.
434 function &getReleases() {
435 if (!is_array($this->package_releases) || count($this->package_releases) < 1) {
436 $this->package_releases=array();
437 $res = db_query_params ('SELECT * FROM frs_release WHERE package_id=$1',
438 array ($this->getID())) ;
439 while ($arr = db_fetch_array($res)) {
440 $this->package_releases[]=$this->newFRSRelease($arr['release_id'],$arr);
443 return $this->package_releases;
447 * newFRSRelease - generates a FRSRelease (allows overloading by subclasses)
449 * @param string FRS release identifier
450 * @param array fetched data from the DB
451 * @return FRSRelease new FRSFile object.
453 protected function newFRSRelease($release_id, $data) {
454 return new FRSRelease($this,$release_id, $data);
458 * delete - delete this package and all its related data.
460 * @param bool I'm Sure.
461 * @param bool I'm REALLY sure.
462 * @return bool true/false;
464 function delete($sure, $really_sure) {
465 if (!$sure || !$really_sure) {
466 $this->setMissingParamsError(_('Please tick all checkboxes.'));
469 if (!forge_check_perm ('frs', $this->Group->getID(), 'write')) {
470 $this->setPermissionDeniedError();
473 $r =& $this->getReleases();
474 for ($i=0; $i<count($r); $i++) {
475 if (!is_object($r[$i]) || $r[$i]->isError() || !$r[$i]->delete($sure, $really_sure)) {
476 $this->setError(_('Release Error: ').$r[$i]->getName().':'.$r[$i]->getErrorMessage());
480 $dir=forge_get_config('upload_dir').'/'.
481 $this->Group->getUnixName() . '/' .
482 $this->getFileName().'/';
484 // double-check we're not trying to remove root dir
485 if (util_is_root_dir($dir)) {
486 $this->setError(_('Package delete error: trying to delete root dir'));
489 $this->deleteNewestReleaseFilesAsZip();
494 db_query_params ('DELETE FROM frs_package WHERE package_id=$1 AND group_id=$2',
495 array ($this->getID(),
496 $this->Group->getID())) ;
501 * Function that selects the newest release.
502 * The newest release is the release with the highest ID
504 * @return object FRSRelease
507 function getNewestRelease() {
508 $result = db_query_params('SELECT MAX(release_id) AS release_id FROM frs_release WHERE package_id=$1',
509 array ($this->getID())) ;
511 if ($result && db_numrows($result) == 1) {
512 $row = db_fetch_array($result);
513 return frsrelease_get_object($row['release_id']);
515 $this->setError(_('No valid max release id'));
520 public function getNewestReleaseZipName() {
521 return $this->getFileName()."-latest.zip";
524 public function getNewestReleaseZipPath () {
525 return forge_get_config('upload_dir').'/'.$this->Group->getUnixName().'/'.$this->getFileName().'/'.$this->getNewestReleaseZipName();
528 public function createNewestReleaseFilesAsZip(){
529 $release = $this->getNewestRelease();
530 if ($release && class_exists('ZipArchive')) {
531 $zip = new ZipArchive();
532 $zipPath = $this->getNewestReleaseZipPath();
533 $filesPath = forge_get_config('upload_dir').'/'.$this->Group->getUnixName().'/'.$this->getFileName().'/'.$release->getFileName();
535 if ($zip->open($zipPath, ZIPARCHIVE::OVERWRITE)!==true) {
536 exit_error(_('Cannot open the file archive.').' '.$zipPath.'.');
539 $files = $release->getFiles();
541 foreach ($files as $f) {
542 $filePath = $filesPath.'/'.$f->getName();
543 $zip->addFile($filePath,$f->getName());
550 public function deleteNewestReleaseFilesAsZip() {
551 if (file_exists($this->getNewestReleaseZipPath()))
552 unlink($this->getNewestReleaseZipPath());
559 // c-file-style: "bsd"