3 * FusionForge file release system
5 * Copyright 2002, Tim Perdue/GForge, LLC
6 * Copyright 2009, Roland Mas
7 * Copyright (C) 2011 Alain Peyrat - Alcatel-Lucent
8 * Copyright 2011, Franck Villaume - Capgemini
10 * This file is part of FusionForge. FusionForge is free software;
11 * you can redistribute it and/or modify it under the terms of the
12 * GNU General Public License as published by the Free Software
13 * Foundation; either version 2 of the Licence, or (at your option)
16 * FusionForge is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
21 * You should have received a copy of the GNU General Public License along
22 * with FusionForge; if not, write to the Free Software Foundation, Inc.,
23 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
26 require_once $gfcommon.'include/Error.class.php';
27 require_once $gfcommon.'frs/FRSRelease.class.php';
29 function get_frs_packages($Group) {
31 $res = db_query_params ('SELECT * FROM frs_package WHERE group_id=$1',
32 array ($Group->getID())) ;
33 if (db_numrows($res) > 0) {
34 while($arr = db_fetch_array($res)) {
35 $ps[]=new FRSPackage($Group,$arr['package_id'],$arr);
42 * Gets a FRSPackage object from the given package id
44 * @param int the package id
45 * @param array the DB handle if passed in (optional)
46 * @return object the FRSPackage object
48 function frspackage_get_object($package_id, $data=false) {
49 global $FRSPACKAGE_OBJ;
50 if (!isset($FRSPACKAGE_OBJ['_'.$package_id.'_'])) {
52 //the db result handle was passed in
54 $res = db_query_params ('SELECT * FROM frs_package WHERE package_id=$1',
55 array ($package_id)) ;
56 if (db_numrows($res)<1) {
59 $data = db_fetch_array($res);
61 $Group = group_get_object($data['group_id']);
62 $FRSPACKAGE_OBJ['_'.$package_id.'_']= new FRSPackage($Group,$data['package_id'],$data);
64 return $FRSPACKAGE_OBJ['_'.$package_id.'_'];
67 class FRSPackage extends Error {
70 * Associative array of data from db.
72 * @var array $data_array.
75 var $package_releases;
82 var $Group; //group object
87 * @param object The Group object to which this FRSPackage is associated.
88 * @param int The package_id.
89 * @param array The associative array of data.
90 * @return boolean success.
92 function FRSPackage(&$Group, $package_id=false, $arr=false) {
94 if (!$Group || !is_object($Group)) {
95 $this->setError('FRSPackage:: No Valid Group Object');
98 if ($Group->isError()) {
99 $this->setError('FRSPackage:: '.$Group->getErrorMessage());
102 $this->Group =& $Group;
105 if (!$arr || !is_array($arr)) {
106 if (!$this->fetchData($package_id)) {
110 $this->data_array =& $arr;
111 if ($this->data_array['group_id'] != $this->Group->getID()) {
112 $this->setError('Group_id in db result does not match Group Object');
113 $this->data_array=null;
117 // Add an is_public check here
125 * create - create a new FRSPackage in the database.
127 * @param string The name of this package.
128 * @param boolean Whether it's public or not. 1=public 0=private.
129 * @return boolean success.
131 function create($name, $is_public = 1) {
133 if (strlen($name) < 3) {
134 $this->setError(_('FRSPackage Name Must Be At Least 3 Characters'));
137 if (!util_is_valid_filename($name)) {
138 $this->setError(_('FRSPackage::Update: Package Name can only be alphanumeric or "-" "_" "+" "." "~"'));
140 if (!forge_check_perm ('frs', $this->Group->getID(), 'write')) {
141 $this->setPermissionDeniedError();
145 $res = db_query_params ('SELECT * FROM frs_package WHERE group_id=$1 AND name=$2',
146 array ($this->Group->getID(),
147 htmlspecialchars($name))) ;
148 if (db_numrows($res)) {
149 $this->setError('FRSPackage::create() Error Adding Package: Name Already Exists');
154 $result = db_query_params ('INSERT INTO frs_package(group_id,name,status_id,is_public) VALUES ($1,$2,$3,$4)',
155 array ($this->Group->getId(),
156 htmlspecialchars($name),
160 $this->setError('FRSPackage::create() Error Adding Package: '.db_error());
164 $this->package_id=db_insertid($result,'frs_package','package_id');
165 if (!$this->fetchData($this->package_id)) {
170 //make groupdir if it doesn't exist
171 $groupdir = forge_get_config('upload_dir').'/'.$this->Group->getUnixName();
172 if (!is_dir($groupdir)) {
176 $newdirlocation = $groupdir.'/'.$this->getFileName();
177 if (!is_dir($newdirlocation)) {
178 @mkdir($newdirlocation);
181 // 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
182 @chown($newdirlocation,forge_get_config('apache_user'));
183 @chgrp($newdirlocation,forge_get_config('apache_group'));
190 * fetchData - re-fetch the data for this Package from the database.
192 * @param int The package_id.
193 * @return boolean success.
195 function fetchData($package_id) {
196 $res = db_query_params ('SELECT * FROM frs_package WHERE package_id=$1 AND group_id=$2',
198 $this->Group->getID())) ;
199 if (!$res || db_numrows($res) < 1) {
200 $this->setError('FRSPackage::fetchData() Invalid package_id'.db_error());
203 $this->data_array = db_fetch_array($res);
204 db_free_result($res);
209 * getGroup - get the Group object this FRSPackage is associated with.
211 * @return object The Group object.
213 function &getGroup() {
218 * getID - get this package_id.
220 * @return int The id of this package.
223 return $this->data_array['package_id'];
227 * getName - get the name of this package.
229 * @return string The name of this package.
232 return $this->data_array['name'];
236 * getFileName - get the filename of this package.
238 * @return string The name of this package.
240 function getFileName() {
241 return util_secure_filename($this->data_array['name']);
245 * getStatus - get the status of this package.
247 * @return int The status.
249 function getStatus() {
250 return $this->data_array['status_id'];
254 * isPublic - whether non-group-members can view.
256 * @return boolean is_public.
258 function isPublic() {
259 return $this->data_array['is_public'];
263 * setMonitor - Add the current user to the list of people monitoring this package.
265 * @return boolean success.
267 function setMonitor() {
268 if (!session_loggedin()) {
269 $this->setError(_('You can only monitor if you are logged in'));
272 $result = db_query_params ('SELECT * FROM filemodule_monitor WHERE user_id=$1 AND filemodule_id=$2',
276 if (!$result || db_numrows($result) < 1) {
278 User is not already monitoring thread, so
279 insert a row so monitoring can begin
281 $result = db_query_params ('INSERT INTO filemodule_monitor (filemodule_id,user_id) VALUES ($1,$2)',
282 array ($this->getID(),
286 $this->setError('Unable to add monitor: '.db_error());
295 * stopMonitor - Remove the current user from the list of people monitoring this package.
297 * @return boolean success.
299 function stopMonitor() {
300 if (!session_loggedin()) {
301 $this->setError(_('You can only monitor if you are logged in'));
304 return db_query_params ('DELETE FROM filemodule_monitor WHERE user_id=$1 AND filemodule_id=$2',
310 * getMonitorCount - Get the count of people monitoring this package
312 * @return int the count
314 function getMonitorCount() {
315 $res = db_result(db_query_params ('select count(*) as count from filemodule_monitor where filemodule_id=$1',
316 array ($this->getID())), 0, 0);
318 $this->setError('FRSPackage::getMonitorCount() Error On querying monitor count: '.db_error());
325 * isMonitoring - Is the current user in the list of people monitoring this package.
327 * @return boolean is_monitoring.
329 function isMonitoring() {
330 if (!session_loggedin()) {
334 $result = db_query_params ('SELECT * FROM filemodule_monitor WHERE user_id=$1 AND filemodule_id=$2',
338 if (!$result || db_numrows($result) < 1) {
346 * getMonitorIDs - Return an array of user_id's of the list of people monitoring this package.
348 * @return array The array of user_id's.
350 function &getMonitorIDs() {
351 $res = db_query_params ('SELECT user_id FROM filemodule_monitor WHERE filemodule_id=$1',
352 array ($this->getID())) ;
353 return util_result_column_to_array($res);
357 * update - update an FRSPackage in the database.
359 * @param string The name of this package.
360 * @param int The status_id of this package from frs_status table.
361 * @param int public or private : 1 or 0
362 * @return boolean success.
364 function update($name, $status, $is_public = 1) {
365 if (strlen($name) < 3) {
366 $this->setError(_('FRSPackage Name Must Be At Least 3 Characters'));
370 if (!forge_check_perm('frs', $this->Group->getID(), 'write')) {
371 $this->setPermissionDeniedError();
374 if($this->getName()!=htmlspecialchars($name)) {
375 $res = db_query_params ('SELECT * FROM frs_package WHERE group_id=$1 AND name=$2',
376 array ($this->Group->getID(),
377 htmlspecialchars($name))) ;
378 if (db_numrows($res)) {
379 $this->setError('FRSPackage::update() Error Updating Package: Name Already Exists');
384 $res = db_query_params('UPDATE frs_package SET name=$1, status_id=$2, is_public=$3 WHERE group_id=$4 AND package_id=$5',
385 array (htmlspecialchars($name),
388 $this->Group->getID(),
390 if (!$res || db_affected_rows($res) < 1) {
391 $this->setError('FRSPackage::update() Error On Update: '.db_error());
396 $olddirname = $this->getFileName();
397 if(!$this->fetchData($this->getID())){
398 $this->setError("FRSPackage::update() Error Updating Package: Couldn't fetch data");
402 $newdirname = $this->getFileName();
403 $olddirlocation = forge_get_config('upload_dir').'/'.$this->Group->getUnixName().'/'.$olddirname;
404 $newdirlocation = forge_get_config('upload_dir').'/'.$this->Group->getUnixName().'/'.$newdirname;
406 if(($olddirname!=$newdirname)){
407 if(is_dir($newdirlocation)){
408 $this->setError('FRSPackage::update() Error Updating Package: Directory Already Exists');
412 if(!@rename($olddirlocation,$newdirlocation)) {
413 $this->setError("FRSPackage::update() Error Updating Package: Couldn't rename dir");
420 $this->createNewestReleaseFilesAsZip();
425 * getReleases - gets Release objects for all the releases in this package.
427 * return array Array of FRSRelease Objects.
429 function &getReleases() {
430 if (!is_array($this->package_releases) || count($this->package_releases) < 1) {
431 $this->package_releases=array();
432 $res = db_query_params ('SELECT * FROM frs_release WHERE package_id=$1',
433 array ($this->getID())) ;
434 while ($arr = db_fetch_array($res)) {
435 $this->package_releases[]=new FRSRelease($this,$arr['release_id'],$arr);
438 return $this->package_releases;
442 * delete - delete this package and all its related data.
444 * @param bool I'm Sure.
445 * @param bool I'm REALLY sure.
446 * @return bool true/false;
448 function delete($sure, $really_sure) {
449 if (!$sure || !$really_sure) {
450 $this->setMissingParamsError(_('Please tick all checkboxes.'));
453 if (!forge_check_perm ('frs', $this->Group->getID(), 'write')) {
454 $this->setPermissionDeniedError();
457 $r =& $this->getReleases();
458 for ($i=0; $i<count($r); $i++) {
459 if (!is_object($r[$i]) || $r[$i]->isError() || !$r[$i]->delete($sure, $really_sure)) {
460 $this->setError('Release Error: '.$r[$i]->getName().':'.$r[$i]->getErrorMessage());
464 $dir=forge_get_config('upload_dir').'/'.
465 $this->Group->getUnixName() . '/' .
466 $this->getFileName().'/';
468 // double-check we're not trying to remove root dir
469 if (util_is_root_dir($dir)) {
470 $this->setError('Package::delete error: trying to delete root dir');
476 db_query_params ('DELETE FROM frs_package WHERE package_id=$1 AND group_id=$2',
477 array ($this->getID(),
478 $this->Group->getID())) ;
483 * Function that selects the newest release.
484 * The newest release is the release with the highest ID
486 * @return object FRSRelease
489 function getNewestRelease() {
490 $result = db_query_params('SELECT MAX(release_id) AS release_id FROM frs_release WHERE package_id=$1',
491 array ($this->getID())) ;
493 if ($result && db_numrows($result) == 1) {
494 $row = db_fetch_array($result);
495 return frsrelease_get_object($row['release_id']);
497 $this->setError('FRSRelease:: No valid max release id');
502 public function getNewestReleaseZipName () {
503 return $this->getFileName()."-latest.zip";
506 public function getNewestReleaseZipPath () {
507 return forge_get_config('upload_dir').'/'.$this->Group->getUnixName().'/'.$this->getFileName().'/'.$this->getNewestReleaseZipName();
510 public function createNewestReleaseFilesAsZip(){
511 $release = $this->getNewestRelease();
513 $zip = new ZipArchive();
514 $zipPath = $this->getNewestReleaseZipPath();
515 $filesPath = forge_get_config('upload_dir').'/'.$this->Group->getUnixName().'/'.$this->getFileName().'/'.$release->getFileName();
517 if ($zip->open($zipPath, ZIPARCHIVE::OVERWRITE)!==true) {
518 exit_error(_('Cannot open the file archive.').' '.$zipPath.'.');
521 $files = $release->getFiles();
523 foreach ($files as $f) {
524 $filePath = $filesPath.'/'.$f->getName();
525 $zip->addFile($filePath,$f->getName());
536 // c-file-style: "bsd"