Merge lp:~vierbergenlars/remotecp-panel/rest into lp:~vierbergenlars/remotecp-panel/trunk

Proposed by Lars Vierbergen
Status: Work in progress
Proposed branch: lp:~vierbergenlars/remotecp-panel/rest
Merge into: lp:~vierbergenlars/remotecp-panel/trunk
Diff against target: 1426 lines (+970/-117)
33 files modified
api/REST/REST.php (+46/-2)
api/REST/checks.php (+57/-0)
api/REST/dispatcher.php (+190/-0)
api/REST/exceptions.php (+22/-1)
api/REST/input.php (+31/-0)
api/REST/response.php (+4/-0)
api/REST_entry.php (+0/-9)
api/auth/auth.php (+2/-3)
api/auth/authorize.php (+6/-1)
api/modules/database.php (+25/-0)
api/modules/database/database.a.php (+12/-0)
api/modules/database/database.group.a.php (+44/-0)
api/modules/database/database.group.a.user.php (+33/-0)
api/modules/database/database.group.php (+30/-0)
api/modules/database/database.php (+6/-0)
api/modules/database/database.settings.php (+58/-0)
api/modules/database/database.site.php (+97/-0)
api/modules/database/site/database.site.a.php (+49/-0)
api/modules/database/site/database.site.subhandler.php (+13/-0)
api/modules/database/site/database.site.user.php (+24/-0)
api/modules/user.php (+6/-95)
api/modules/user/user.a.php (+19/-0)
api/modules/user/user.me.php (+30/-0)
api/modules/user/user.php (+29/-0)
api/modules/user/user.search.php (+9/-0)
api/paths.txt (+77/-0)
api/request.php (+4/-1)
api/responder.php (+29/-1)
inc/groups/groups.php (+1/-1)
inc/rdb/auth.php (+1/-1)
inc/utils/validDomainName.php (+15/-0)
licenses/licenses.txt (+1/-0)
zz-schemas/schemas.readme.txt (+0/-2)
To merge this branch: bzr merge lp:~vierbergenlars/remotecp-panel/rest
Reviewer Review Type Date Requested Status
Lars Vierbergen Pending
Review via email: mp+79881@code.launchpad.net

Description of the change

Add REST API for webservices

To post a comment you must log in.
207. By Launchpad Translations on behalf of vierbergenlars

Launchpad automatic translations update.

208. By Lars Vierbergen

Fix authentication timeout with applications demanding all privileges

209. By Lars Vierbergen

Working on REST database module

210. By Lars Vierbergen

Work on database API
Make RESTinput::getParts more powerful
Remove auth for GET user info
Add document describing implemented paths
Make api/request.php HTML compliant

211. By Lars Vierbergen

Always chdir back to previous directory after including a file
Add auth::write_db_groups when issuing PUT on database/{ID}/group
Add GET database/{ID}/group/{GID} method

212. By Lars Vierbergen

Add some prepared checks and exceptions to REST.
Fix PUT database/{}/group

213. By Lars Vierbergen

Add PUT/POST database/{}/group/{} (not tested)

214. By Lars Vierbergen

Add GET database/{ID}/group/{GID}/{GUID} (untested)

215. By Lars Vierbergen

Add assure to RESTcheck
RegExpRESTException fixed
RESTresponse now checks wether status exists before polling it
Remove mysqli_result::free()
Add extra error handling for PHP errors
Test all untested REST changes

216. By Lars Vierbergen

Add system to defer actions to submodules (REST)
Remove schemas

217. By Lars Vierbergen

Added RESTDispatcher class
Added override of dispatcher directory
Added REST::load to load files outside api
Moved submodules to directories
Splitted user.php

218. By Lars Vierbergen

Fix remote database not imported
Fix dispatcher.php override_namespace
Fix RESTinput::getParts not to return empty array value
Let REST::load use global connections
Add POST {ANID}/group/{GUID}/{GUID}

219. By Lars Vierbergen

Make RESTcheck automatically throw exceptions if the second parameter is not set or true
Add PHPDoc and URI override to dispatcher.php
Update other files for new structure

220. By Lars Vierbergen

Add decode function to RESTinput
Change ACI 128 to allow deletion of sites
Implement GET database.site endpoint, GET/POST database.settings endpoint
Add new paths.txt
Add is_valid_domain_name() function (and license)

221. By Lars Vierbergen

Implement PUT database.site and GET database.site.a

222. By Lars Vierbergen

Add JSON-P as response type

223. By Lars Vierbergen

Make RESTcheck::parameter_exists accept arrays

224. By Lars Vierbergen

Implement PUT/DELETE database/{ID}/site/{SID}
Add database.site.a.user spec

225. By Lars Vierbergen

dispatcher matches full pattern
Move site handlers to a subhandler
Implement GET database/{ID}/site/{SID}/user/{GUID}
Add some endpoints

226. By Lars Vierbergen

Update RESTDispatcher to support * for all characters
Incorporate REST_entry.php into responder.php

227. By Lars Vierbergen

Change dispatcher for the subhandler a bit
Forgot an override in database.site.subhandler
Implement POST/DELETE database.site.user

228. By Lars Vierbergen

Reduce function calls (remove 4 calls)
* REST::dispatch takes the handler for ''
* database.site override is for url site/{GUID}

Unmerged revisions

228. By Lars Vierbergen

Reduce function calls (remove 4 calls)
* REST::dispatch takes the handler for ''
* database.site override is for url site/{GUID}

227. By Lars Vierbergen

Change dispatcher for the subhandler a bit
Forgot an override in database.site.subhandler
Implement POST/DELETE database.site.user

226. By Lars Vierbergen

Update RESTDispatcher to support * for all characters
Incorporate REST_entry.php into responder.php

225. By Lars Vierbergen

dispatcher matches full pattern
Move site handlers to a subhandler
Implement GET database/{ID}/site/{SID}/user/{GUID}
Add some endpoints

224. By Lars Vierbergen

Implement PUT/DELETE database/{ID}/site/{SID}
Add database.site.a.user spec

223. By Lars Vierbergen

Make RESTcheck::parameter_exists accept arrays

222. By Lars Vierbergen

Add JSON-P as response type

221. By Lars Vierbergen

Implement PUT database.site and GET database.site.a

220. By Lars Vierbergen

Add decode function to RESTinput
Change ACI 128 to allow deletion of sites
Implement GET database.site endpoint, GET/POST database.settings endpoint
Add new paths.txt
Add is_valid_domain_name() function (and license)

219. By Lars Vierbergen

Make RESTcheck automatically throw exceptions if the second parameter is not set or true
Add PHPDoc and URI override to dispatcher.php
Update other files for new structure

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'api/REST/REST.php'
2--- api/REST/REST.php 2011-09-22 16:07:24 +0000
3+++ api/REST/REST.php 2011-12-11 19:47:27 +0000
4@@ -3,6 +3,8 @@
5 require('input.php');
6 require('output.php');
7 require('response.php');
8+require('checks.php');
9+require('dispatcher.php');
10 class REST {
11 const get=1;
12 const post=2;
13@@ -10,6 +12,7 @@
14 const delete=4;
15 const json=1;
16 const serialize=2;
17+ const jsonp=3;
18 static private $reqUrl='';
19 static private $method=self::get;
20 static private $datatype=self::json;
21@@ -17,6 +20,7 @@
22 static private $errorString=NULL;
23 static private $latest_output_object=NULL;
24 static private $latest_input_object=NULL;
25+ static private $check_object=NULL;
26 /**
27 * Initialisation method for the class
28 * @throws MethodNotAllowedException
29@@ -32,6 +36,10 @@
30 self::$datatype=self::serialize;
31 header('Content-Type: application/x-php-serialized');
32 }
33+ elseif(isset($_GET['callback'])) { //JSON-P request
34+ self::$datatype=self::jsonp;
35+ header('Content-Type: text/javascript');
36+ }
37 elseif(strpos(self::$reqUrl, '.json')!==false){ //Request has .json extention
38 self::$datatype=self::json;
39 header('Content-Type: application/json');
40@@ -39,7 +47,7 @@
41 elseif(strpos(self::$reqUrl, '.ser')!==false){ //Request has .ser extention
42 self::$datatype=self::serialize;
43 header('Content-Type: application/x-php-serialized');
44- }
45+ }
46 else {
47 header('Content-Type: application/json');
48 throw new UnsupportedMediaTypeException('Please provide an Accept header of \'application/json\' or \'application/x-php-serialized\' or add a .json or .ser extention');
49@@ -101,6 +109,15 @@
50 return new RESTresponse(self::$datatype,$output,self::$statusCode);
51 }
52 /**
53+ * Gives a check object
54+ * @return RESTcheck
55+ */
56+ static function check() {
57+ if(self::$check_object===NULL)
58+ self::$check_object=new RESTcheck;
59+ return self::$check_object;
60+ }
61+ /**
62 * Prepares an error for sending
63 * @param int $statusCode HTTP status code
64 * @param string $errorString String explaining the error
65@@ -130,11 +147,38 @@
66 }
67 return $retarr;
68 }
69+ /**
70+ * Returns the method used to request the resource
71+ * @return int
72+ */
73 static function getMethod() {
74 return self::$method;
75 }
76+ /**
77+ * Returns the datatype used to request the resource
78+ * @return int
79+ */
80 static function getDataType() {
81 return self::$datatype;
82 }
83+ /**
84+ * Registers a submodule to launch when a specific URI is requested
85+ * @param string $uri The URI pattern to launch on
86+ * @param string $file The submodule to load
87+ * @return RESTDispatcher
88+ */
89+ static function dispatch($uri=NULL,$file=NULL) {
90+ return new RESTDispatcher($uri, $file);
91+ }
92+ /**
93+ * Load a file from outside the api with the right path
94+ * @param string $file The filename to load
95+ */
96+ static function load($file) {
97+ global $local_connection,$remote_connection;
98+ chdir(__DIR__.'/../..');
99+ require $file;
100+ chdir(__DIR__.'/..');
101+ }
102 }
103-REST::init();
104\ No newline at end of file
105+REST::init();
106
107=== added file 'api/REST/checks.php'
108--- api/REST/checks.php 1970-01-01 00:00:00 +0000
109+++ api/REST/checks.php 2011-12-11 19:47:27 +0000
110@@ -0,0 +1,57 @@
111+<?php
112+/**
113+ * Implements some nice checks for REST modules
114+ */
115+class RESTcheck {
116+ /**
117+ * Performs a preg_match, throwing an exception if the subject does not match
118+ * @param string $pattern The pattern to check for
119+ * @param mixed $subject The string to check
120+ * @param string $name The name of the subject (parameter name or other)
121+ * @param bool $throw Throw an exception if there is no match
122+ * @throws RegExpRESTException
123+ * @return bool
124+ */
125+ function preg_match($pattern,$subject,$name='',$throw=true) {
126+ if(preg_match($pattern,$subject)) return true;
127+ if($throw) throw new RegExpRESTException($name, $pattern);
128+ return false;
129+ }
130+ /**
131+ * Checks if a named parameter exists in this request
132+ * @param string|array $name The name of the parameter to check
133+ * @param bool $throw Throw an exception if there is no match
134+ * @throws MissingParameterRESTException
135+ * @return bool
136+ */
137+ function parameter_exists($name,$throw=true) {
138+ $inputdata=REST::input()->getData();
139+ if(is_string($name)) {
140+ if(isset($inputdata[$name])) return true;
141+ if($throw) throw new MissingParameterRESTException($name);
142+ }
143+ if(is_array($name)) {
144+ $missing=array();
145+ foreach($name as $param) {
146+ if(!isset($inputdata[$param])) $missing[]=$param;
147+ }
148+ if(count($missing)==0) return true;
149+ if($throw) throw new MissingParameterRESTException($missing);
150+ }
151+
152+ return false;
153+ }
154+ /**
155+ * Checks if something is true
156+ * @param bool $test Test wether this is true
157+ * @param Exception $throw Throw this object if it is not true
158+ * @throws Exception
159+ * @return bool
160+ */
161+ function assure($test,Exception &$throw=NULL) {
162+ if($test) return true;
163+ if($throw instanceof Exception) throw $throw;
164+ unset($throw);
165+ return false;
166+ }
167+}
168
169=== added file 'api/REST/dispatcher.php'
170--- api/REST/dispatcher.php 1970-01-01 00:00:00 +0000
171+++ api/REST/dispatcher.php 2011-12-11 19:47:27 +0000
172@@ -0,0 +1,190 @@
173+<?php
174+class RESTDispatcher {
175+ /**
176+ * Current path override
177+ * @var string
178+ */
179+ private static $root_path='modules';
180+ /**
181+ * Al previous path overrides, to allow revert
182+ * @var array
183+ */
184+ private static $prev_path=array();
185+ /**
186+ * Current namespace override
187+ * @var string
188+ */
189+ private static $root_namespace='';
190+ /**
191+ * Al previous namespace overrides, to allow revert
192+ * @var array
193+ */
194+ private static $prev_namespaces=array();
195+ /**
196+ * Current URI override
197+ * @var string
198+ */
199+ private static $root_uri='';
200+ /**
201+ * Al previous URI overrides, to allow revert
202+ * @var array
203+ */
204+ private static $prev_uri=array();
205+ /**
206+ * The file to load
207+ * @var string
208+ */
209+ private $file=NULL;
210+ /**
211+ * Something was already dispatched, stop checking
212+ * @var bool
213+ */
214+ private $kill=false;
215+ /**
216+ * Assigns a path to a dispatcher file
217+ * @param string $uri Path structure
218+ * @param string $file File to load
219+ * @throws NotImplementedException
220+ * @throws MethodNotAllowedException
221+ * @return RESTDispatcher
222+ */
223+ function __construct($uri,$file) {
224+ if($uri===NULL&&$file===NULL||$this->kill) return $this;
225+ if($file!='') $ns=self::$root_namespace.'.';
226+ else $ns=self::$root_namespace;
227+ $input=REST::input();
228+ $current_uri=$input->getPart();
229+ $uri=self::$root_uri.$uri;
230+ if(substr($uri, -1)=='/') $uri=substr($uri,0,-1); //Remove last / from uri
231+ $uri=preg_quote($uri,'/');
232+ $search=array('\\{GUID\\}', '\\{ANID\\}', '\\{NID\\}', '\\{ALPHA\\}', '\\{\\}', '\\*');
233+ $replace=array('[0-9A-Fa-f]{8}-([0-9A-Fa-f]{4}-){3}[0-9A-Fa-f]{12}', '[0-9A-Za-z]+', '[0-9]+', '[A-Za-z]+', '[^\\/]+', '.*');
234+ $pattern=str_replace($search,$replace,$uri).'\\/?';
235+ if(preg_match('/^'.$pattern.'$/', $current_uri)) {
236+ $this->file=self::$root_path.'/'.$ns.$file.'.php';
237+ if(!file_exists($this->file)) throw new NotImplementedException('Module '.$ns.$file.' is not available');
238+ $return=$this->launch();
239+ if($return===false) throw new MethodNotAllowedException('Invalid method for "'.$ns.$file.'"');
240+ $this->kill=true;
241+ }
242+ return $this;
243+ }
244+ /**
245+ * Open the file to be executed, assign right parameters
246+ * @return bool The return value of the file, true means OK, false MethodNotAllowedException
247+ */
248+ private function launch() {
249+ global $local_connection,$remote_connection;
250+ return require $this->file;
251+ }
252+ /**
253+ * Set a new namespace.
254+ * @param string $new The new namespace. If a dot (.) is prepended, the previous namespace is extended
255+ * @return RESTDispatcher
256+ */
257+ function override_namespace($new) {
258+ if($this->kill) return $this;
259+ self::$prev_namespaces[]=self::$root_namespace;
260+ if(strpos($new, '.')===0) $new=self::$root_namespace.$new;
261+ self::$root_namespace=$new;
262+ return $this;
263+ }
264+ /**
265+ * Set a new path to look for files in
266+ * @param string $new The new path. If './' is prepended, the previous path is extended
267+ * @throws RuntimeException When path is not a directory
268+ * @return RESTDispatcher
269+ */
270+ function override_path($new) {
271+ if($this->kill) return $this;
272+ self::$prev_path[]=self::$root_path;
273+ if(strpos($new, './')===0) $new=self::$root_path.'/'.$new;
274+ if(!is_dir($new)) throw new RuntimeException('The path '.$new.' does not exist');
275+ self::$root_path=$new;
276+ return $this;
277+ }
278+ /**
279+ * Set a new uri to put before the give part
280+ * @param string $new The new URI. If './' is prepended, the previous URI is extended
281+ * @return RESTDispatcher
282+ */
283+ function override_uri($new) {
284+ if($this->kill) return $this;
285+ self::$prev_uri[]=self::$root_uri;
286+ if(strpos($new,'./')===0) $new=self::$root_uri.substr($new, 2);
287+ self::$root_uri=$new.'/';
288+ return $this;
289+ }
290+ /**
291+ * Overrides namespace, uri and path
292+ * @param string $namespace The new namespace
293+ * @param string $uri The new URI
294+ * @param string $path The new path
295+ * @see RESTDispatcher::override_namespace()
296+ * @see RESTDispatcher::override_path()
297+ * @see RESTDispatcher::override_uri()
298+ * @uses override_namespace()
299+ * @uses override_path()
300+ * @uses override_uri()
301+ * @return RESTDispatcher
302+ */
303+ function override($namespace=NULL,$uri=NULL,$path=NULL) {
304+ if($this->kill) return $this;
305+ if(!is_null($namespace)) $this->override_namespace($namespace);
306+ if(!is_null($uri)) $this->override_uri($uri);
307+ if(!is_null($path)) $this->override_path($path);
308+ return $this;
309+ }
310+ /**
311+ * Puts the previous namespace back
312+ * @return RESTDispatcher
313+ */
314+ function revert_namespace() {
315+ if($this->kill) return $this;
316+ self::$root_namespace=array_pop(self::$prev_namespaces);
317+ return $this;
318+ }
319+ /**
320+ * Puts the previous path back
321+ * @return RESTDispatcher
322+ */
323+ function revert_path() {
324+ if($this->kill) return $this;
325+ self::$root_path=array_pop(self::$prev_path);
326+ return $this;
327+ }
328+ /**
329+ * Puts the previous URI back
330+ * @return RESTDispatcher
331+ */
332+ function revert_uri() {
333+ if($this->kill) return $this;
334+ self::$root_uri=array_pop(self::$prev_uri);
335+ return $this;
336+ }
337+ /**
338+ * Assigns a path to a dispatcher file
339+ * @uses RESTDispatcher::__construct();
340+ * @param string $uri Path structure
341+ * @param string $file File to load
342+ * @return RESTDispatcher
343+ */
344+ function dispatch($uri,$file) {
345+ if($this->kill) return $this;
346+ return $this->__construct($uri,$file);
347+ }
348+
349+ /**
350+ * Debug function
351+ * @internal
352+ */
353+ function debug() {
354+ echo 'Path:'.self::$root_path."\r\n";
355+ var_dump(self::$prev_path);
356+ echo 'NS:'.self::$root_namespace."\r\n";
357+ var_dump(self::$prev_namespaces);
358+ echo 'URI:'.self::$root_uri."\r\n";
359+ var_dump(self::$prev_uri);
360+ return $this;
361+ }
362+}
363\ No newline at end of file
364
365=== modified file 'api/REST/exceptions.php'
366--- api/REST/exceptions.php 2011-09-07 18:23:04 +0000
367+++ api/REST/exceptions.php 2011-12-11 19:47:27 +0000
368@@ -1,4 +1,7 @@
369 <?php
370+/**
371+ * Exceptions based on HTTP response codes
372+ */
373 class HTTPException extends Exception {}
374 class BadRequestException extends HTTPException {
375 function __construct($message) {
376@@ -94,4 +97,22 @@
377 function __construct($message) {
378 parent::__construct($message, 505);
379 }
380-}
381\ No newline at end of file
382+}
383+/**
384+ * Exceptions based on REST error conditions
385+ */
386+class MissingParameterRESTException extends BadRequestException {
387+ function __construct($param_name) {
388+ if(!is_array($param_name)) $param_name=array($param_name);
389+ $message='Missing required parameters "'.
390+ implode('" ,"',$param_name).
391+ '"';
392+ parent::__construct($message);
393+ }
394+}
395+class RegExpRESTException extends BadRequestException {
396+ function __construct($param_name,$regex) {
397+ $message='Parameter "'.$param_name.'" should match the regular expression "'.$regex.'"';
398+ parent::__construct($message);
399+ }
400+}
401
402=== modified file 'api/REST/input.php'
403--- api/REST/input.php 2011-09-22 13:55:20 +0000
404+++ api/REST/input.php 2011-12-11 19:47:27 +0000
405@@ -66,6 +66,19 @@
406 return $this->part;
407 }
408 /**
409+ * Gets the action name separated by / in an array if no id is given.
410+ * Gets the action name at position $id if an id is given.
411+ * @param int $id The position of the action name
412+ * @return mixed Array if no id is given, string if an id is given and exists, false if an id is given and does not exist
413+ */
414+ function getParts($id=NULL) {
415+ $parts=explode('/',$this->part);
416+ if(($last=array_pop($parts))!='') array_push($parts, $last);
417+ if($id===NULL) return $parts;
418+ if(array_key_exists($id, $parts)) return $parts[$id];
419+ return false;
420+ }
421+ /**
422 * Gets the full querystring
423 * @return string
424 */
425@@ -79,4 +92,22 @@
426 function getData() {
427 return $this->data;
428 }
429+ /**
430+ * Decodes input data according to the data type
431+ * @param string $data The data to decode
432+ * @return mixed The decoded data
433+ * @throws UnexpectedValueException
434+ */
435+ function decode($data) {
436+ switch(REST::getDataType()) {
437+ case REST::json:
438+ return json_decode($data,true);
439+ break;
440+ case REST::serialize:
441+ return unserialize($data);
442+ break;
443+ default:
444+ throw new UnexpectedValueException('REST data type should be json or serialize');
445+ }
446+ }
447 }
448\ No newline at end of file
449
450=== modified file 'api/REST/response.php'
451--- api/REST/response.php 2011-09-07 18:23:04 +0000
452+++ api/REST/response.php 2011-12-11 19:47:27 +0000
453@@ -16,6 +16,7 @@
454 */
455 function __construct($dataType,RESToutput $output,$statuscode=200) {
456 $this->output=$output->getData();
457+ if(isset($this->output['status'])&&$this->output['status']===false) $statuscode=500; //Our status is not good, 500 error
458 $this->dataType=$dataType;
459 $this->statuscode=$statuscode;
460 }
461@@ -27,6 +28,9 @@
462 if($this->dataType==REST::json) {
463 echo json_encode($this->output);
464 }
465+ elseif($this->dataType==REST::jsonp) {
466+ echo $_GET['callback'].'('.json_encode($this->output).');';
467+ }
468 elseif($this->dataType==REST::serialize) {
469 echo serialize($this->output);
470 }
471
472=== removed file 'api/REST_entry.php'
473--- api/REST_entry.php 2011-09-18 16:51:00 +0000
474+++ api/REST_entry.php 1970-01-01 00:00:00 +0000
475@@ -1,9 +0,0 @@
476-<?php
477-require 'REST/REST.php';
478-require 'auth/auth.php';
479-$module=REST::input()->getModule();
480-if(!file_exists('modules/'.$module.'.php')) {
481- throw new NotFoundException('Module '.$module.' does not exist');
482-}
483-require 'modules/'.$module.'.php';
484-
485
486=== modified file 'api/auth/auth.php'
487--- api/auth/auth.php 2011-09-22 15:46:09 +0000
488+++ api/auth/auth.php 2011-12-11 19:47:27 +0000
489@@ -1,5 +1,4 @@
490 <?php
491-define('__DEBUG__', true);
492 $wd=getcwd();
493 chdir(__DIR__.'/../..');
494 require 'inc/controllers.php';
495@@ -171,7 +170,7 @@
496 if($aci&16) $return[]=$t->_('Send and remove messages');
497 if($aci&32) $return[]=$t->_('Read all data in your databases');
498 if($aci&64) $return[]=$t->_('Add users to groups in your databases');
499- if($aci&128) $return[]=$t->_('Create sites in your databases');
500+ if($aci&128) $return[]=$t->_('Create and delete sites in your databases');
501 if($aci&256) $return[]=$t->_('Edit sites in your databases');
502 if($aci&512) $return[]=$t->_('Change site administrators and group administrators in your databases');
503 if($aci&1024) $return[]=$t->_('Add users to your databases');
504@@ -204,5 +203,5 @@
505 elseif($throw_on_failure) throw new UnauthorizedException('You don\'t have the right permissions');
506 return false;
507 }
508-
509+
510 }
511
512=== modified file 'api/auth/authorize.php'
513--- api/auth/authorize.php 2011-09-22 15:46:09 +0000
514+++ api/auth/authorize.php 2011-12-11 19:47:27 +0000
515@@ -58,13 +58,18 @@
516 $time=NULL;
517 }
518 else {
519- $time=$_POST['auth_time_days']*24*60*60+$_POST['auth_time_hours']*60*60+$_POST['auth_time_mins']*60;
520+ $time=(int)$_POST['auth_time_days']*24*60*60+(int)$_POST['auth_time_hours']*60*60+(int)$_POST['auth_time_mins']*60;
521+ }
522+ if(isset($_POST['time'])) {
523+ $time=(int)$_POST['time'];
524+ if($time=='') $time=NULL;
525 }
526 if((int)$cred_info['use']&auth::all) { //Warn again about all permissions
527 echo '<h1 class="ui-widget-header ui-corner-top" style="margin-bottom: 0">'.$t->_('Are you really sure?').'</h1>'.
528 '<div class="ui-widget-content ui-corner-bottom">'.
529 $t->_('You are about to give an application <b>ALL</b> permissions (including deleting and creating accounts)').
530 '<form method="POST"><input type="hidden" name="really_sure" value="reallysure">'.
531+ '<input type="hidden" name="time" value="'.htmlspecialchars($time).'">'.
532 '<input type="submit" class="gui-button ui-priority-primary" name="authorize" value="'.$t->_('Grant all privileges').'">'.
533 '<input type="submit" class="gui-button ui-priority-secondary" name="cancel" value="'.$t->_('Cancel').'"></form>'.
534 '</div>';
535
536=== added directory 'api/modules/database'
537=== added file 'api/modules/database.php'
538--- api/modules/database.php 1970-01-01 00:00:00 +0000
539+++ api/modules/database.php 2011-12-11 19:47:27 +0000
540@@ -0,0 +1,25 @@
541+<?php
542+$input=REST::input();
543+$method=REST::getMethod();
544+auth::init();
545+auth::granted(auth::read_db,true);
546+if(count($input->getParts())>=1){
547+ $_SERVER['PATH_INFO']='/'.$input->getParts(0);
548+ REST::load('inc/rdb/rdb.php');
549+}
550+REST::dispatch('','')
551+->override('database',NULL,'./database')
552+ ->override_uri('{ANID}')
553+ ->override('.group','./group')
554+ ->dispatch('{GUID}/{GUID}', 'a.user')
555+ ->dispatch('{GUID}', 'a')
556+ ->dispatch('', '')
557+ ->revert_namespace()->revert_uri()
558+ ->override('.site','./site/{GUID}','./site')
559+ ->dispatch('*','subhandler')
560+ ->revert_path()
561+ ->dispatch('','')
562+ ->revert_namespace()->revert_uri()
563+ ->dispatch('settings','settings')
564+ ->dispatch('', 'a')
565+;
566
567=== added file 'api/modules/database/database.a.php'
568--- api/modules/database/database.a.php 1970-01-01 00:00:00 +0000
569+++ api/modules/database/database.a.php 2011-12-11 19:47:27 +0000
570@@ -0,0 +1,12 @@
571+<?php
572+$input=REST::input();
573+if(REST::getMethod()!==REST::delete) return false;
574+auth::granted(auth::all,true);
575+if(rdb_auth::$level!=9) throw new UnauthorizedException('You need database admin privileges to delete a database');
576+$q=array();
577+$q[]=$local_connection->query('DELETE FROM `remote_databases` WHERE `key`=\''.$local_connection->escape_string($input->getPart().'\''));
578+$q[]=$local_connection->query('DELETE FROM `remote_databases_assignments` WHERE `key`=\''.$local_connection->escape_string($input->getPart().'\''));
579+if(!array_search(false, $q,true)) REST::output()->setData(array('status'=>true));
580+else REST::output()->setData(array('status'=>false));
581+$q[0]->free();
582+$q[1]->free();
583
584=== added file 'api/modules/database/database.group.a.php'
585--- api/modules/database/database.group.a.php 1970-01-01 00:00:00 +0000
586+++ api/modules/database/database.group.a.php 2011-12-11 19:47:27 +0000
587@@ -0,0 +1,44 @@
588+<?php
589+$input=REST::input();
590+REST::load('inc/groups/groups.php');
591+$GID=$input->getParts(2);
592+switch(REST::getMethod()) {
593+ case REST::get:
594+ $nameq=$remote_connection->query('SELECT * FROM `groups_names` WHERE UPPER(`gid`)="'.strtoupper($GID).'"');
595+ if($nameq->num_rows!=1) throw new NotFoundException('The group with GID '.$GID.' does not exist');
596+ $name=$nameq->fetch_object()->name;
597+ $users=array();
598+ $usersq=$remote_connection->query('SELECT * FROM `groups` WHERE UPPER(`gid`)="'.strtoupper($GID).'"');
599+ while($user=$usersq->fetch_assoc()) {
600+ $users[]=array('user'=>$user['user'],'administrator'=>(bool)$user['admin']);
601+ }
602+ REST::output()->setData(array('name'=>$name,'users'=>$users));
603+ break;
604+ case REST::put:
605+ auth::granted(auth::write_db_groups,true);
606+ $data=$input->getData();
607+ REST::check()->parameter_exists('user');
608+ REST::check()->assure(groups::groupExists($GID),new NotFoundException('The group with GID '.$GID.' does not exist'));
609+ REST::check()->assure(groups::isGroupAdmin($GID),new ForbiddenException('You are not an administrator of the group with GID '.$GID));
610+ REST::check()->assure(session::userExists($data['user']),new NotFoundException('The user with GUID '.$data['user'].' does not exist'));
611+ if(groups::addUser($data['user'], $GID)) {
612+ REST::output()->setData(array('status'=>true));
613+ }
614+ else {
615+ REST::output()->setData(array('status'=>false,'errors'=>JSError::get()));
616+ }
617+ break;
618+ case REST::post:
619+ auth::granted(auth::write_db_groups,true);
620+ $data=$input->getData();
621+ REST::check()->parameter_exists('name');
622+ REST::check()->preg_match('/^[A-Za-z_0-9\\-\\(\\)]+$/', $data['name'],'name');
623+ REST::check()->assure(groups::groupExists($GID),new NotFoundException('The group with GID '.$GID.' does not exist'));
624+ REST::check()->assure(groups::isGroupAdmin($GID),new ForbiddenException('You are not an administrator of the group with GID '.$GID));
625+ $q=$remote_connection->query('UPDATE `groups_names` SET `name`=\''.$data['name'].'\' WHERE UPPER(`GID`)=\''.strtoupper($GID).'\'');
626+ if($q) REST::output()->setData(array('status'=>true));
627+ else REST::output()->setData(array('status'=>false));
628+ break;
629+ default:
630+ return false;
631+}
632\ No newline at end of file
633
634=== added file 'api/modules/database/database.group.a.user.php'
635--- api/modules/database/database.group.a.user.php 1970-01-01 00:00:00 +0000
636+++ api/modules/database/database.group.a.user.php 2011-12-11 19:47:27 +0000
637@@ -0,0 +1,33 @@
638+<?php
639+$input=REST::input();
640+REST::load('inc/groups/groups.php');
641+$GID=strtoupper($input->getParts(2));
642+REST::check()->assure(groups::groupExists($GID),new NotFoundException('The group with GID '.$GID.' does not exist'));
643+REST::check()->assure(session::userExists($input->getParts(3)),new NotFoundException('The user with GUID '.$input->getParts(3).' does not exist'));
644+switch(REST::getMethod()) {
645+ case REST::get:
646+ $q=$remote_connection->query('SELECT * FROM `groups` WHERE UPPER(`gid`)=\''.$GID.'\' AND `user`=\''.$input->getParts(3).'\'');
647+ if(!$q) REST::output()->setData(array('status'=>false));
648+ elseif($q->num_rows==1) REST::output()->setData(array('member'=>true));
649+ else REST::output()->setData(array('member'=>false));
650+ break;
651+ case REST::post:
652+ auth::granted(auth::write_db_groups,true);
653+ REST::check()->parameter_exists('administrator');
654+ $data=$input->getData();
655+ REST::check()->assure($data['administrator']==1||$data['administrator']==0,new BadRequestException('The value of the parameter administrator should either be 0 or 1'));
656+ REST::check()->assure(groups::isGroupAdmin($GID),new ForbiddenException('You are not an administrator of the group with GID '.$GID));
657+ $c0=$remote_connection->query('SELECT * FROM `groups` WHERE UPPER(`gid`)=\''.$GID.'\' AND `user`=\''.REST::input()->getParts(3).'\'');
658+ if(!$c0) {
659+ REST::output()->setData(array('status'=>false));
660+ return;
661+ }
662+ REST::check()->assure($c0->num_rows==1,new NotFoundException('The user with GUID '.$input->getParts(3).' is not a member of group with GID '.$GID));
663+ $q=$remote_connection->query('UPDATE `groups` SET `admin`='.$data['administrator'].' WHERE `user`=\''.$input->getParts(3).'\' AND UPPER(`gid`)=\''.$GID.'\'');
664+ if(!$q) REST::output()->setData(array('status'=>false));
665+ else REST::output()->setData(array('status'=>true));
666+ break;
667+ default:
668+ return false;
669+}
670+
671
672=== added file 'api/modules/database/database.group.php'
673--- api/modules/database/database.group.php 1970-01-01 00:00:00 +0000
674+++ api/modules/database/database.group.php 2011-12-11 19:47:27 +0000
675@@ -0,0 +1,30 @@
676+<?php
677+REST::load('inc/groups/groups.php');
678+switch(REST::getMethod()) {
679+ case REST::get: //List my groups
680+ $grps=groups::getMyGroups();
681+ foreach($grps as $grp) {
682+ $grpnam=groups::getName($grp);
683+ REST::output()->appendData(array('gid'=>$grp,'name'=>$grpnam));
684+ }
685+ break;
686+ case REST::put: //Create new group
687+ auth::granted(auth::write_db_groups,true);
688+ $data=REST::input()->getData();
689+ REST::check()->parameter_exists('name');
690+ REST::check()->preg_match('/^[a-zA-Z0-9_]+$/', $data['name'],'name');
691+ REST::check()->assure(!groups::groupExists($data['name']),new ConflictException('This groupname is already in use'));
692+ $q=array();
693+ REST::load('inc/utils/guid.php');
694+ $uuid=guid();
695+ $q[]=$remote_connection->query('INSERT INTO `groups_names` VALUES(\''.$uuid.'\', \''.$data['name'].'\')');
696+ $q[]=$remote_connection->query('INSERT INTO `groups` VALUES(\''.$uuid.'\',\''.session::$guid.'\',1)');
697+ if(!array_search(false, $q,true)) {
698+ REST::output()->setData(array('status'=>true));
699+ REST::success(201);
700+ }
701+ else REST::output()->setData(array('status'=>false));
702+ break;
703+ default:
704+ return false;
705+}
706
707=== added file 'api/modules/database/database.php'
708--- api/modules/database/database.php 1970-01-01 00:00:00 +0000
709+++ api/modules/database/database.php 2011-12-11 19:47:27 +0000
710@@ -0,0 +1,6 @@
711+<?php
712+if(REST::getMethod()!==REST::get) return false;
713+$q=$local_connection->query('SELECT `key` FROM `remote_databases_assignments` WHERE `user`="'.$local_connection->escape_string(session::$guid).'"');
714+while($r=$q->fetch_assoc()){
715+ REST::output()->appendData($r['key']);
716+}
717
718=== added file 'api/modules/database/database.settings.php'
719--- api/modules/database/database.settings.php 1970-01-01 00:00:00 +0000
720+++ api/modules/database/database.settings.php 2011-12-11 19:47:27 +0000
721@@ -0,0 +1,58 @@
722+<?php
723+REST::load('inc/utils/doubleExplode.php');
724+switch (REST::getMethod()) {
725+ case REST::get:
726+ $settings=array();
727+ $settings['title']=$local_connection->query('SELECT `title` FROM `remote_databases` WHERE `key`=\''.$local_connection->escape_string(REST::input()->getParts(0)).'\'')
728+ ->fetch_object()->title;
729+ $settingsq=$remote_connection->query('SELECT * FROM `_system_`');
730+ while($setting=$settingsq->fetch_assoc()) {
731+ switch($setting['key']) {
732+ case 'styles':
733+ $styles=explode('|',$setting['value']);
734+ break;
735+ case 'domains':
736+ $domains=explode('|',$setting['value']);
737+ break;
738+ case 'addons':
739+ $addons=doubleExplode('&', '=', $setting['value']);
740+ $sortedaddons=array();
741+ foreach($addons as $k=>$v) {
742+ array_push($sortedaddons, array('id'=>$k,'name'=>$v));
743+ }
744+ break;
745+ default:
746+ $settings[$setting['key']]=$setting['value'];
747+ }
748+ }
749+ $settings['styles']=$styles;
750+ $settings['domains']=$domains;
751+ $settings['addons']=$sortedaddons;
752+ REST::output()->setData($settings);
753+ break;
754+ case REST::post:
755+ auth::granted(auth::all);
756+ $data=REST::input()->getData();
757+ $parameters=array('title'=>null,'domains'=>null);
758+ $data=array_intersect_key($data,$parameters); //At least one key from the parameters array should be present
759+ REST::check()->assure(count($data)>=1, new MissingParameterRESTException(array('title','domains')));
760+ $q=array();
761+ if(isset($data['title'])) {
762+ REST::check()->preg_match('^[a-zA-Z0-9 -_]+$', $data['title'],'title');
763+ $q[]=$local_connection->query('UPDATE `remote_databases` SET `title`=\''.$local_connection->escape_string($data['title']).'\' WHERE `key`=\''.$local_connection->escape_string(REST::input()->getParts(0)).'\'');
764+ }
765+ if(isset($data['domains'])) {
766+ REST::load('inc/utils/validDomainName.php');
767+ $domains=REST::input()->decode($data['domains']);
768+ foreach($domains as $domain) {
769+ REST::check()->assure(is_valid_domain_name($domain),new BadRequestException($domain.' is not a valid domain name'));
770+ }
771+ $domains=implode('|',$domains);
772+ $q[]=$remote_connection->query('UPDATE `_system_` SET `value`=\''.$domains.'\' WHERE `key`=\'domains\'');
773+ }
774+ if(in_array(false, $q,true)) REST::output()->setData(array('status'=>false));
775+ else REST::output()->setData(array('status'=>true));
776+ break;
777+ default:
778+ return false;
779+}
780\ No newline at end of file
781
782=== added file 'api/modules/database/database.site.php'
783--- api/modules/database/database.site.php 1970-01-01 00:00:00 +0000
784+++ api/modules/database/database.site.php 2011-12-11 19:47:27 +0000
785@@ -0,0 +1,97 @@
786+<?php
787+switch(REST::getMethod()) {
788+ case REST::get:
789+ $sitesq=$remote_connection->query('SELECT `site_ref` FROM `system_siteinfo` GROUP BY `site_ref`');
790+ while($site=$sitesq->fetch_assoc()) {
791+ REST::output()->appendData($site['site_ref']);
792+ }
793+ break;
794+ case REST::put:
795+ auth::granted(auth::write_db_sites_new);
796+ REST::check()->parameter_exists(array(
797+ 'domain','subdomain','style','language','title','tagline','footer','author'
798+ ));
799+ $data=REST::input()->getData();
800+ //Check domain
801+ $c0=$remote_connection->query('SELECT `value` FROM `_system_` WHERE `key`=\'domains\'');
802+ REST::check()->assure($c0->num_rows==1,new GatewayException('Remote database has invalid domain settings in _system_'));
803+ $available_domains=explode('|', $c0->fetch_object()->value);
804+ $c0->free();
805+ REST::check()->assure(in_array($data['domain'], $available_domains),new BadRequestException('The provided domain is not in the range of valid domains'));
806+ //Check subdomain
807+ REST::check()->preg_match('/^[a-z0-9\\-]+$/i', $data['subdomain'],'subdomain');
808+ $c1=$remote_connection->query('SELECT * FROM `system_domains` WHERE `url-in`=\''.$data['subdomain'].'.'.$data['domain'].'\'');
809+ REST::check()->assure($c1->num_rows==0,new ConflictException('This subdomain is already registered'));
810+ $c1->free();
811+ //Check style
812+ $c2=$remote_connection->query('SELECT `value` FROM `_system_` WHERE `key`=\'styles\'');
813+ if($c2->num_rows!=1) throw new GatewayException('Remote database has invalid style settings in _system_');
814+ $available_styles=explode('|', $c2->fetch_object()->value);
815+ $c2->free();
816+ REST::check()->assure(in_array($data['style'], $available_styles),new BadRequestException('The provided style is not in the range of valid styles'));
817+ //Check language
818+ require __DIR__.'/../../../inc/utils/languageCodes.php';
819+ REST::check()->assure(array_key_exists($data['language'], $languageCodes),new BadRequestException('The provided language is not in the range of valid languages'));
820+ //Check title
821+ REST::check()->assure(trim($data['title'])!='', new BadRequestException('The provided title should be at least one character'));
822+ //Execute registration
823+ REST::load('inc/utils/guid.php');
824+ REST::load('inc/utils/doubleExplode.php');
825+ $site_ref=guid();
826+ //Create domain link
827+ $x[]=$remote_connection->query('INSERT INTO `system_domains` VALUES(\''.$remote_connection->escape_string($data['subdomain'].'.'.$data['domain']).'\',NULL,\''.$site_ref.'\')');
828+ //Create site constants
829+ $x[]=$remote_connection->query('INSERT INTO `system_siteinfo` VALUES(\''.$site_ref.'\',\'SITE_TITLE\',\''.$remote_connection->escape_string(htmlspecialchars($data['title'])).'\')');
830+ $x[]=$remote_connection->query('INSERT INTO `system_siteinfo` VALUES(\''.$site_ref.'\',\'URL_SITE\',\'http://'.$remote_connection->escape_string($data['subdomain'].'.'.$data['domain']).'/\')');
831+ $x[]=$remote_connection->query('INSERT INTO `system_siteinfo` VALUES(\''.$site_ref.'\',\'SITE_AUTHOR\',\''.$remote_connection->escape_string(htmlspecialchars($data['author'])).'\')');
832+ $x[]=$remote_connection->query('INSERT INTO `system_siteinfo` VALUES(\''.$site_ref.'\',\'SITE_SLOGAN\',\''.$remote_connection->escape_string(htmlspecialchars($data['tagline'])).'\')');
833+ $x[]=$remote_connection->query('INSERT INTO `system_siteinfo` VALUES(\''.$site_ref.'\',\'SITE_CSS\',\''.$remote_connection->escape_string($data['style']).'\')');
834+ $x[]=$remote_connection->query('INSERT INTO `system_siteinfo` VALUES(\''.$site_ref.'\',\'SITE_LNG\',\''.$remote_connection->escape_string($data['language']).'\')');
835+ $x[]=$remote_connection->query('INSERT INTO `system_siteinfo` VALUES(\''.$site_ref.'\',\'SITE_FOOTER\',\''.$remote_connection->escape_string($data['footer']).'\')');
836+ $x[]=$remote_connection->query('INSERT INTO `system_siteinfo` VALUES(\''.$site_ref.'\',\'ADMIN_GROUP\',NULL)');
837+
838+ //Create site addons index
839+ $x[]=$remote_connection->query("CREATE TABLE `{$site_ref}_addons` (`name` varchar(30) NOT NULL,`reference` varchar(30) NOT NULL,`status` int(1) NOT NULL default '0',`gid` char(36) NULL default NULL,`editable` int(1) NOT NULL default '1') ENGINE=MyISAM DEFAULT CHARSET=latin1");
840+ $q=$remote_connection->query('SELECT * FROM `_system_` WHERE `key`=\'addons\''); //Get installed addons
841+ $prepared_q="INSERT INTO `{$site_ref}_addons` (`name`, `reference`, `status`, `gid`, `editable`) VALUES ('CMS', 'cms', 1, NULL, 0),('Column1', 'col1', 1, NULL, 0),('Column 3', 'col3', 1, NULL, 0),('File manager', 'filemanager', 1, NULL, 0)";
842+ $q=$q->fetch_assoc();
843+ $q['value']=preg_replace('@^&?(.*)&?$@', '$1', $q['value']);
844+ $addons=doubleExplode('&','=',$q['value']);
845+ foreach($addons as $name=>$addon) {
846+ $prepared_q.=",('$name', '$addon', 0, NULL, 1)";
847+ }
848+ $x[]=$remote_connection->query($prepared_q); //Dump addons into table
849+ //Create col1 table
850+ $x[]=$remote_connection->query("CREATE TABLE `{$site_ref}_col1` ( `id` int(11) NOT NULL AUTO_INCREMENT, `order` int(5) NOT NULL, `title` varchar(30) NOT NULL, `content` text NOT NULL, `plugin-reference` varchar(30) DEFAULT NULL, `access` int(1) NOT NULL DEFAULT '0', PRIMARY KEY (`id`)) ENGINE=MyISAM DEFAULT CHARSET=latin1");
851+ $remote_connection->query("TRUNCATE TABLE `{$site_ref}_col1`"); //Clean table
852+ //Dump col1 contents into table
853+ //No contents
854+ //Create col3 table
855+ $x[]=$remote_connection->query("CREATE TABLE `{$site_ref}_col3` ( `id` int(11) NOT NULL AUTO_INCREMENT, `order` int(5) NOT NULL, `title` varchar(30) NOT NULL, `content` text NOT NULL, `plugin-reference` varchar(30) DEFAULT NULL, `access` int(1) NOT NULL DEFAULT '0', PRIMARY KEY (`id`)) ENGINE=MyISAM DEFAULT CHARSET=latin1");
856+ $remote_connection->query("TRUNCATE TABLE `{$site_ref}_col3`"); //Clean table
857+ //Dump col3 contents into table
858+ //No contents
859+ //Create pageindex table
860+ $x[]=$remote_connection->query("CREATE TABLE `{$site_ref}_pageindex` ( `id` int(5) NOT NULL AUTO_INCREMENT, `type` int(1) NOT NULL DEFAULT '0', `page_order` int(5) NOT NULL, `page_title` text COLLATE latin1_general_ci NOT NULL, `link` text COLLATE latin1_general_ci NOT NULL, `access` int(1) NOT NULL DEFAULT '0', `visible` int(11) NOT NULL DEFAULT '1', PRIMARY KEY (`id`)) ENGINE=MyISAM DEFAULT CHARSET=latin1 COLLATE=latin1_general_ci;");
861+ $remote_connection->query("TRUNCATE TABLE `{$site_ref}_pageindex`"); //Clean table
862+ //Dump pageindex contents into table
863+ $x[]=$remote_connection->query("INSERT INTO `{$site_ref}_pageindex` (`id`, `type`, `page_order`, `page_title`, `link`, `access`, `visible`) VALUES(1, 2, 1, 'Home', '', 0, 1)");
864+ //Create pages tables
865+ $x[]=$remote_connection->query("CREATE TABLE `{$site_ref}_pages` ( `id` int(11) NOT NULL AUTO_INCREMENT, `page_id` int(5) NOT NULL, `section_order` int(11) NOT NULL DEFAULT '1', `section_title` text COLLATE latin1_general_ci NOT NULL, `section_main` text COLLATE latin1_general_ci NOT NULL, `plugin-reference` varchar(30) COLLATE latin1_general_ci DEFAULT NULL, PRIMARY KEY (`id`)) ENGINE=MyISAM DEFAULT CHARSET=latin1 COLLATE=latin1_general_ci");
866+ $remote_connection->query("TRUNCATE TABLE `{$site_ref}_pages`"); //Clean table
867+ //Dump pages contents into table
868+ //No contents
869+ //Create MySQLfs index table
870+ $x[]=$remote_connection->query("CREATE TABLE `{$site_ref}_fs` (`path` varchar(900) NOT NULL,`filename` varchar(100) NOT NULL,`rights` int(3) unsigned zerofill NOT NULL DEFAULT '777',`owner` char(36) DEFAULT NULL,`group` char(36) DEFAULT NULL,`time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,`type` enum('d','f') NOT NULL,`mime` varchar(100) NOT NULL DEFAULT 'application/octet-stream',`size` int(11) unsigned NOT NULL DEFAULT '0',`mfi` int(11) unsigned NOT NULL AUTO_INCREMENT,UNIQUE KEY `path` (`path`,`filename`),UNIQUE KEY `mfi` (`mfi`)) ENGINE=MyISAM");
871+ //Dump MySQLfs primary folder
872+ $x[]=$remote_connection->query("INSERT INTO `{$site_ref}_fs` (`path`, `filename`, `rights`, `owner`, `group`, `time`, `type`, `mime`, `size`, `mfi`) VALUES('/', '', 777, NULL, NULL, NULL, 'd', 'application/octet-stream', 0, 1);");
873+ //Create MySQLfs data table
874+ $x[]=$remote_connection->query("CREATE TABLE `{$site_ref}_fsdata` (`id` int(11) unsigned NOT NULL AUTO_INCREMENT,`masterid` int(11) unsigned NOT NULL,`data` blob NOT NULL,PRIMARY KEY (`id`),KEY `masterid` (`masterid`)) ENGINE=MyISAM");
875+ //Assign admin link
876+ $x[]=$remote_connection->query("INSERT INTO `sites` VALUES ('".session::$guid."', '{$site_ref}', '')");
877+ if(in_array(false, $x,true)) REST::output()->setData(array('status'=>false));
878+ else REST::output()->setData(array('status'=>true,'id'=>$site_ref));
879+ break;
880+ default:
881+ return false;
882+}
883\ No newline at end of file
884
885=== added directory 'api/modules/database/site'
886=== added file 'api/modules/database/site/database.site.a.php'
887--- api/modules/database/site/database.site.a.php 1970-01-01 00:00:00 +0000
888+++ api/modules/database/site/database.site.a.php 2011-12-11 19:47:27 +0000
889@@ -0,0 +1,49 @@
890+<?php
891+switch(REST::getMethod()) {
892+ case REST::get:
893+ $addons=array();
894+ $users=array();
895+ $q0=$remote_connection->query('SELECT * FROM `'.SITE.'_addons');
896+ while($addon=$q0->fetch_assoc()) {
897+ $addons[]=array('name'=>$addon['name'],'identifier'=>$addon['reference'],'status'=>(bool)$addon['status'],'administrator_group'=>$addon['gid'],'editable'=>(bool)$addon['editable']);
898+ }
899+ $q0->free();
900+ $q1=$remote_connection->query('SELECT * FROM `sites` WHERE `ref`=\''.SITE.'\'');
901+ while($user=$q1->fetch_assoc()) {
902+ $users[]=array('user'=>$user['user'],'role'=>$user['title']);
903+ }
904+ $q1->free();
905+ REST::output()->setData(array('addons'=>$addons,'users'=>$users));
906+ break;
907+ case REST::put:
908+ auth::granted(auth::write_db_sites_edit);
909+ REST::check()->parameter_exists('user');
910+ $data=REST::input()->getData();
911+ REST::check()->assure(session::userExists($data['user']),new NotFoundException('This user does not exist'));
912+ REST::check()->assure(isSiteFullAdmin(),new ForbiddenException('You are not allowed to add a user to this site'));
913+ if(isset($data['role'])) {
914+ REST::check()->preg_match('/^[a-zA-Z\\-\\_ ]*$/', $data['role'],'role');
915+ }
916+ else {
917+ $data['role']='';
918+ }
919+ $q=$remote_connection->query('INSERT INTO `sites` VALUES (\''.$data['user'].'\',\''.SITE.'\',\''.$data['role'].'\')');
920+ if($q) REST::output()->setData(array('status'=>true));
921+ else REST::output()->setData(array('status'=>false));
922+ break;
923+ case REST::delete:
924+ auth::granted(auth::write_db_sites_new);
925+ $x=array();
926+ $tables=$remote_connection->query('SHOW TABLES LIKE \''.SITE.'_%\'');
927+ while($table=$tables->fetch_array()) {
928+ $x[]=$remote_connection->query('DROP TABLE `'.$table[0].'`');
929+ }
930+ $x[]=$remote_connection->query('DELETE FROM `system_domains` WHERE `site`=\''.SITE.'\'');
931+ $x[]=$remote_connection->query('DELETE FROM `system_siteinfo` WHERE `site_ref`=\''.SITE.'\'');
932+ $x[]=$remote_connection->query('DELETE FROM `sites` WHERE `ref`=\''.SITE.'\'');
933+ if(!in_array(false,$x,true)) REST::output()->setData(array('status'=>true));
934+ else REST::output()->setData(array('status'=>false));
935+ break;
936+ default:
937+ return false;
938+}
939
940=== added file 'api/modules/database/site/database.site.subhandler.php'
941--- api/modules/database/site/database.site.subhandler.php 1970-01-01 00:00:00 +0000
942+++ api/modules/database/site/database.site.subhandler.php 2011-12-11 19:47:27 +0000
943@@ -0,0 +1,13 @@
944+<?php
945+$site_ref=REST::input()->getParts(2);
946+$_GET['site']=$site_ref;
947+REST::load('inc/accountlevels.php');
948+REST::load('inc/groups/groups.php');
949+$sitecheck=$remote_connection->query('SELECT COUNT(*) FROM `sites` WHERE `user`=\''.session::$guid.'\' AND `ref`=\''.$site_ref.'\'')->fetch_array();
950+REST::check()->assure($sitecheck[0]==1, new UnauthorizedException('You do not have access to this site'));
951+//Running at database/{ID}/site/{GUID}
952+REST::dispatch('','a')
953+->dispatch('user/{GUID}','user')
954+->dispatch('addon','addon')
955+->dispatch('addon/*','addon.subhandler')
956+;
957
958=== added file 'api/modules/database/site/database.site.user.php'
959--- api/modules/database/site/database.site.user.php 1970-01-01 00:00:00 +0000
960+++ api/modules/database/site/database.site.user.php 2011-12-11 19:47:27 +0000
961@@ -0,0 +1,24 @@
962+<?php
963+$username=REST::input()->getParts(4);
964+$sitecheck=$remote_connection->query('SELECT * FROM `sites` WHERE `user`=\''.$username.'\' AND `ref`=\''.SITE.'\'');
965+REST::check()->assure($sitecheck->num_rows==1, new NotFoundException('This user is not a member of this site'));
966+switch(REST::getMethod()) {
967+ case REST::get:
968+ $role=$sitecheck->fetch_object()->title;
969+ REST::output()->setData(array('role'=>$role));
970+ break;
971+ case REST::post:
972+ REST::check()->parameter_exists('role');
973+ $data=REST::input()->getData();
974+ $q=$remote_connection->query('UPDATE `sites` SET `title`=\''.$remote_connection->escape_string($data['role']).'\' WHERE `user`=\''.$username.'\' AND `ref`=\''.SITE.'\'');
975+ if($q) REST::output()->setData(array('status'=>true));
976+ else REST::output()->setData(array('status'=>false));
977+ break;
978+ case REST::delete:
979+ $q=$remote_connection->query('DELETE FROM `sites` WHERE `user`=\''.$username.'\' AND `ref`=\''.SITE.'\'');
980+ if($q) REST::output()->setData(array('status'=>true));
981+ else REST::output()->setData(array('status'=>false));
982+ break;
983+ default:
984+ return false;
985+}
986\ No newline at end of file
987
988=== added directory 'api/modules/user'
989=== modified file 'api/modules/user.php'
990--- api/modules/user.php 2011-09-22 16:07:24 +0000
991+++ api/modules/user.php 2011-12-11 19:47:27 +0000
992@@ -1,98 +1,9 @@
993 <?php
994 $input=REST::input();
995 $method=REST::getMethod();
996-if($input->getPart()=='') {
997- switch ($method) {
998- case REST::get: //List
999- $q=$local_connection->query('SELECT `GUID`,`username` FROM `users`');
1000- while($r=$q->fetch_assoc()) {
1001- REST::output()->appendData($r);
1002- }
1003- break;
1004- case REST::put: //Create new
1005- auth::init();
1006- auth::granted(auth::all,true);
1007- if(!session::isAdmin()) throw new UnauthorizedException('You need admin privileges to create a user');
1008- $data=$input->getData();
1009- if(!isset($data['username'],$data['password'],$data['email'])) throw new BadRequestException('Please provide username, password and email parameters');
1010- if(session::register($data['username'], $data['password'], $data['email'])) {
1011- REST::output()->setData(array('status'=>true,'errors'=>array()));
1012- REST::success(201);
1013- }
1014- else {
1015- $errors=JSError::get();
1016- REST::output()->setData(array('status'=>false,'errors'=>$errors));
1017- }
1018- break;
1019- default:
1020- throw new MethodNotAllowedException('Invalid method for "'.$input->getPart().'" on "'.$input->getModule().'"');
1021- }
1022-}
1023-else if(strlen($input->getPart())==36&&preg_match('/^[0-9A-F]{8}-([0-9A-F]{4}-){3}[0-9A-F]{12}$/i', $input->getPart())) { //User by guid
1024- switch ($method) {
1025- case REST::get: //Show user info
1026- auth::init();
1027- $q=$local_connection->query('SELECT `GUID`,`username` FROM `users` WHERE `GUID`=\''.$local_connection->escape_string($input->getPart()).'\'');
1028- if($q->num_rows!=1) throw new NotFoundException('This user does not exist');
1029- $data=$q->fetch_assoc();
1030- REST::output()->setData($data);
1031- break;
1032- case REST::delete: //Delete this user
1033- auth::init();
1034- auth::granted(auth::all,true);
1035- if(!session::isAdmin()) throw new UnauthorizedException('You need admin privileges to delete a user');
1036- $q=$local_connection->query('DELETE FROM `users` WHERE `GUID`=\''.$local_connection->escape_string($input->getPart().'\''));
1037- if($q) REST::output()->setData(array('status'=>true));
1038- else REST::output()->setData(array('status'=>false));
1039- default:
1040- throw new MethodNotAllowedException('Invalid method for "'.$input->getPart().'" on "'.$input->getModule().'"');
1041- }
1042-}
1043-elseif($input->getPart()=='search') {
1044- switch($method) {
1045- case REST::get:
1046- $data=$input->getData();
1047- if(!isset($data['username'])) $data['username']='';
1048- $q=$local_connection->query('SELECT `GUID`,`username` FROM `users` WHERE `username` LIKE \''.$local_connection->escape_string($data['username']).'\'');
1049- while($r=$q->fetch_assoc()){
1050- REST::output()->appendData($r);
1051- }
1052- break;
1053- default:
1054- throw new MethodNotAllowedException('Invalid method for "'.$input->getPart().'" on "'.$input->geModule().'"');
1055- }
1056-}
1057-elseif($input->getPart()=='me') {
1058- switch ($method) {
1059- case REST::get: //Show user info
1060- auth::init();
1061- $mail=auth::granted(auth::read_mail_addr);
1062- $lang=auth::granted(auth::read_lang);
1063- $q=$local_connection->query('SELECT `GUID`,`username`'.($mail?',`email`':'').($lang?',`lang`':'').' FROM `users` WHERE `GUID`=\''.$local_connection->escape_string(session::$guid).'\'');
1064- if($q->num_rows!=1) throw new GoneException('Authenticated user no longer exists');
1065- $data=$q->fetch_assoc();
1066- if(isset($data['lang'])) $data['lang']=unserialize($data['lang']);
1067- REST::output()->setData($data);
1068- break;
1069- case REST::post: //Update user info
1070- auth::init();
1071- auth::granted(auth::write_lang,true);
1072- $data=$input->getData();
1073- if(!isset($data['lang'])) throw new BadRequestException('Please provide lang parameter');
1074- $data['lang']=(REST::getDataType()==REST::json?json_decode($data['lang']):unserialize($data['lang']));
1075- if(!is_array($data['lang'])) throw new BadRequestException('Please provide a valid lang parameter');
1076- $q=$local_connection->query('UPDATE `users` SET `lang`=\''.serialize($data['lang']).'\' WHERE `GUID`=\''.$local_connection->escape_string(session::$guid).'\'');
1077- if($q) {
1078- REST::output()->setData(array('status'=>true));
1079- }
1080- else {
1081- REST::output()->setData(array('status'=>false));
1082- }
1083- break;
1084- default:
1085- throw new MethodNotAllowedException('Invalid method for "'.$input->getPart().'" on "'.$input->getModule().'"');
1086- }
1087-}
1088-else {
1089- throw new NotImplementedException('"'.$input->getPart().'" is not implemented in the module "'.$input->getModule().'"');
1090-}
1091\ No newline at end of file
1092+REST::dispatch()
1093+->override('user',NULL,'./user')
1094+->dispatch('{GUID}', 'a')
1095+->dispatch('search', 'search')
1096+->dispatch('me', 'me')
1097+->dispatch('', '');
1098\ No newline at end of file
1099
1100=== added file 'api/modules/user/user.a.php'
1101--- api/modules/user/user.a.php 1970-01-01 00:00:00 +0000
1102+++ api/modules/user/user.a.php 2011-12-11 19:47:27 +0000
1103@@ -0,0 +1,19 @@
1104+<?php
1105+$input=REST::input();
1106+switch (REST::getMethod()) {
1107+ case REST::get: //Show user info
1108+ $q=$local_connection->query('SELECT `GUID`,`username` FROM `users` WHERE `GUID`=\''.$local_connection->escape_string($input->getPart()).'\'');
1109+ if($q->num_rows!=1) throw new NotFoundException('This user does not exist');
1110+ $data=$q->fetch_assoc();
1111+ REST::output()->setData($data);
1112+ break;
1113+ case REST::delete: //Delete this user
1114+ auth::init();
1115+ auth::granted(auth::all,true);
1116+ REST::check()->assure(session::isAdmin(),new UnauthorizedException('You need admin privileges to delete a user'));
1117+ $q=$local_connection->query('DELETE FROM `users` WHERE `GUID`=\''.$local_connection->escape_string($input->getPart().'\''));
1118+ if($q) REST::output()->setData(array('status'=>true));
1119+ else REST::output()->setData(array('status'=>false));
1120+ default:
1121+ return false;
1122+}
1123\ No newline at end of file
1124
1125=== added file 'api/modules/user/user.me.php'
1126--- api/modules/user/user.me.php 1970-01-01 00:00:00 +0000
1127+++ api/modules/user/user.me.php 2011-12-11 19:47:27 +0000
1128@@ -0,0 +1,30 @@
1129+<?php
1130+switch (REST::getMethod()) {
1131+ case REST::get: //Show user info
1132+ auth::init();
1133+ $mail=auth::granted(auth::read_mail_addr);
1134+ $lang=auth::granted(auth::read_lang);
1135+ $q=$local_connection->query('SELECT `GUID`,`username`'.($mail?',`email`':'').($lang?',`lang`':'').' FROM `users` WHERE `GUID`=\''.$local_connection->escape_string(session::$guid).'\'');
1136+ if($q->num_rows!=1) throw new GoneException('Authenticated user no longer exists');
1137+ $data=$q->fetch_assoc();
1138+ if(isset($data['lang'])) $data['lang']=unserialize($data['lang']);
1139+ REST::output()->setData($data);
1140+ break;
1141+ case REST::post: //Update user info
1142+ auth::init();
1143+ auth::granted(auth::write_lang,true);
1144+ $data=REST::input()->getData();
1145+ REST::check()->parameter_exists('lang');
1146+ $data['lang']=(REST::getDataType()==REST::json?json_decode($data['lang']):unserialize($data['lang']));
1147+ if(!is_array($data['lang'])) throw new BadRequestException('Please provide a valid lang parameter');
1148+ $q=$local_connection->query('UPDATE `users` SET `lang`=\''.serialize($data['lang']).'\' WHERE `GUID`=\''.$local_connection->escape_string(session::$guid).'\'');
1149+ if($q) {
1150+ REST::output()->setData(array('status'=>true));
1151+ }
1152+ else {
1153+ REST::output()->setData(array('status'=>false));
1154+ }
1155+ break;
1156+ default:
1157+ return false;
1158+}
1159\ No newline at end of file
1160
1161=== added file 'api/modules/user/user.php'
1162--- api/modules/user/user.php 1970-01-01 00:00:00 +0000
1163+++ api/modules/user/user.php 2011-12-11 19:47:27 +0000
1164@@ -0,0 +1,29 @@
1165+<?php
1166+$input=REST::input();
1167+switch (REST::getMethod()) {
1168+ case REST::get: //List
1169+ $q=$local_connection->query('SELECT `GUID`,`username` FROM `users`');
1170+ while($r=$q->fetch_assoc()) {
1171+ REST::output()->appendData($r);
1172+ }
1173+ break;
1174+ case REST::put: //Create new
1175+ auth::init();
1176+ auth::granted(auth::all,true);
1177+ REST::check()->assure(session::isAdmin(),new UnauthorizedException('You need admin privileges to create a user'));
1178+ $data=$input->getData();
1179+ REST::check()->parameter_exists('username');
1180+ REST::check()->parameter_exists('password');
1181+ REST::check()->parameter_exists('email');
1182+ if(session::register($data['username'], $data['password'], $data['email'])) {
1183+ REST::output()->setData(array('status'=>true,'errors'=>array()));
1184+ REST::success(201);
1185+ }
1186+ else {
1187+ $errors=JSError::get();
1188+ REST::output()->setData(array('status'=>false,'errors'=>$errors));
1189+ }
1190+ break;
1191+ default:
1192+ return false;
1193+}
1194\ No newline at end of file
1195
1196=== added file 'api/modules/user/user.search.php'
1197--- api/modules/user/user.search.php 1970-01-01 00:00:00 +0000
1198+++ api/modules/user/user.search.php 2011-12-11 19:47:27 +0000
1199@@ -0,0 +1,9 @@
1200+<?php
1201+if(REST::getMethod()!==REST::get) return false;
1202+$data=REST::input()->getData();
1203+REST::check()->parameter_exists('username');
1204+$q=$local_connection->query('SELECT `GUID`,`username` FROM `users` WHERE `username` LIKE \''.$local_connection->escape_string($data['username']).'\'');
1205+REST::output()->setData(array('matches'=>$q->num_rows));
1206+while($r=$q->fetch_assoc()){
1207+ REST::output()->appendData($r);
1208+}
1209\ No newline at end of file
1210
1211=== added file 'api/paths.txt'
1212--- api/paths.txt 1970-01-01 00:00:00 +0000
1213+++ api/paths.txt 2011-12-11 19:47:27 +0000
1214@@ -0,0 +1,77 @@
1215+RemoteCP API paths
1216+------------------
1217+1. User (user.*)
1218+-------
1219+GET user Show all usernames and GUIDs (user.core)
1220+PUT user (AUTH::all, session::isAdmin()) Create a new user (needs 'username', 'password', 'email') (user.core)
1221+GET user/{GUID} Show information about user with GUID {GUID} (user.a)
1222+DELETE user/{GUID} (AUTH::all, session::isAdmin()) Delete the user with GUID {GUID} (user.a)
1223+GET user/search Search for a username matching the pattern in 'username' (needs 'username') (user.search-
1224+GET user/me Get information about the authenticated user (user.me)
1225+POST user/me (AUTH::write_lang) Update user information of the authenticated user (needs 'lang':array) (user.me)
1226+
1227+2. Database (AUTH::read_db) (database.*)
1228+---------------------------
1229+GET database Show all databases accessible by the authenticated user (database.core)
1230+DELETE database/{ID} (AUTH::all, rdb_auth::$level=9) Delete the database with id {ID} (database.a)
1231+
1232+2.1. Groups (database.group)
1233+-----------
1234+GET database/{ID}/group Get all groups of the user
1235+PUT database/{ID}/group (AUTH::write_db_groups) Add a group
1236+
1237+2.1.1. A group (database.group.a)
1238+--------------
1239+GET database/{ID}/group/{GID} Gets information about a group: name and users
1240+PUT database/{ID}/group/{GID} (AUTH::write_db_groups) Adds a new user to group {GID} (needs 'user':GUID)
1241+POST database/{ID}/group/{GID} (AUTH::write_db_groups) Change group information of group {GID} (needs 'name')
1242+
1243+2.1.1.1. Users in a group (database.group.a.user)
1244+-------------------------
1245+GET database/{ID}/group/{GID}/{GUID} Checks if the user {GUID} belongs to the group {GID}
1246+POST database/{ID}/group/{GID}/{GUID} (AUTH::write_db_groups) Changes properties of the user {GUID} in the group {GID} (needs 'administrator':bool)
1247+
1248+2.2. Sites (database.site)
1249+----------
1250+GET database/{ID}/site Gets all sites on the database
1251+PUT database/{ID}/site (AUTH::write_db_sites_new) Create a new site (needs:'domain','subdomain','style','language','title','tagline','footer','author')
1252+
1253+2.2.1. A site (database.site.a)
1254+-------------
1255+GET database/{ID}/site/{SID} Retrieves all addons and users of the site (+ user level and addon status)
1256+PUT database/{ID}/site/{SID} (AUTH::write_db_sites_edit) Add a new user to the site (needs:'user',optional:'role')
1257+DELETE database/{ID}/site/{SID} (AUTH::write_db_sites_new) Removes a site
1258+
1259+2.2.1.1. A site user (database.site.user)
1260+--------------------
1261+GET database/{ID}/site/{SID}/user/{GUID} Retieve user role on the site
1262+POST database/{ID}/site/{SID}/user/{GUID} (AUTH::write_db_sites_edit) Change the role of a user (needs: 'role')
1263+DELETE database/{ID}/site/{SID}/user/{GUID} (AUTH::write_db_sites_edit) Remove a user from the site editors
1264+
1265+2.2.1.2. Addons of a site (database.site.addon)
1266+-------------------------
1267+*GET database/{ID}/site/{SID}/addon Retieves a list of installed, a list of available addons and a list of addons available on runner but not on panel
1268+*PUT database/{ID}/site/{SID}/addon (AUTH::write_db_sites_edit) Forwarded to ./{AID} where {AID}=addon (needs:'addon')
1269+*POST database/{ID}/site/{SID}/addon (AUTH::write_db_sites_edit) Changes the administrator group of an addon (needs:'addon','admingroup')
1270+
1271+2.2.1.2.1 An addon (database.site.addon.subhandler) (Recommended: Implementation may vary)
1272+------------------
1273+*GET database/{ID}/site/{SID}/addon/{AID} Retieves a list of exposed functions
1274+*POST database/{ID}/site/{SID}/addon/{AID} (AUTH::write_db_sites_edit) Forwarded to .. where addon={AID}
1275+*PUT database/{ID}/site/{SID}/addon/{AID} (AUTH::write_db_sites_edit) Installs the addon
1276+*DELETE database/{ID}/site/{SID}/addon/{AID} (AUTH::write_db_sites_edit) Removes the addon
1277+
1278+2.3. Database settings (database.settings)
1279+----------------------
1280+GET database/{ID}/settings Retrieve all information about the database (no credentials)
1281+POST database/{ID}/settings (AUTH::all) Update database information (no credentials)
1282+
1283+2.4. Database users (database.user)
1284+-------------------
1285+*GET database/{ID}/user Gets all users allowed to access the database
1286+*PUT database/{ID}/user Adds a new user allowed to access the database
1287+
1288+2.4.1 A database user (database.user.a)
1289+---------------------
1290+*POST database/{ID}/user/{GUID} Change user admin state (needs:'administrator':bool)
1291+*DELETE database/{ID}/user/{GUID} Remove a user from the database
1292\ No newline at end of file
1293
1294=== modified file 'api/request.php'
1295--- api/request.php 2011-09-22 13:55:20 +0000
1296+++ api/request.php 2011-12-11 19:47:27 +0000
1297@@ -1,4 +1,6 @@
1298 <?php
1299+echo '<!DOCTYPE ><html><head><title>API request sender</title><style>'.
1300+ 'input { width: 80% } textarea { width: 100%; height: 80px;}</style></head><body>';
1301 echo '<form method="POST">';
1302 echo '<select name="method">';
1303 if(!isset($_POST['method'])) $method='GET';
1304@@ -36,4 +38,5 @@
1305 }
1306 echo '</pre>';
1307 fclose($sock);
1308-}
1309\ No newline at end of file
1310+}
1311+echo '</body></html>';
1312\ No newline at end of file
1313
1314=== modified file 'api/responder.php'
1315--- api/responder.php 2011-09-13 19:41:07 +0000
1316+++ api/responder.php 2011-12-11 19:47:27 +0000
1317@@ -1,7 +1,35 @@
1318 <?php
1319 define('NO_UURL', true);
1320+header('HTTP/1.1 500 Internal Server Error');
1321+ob_start();
1322+function error_to_exception($enum,$estring,$efile,$eline) {
1323+ if(error_reporting()===0) {
1324+ return;
1325+ }
1326+ throw new ErrorException($estring, 0, $enum, $efile, $eline);
1327+}
1328+set_error_handler('error_to_exception',-1);
1329+function shutdown() {
1330+ if ($error = error_get_last()) {
1331+ ob_clean();
1332+ switch($error['type']) {
1333+ case E_ERROR:
1334+ case E_CORE_ERROR:
1335+ case E_COMPILE_ERROR:
1336+ case E_USER_ERROR:
1337+ REST::error(500, $error['message']);
1338+ }
1339+ }
1340+}
1341+//register_shutdown_function('shutdown');
1342 try {
1343- require 'REST_entry.php';
1344+ require 'REST/REST.php';
1345+ require 'auth/auth.php';
1346+ $module=REST::input()->getModule();
1347+ if(!file_exists('modules/'.$module.'.php')) {
1348+ throw new NotFoundException('Module '.$module.' does not exist');
1349+ }
1350+ require 'modules/'.$module.'.php';
1351 }
1352 catch (HTTPException $e) {
1353 REST::error($e->getCode(), $e->getMessage());
1354
1355=== modified file 'inc/groups/groups.php'
1356--- inc/groups/groups.php 2011-09-02 16:38:47 +0000
1357+++ inc/groups/groups.php 2011-12-11 19:47:27 +0000
1358@@ -52,7 +52,7 @@
1359 JSError::add($t->_('You are not an administrator of that group'));
1360 return false;
1361 }
1362- return self::$dbconn->query('INSERT INTO `groups` VALUES(\''.self::$dbconn->escape_string($group).'\',\''.self::$dbconn->escape_string($user).'\',NULL)');
1363+ return self::$dbconn->query('INSERT INTO `groups` VALUES(\''.self::$dbconn->escape_string($group).'\',\''.self::$dbconn->escape_string($user).'\',0)');
1364 }
1365 /**
1366 * Checks wether a group exists
1367
1368=== modified file 'inc/rdb/auth.php'
1369--- inc/rdb/auth.php 2011-10-19 19:38:18 +0000
1370+++ inc/rdb/auth.php 2011-12-11 19:47:27 +0000
1371@@ -13,7 +13,7 @@
1372 $dblookup=$local_connection->query('SELECT * FROM `remote_databases` WHERE `key`=\''.substr($_SERVER['PATH_INFO'],1,32).'\'');
1373 if($dblookup->num_rows==1)
1374 self::$exists=true;
1375- else
1376+ else
1377 return;
1378 if(($chkauth=self::checkauth())!==false) {
1379 self::$logged_in=true;
1380
1381=== added file 'inc/utils/validDomainName.php'
1382--- inc/utils/validDomainName.php 1970-01-01 00:00:00 +0000
1383+++ inc/utils/validDomainName.php 2011-12-11 19:47:27 +0000
1384@@ -0,0 +1,15 @@
1385+<?php
1386+function is_valid_domain_name($domain_name)
1387+{
1388+ $pieces = explode(".",$domain_name);
1389+ if(count($pieces)<2) return false;
1390+ foreach($pieces as $piece)
1391+ {
1392+ if (!preg_match('/^[a-z\d][a-z\d-]{0,62}$/i', $piece)
1393+ || preg_match('/-$/', $piece) )
1394+ {
1395+ return false;
1396+ }
1397+ }
1398+ return true;
1399+}
1400
1401=== modified file 'licenses/licenses.txt'
1402--- licenses/licenses.txt 2011-09-18 16:51:00 +0000
1403+++ licenses/licenses.txt 2011-12-11 19:47:27 +0000
1404@@ -10,6 +10,7 @@
1405 inc/utils/guid.php Public Domain Soulhuntre: Core Dump http://www.soulhuntre.com/2004/10/29/uuid-guid-in-native-php/
1406 inc/utils/languageCodes.php Public Domain krillzip (adapted by Lars Vierbergen) http://snipplr.com/view/46886/
1407 inc/utils/time_ago.php Public Domain Viral Patel (adapted by Lars Vierbergen) http://viralpatel.net/blogs/2009/06/twitter-like-n-min-sec-ago-timestamp-in-php-mysql.html
1408+inc/utils/validDomainName.php Public Domain velcrow (adapted by Lars Vierbergen) http://stackoverflow.com/questions/1755144/how-to-validate-domain-name-in-php
1409 php.js/dirname.js MIT, GPL Ozh, XoraX http://phpjs.org/functions/dirname:388
1410 scripts/permanent/jquery_escape.js Public Domain Karl Varga http://kjvarga.blogspot.com/2009/06/jquery-plugin-to-escape-css-selector.html
1411 scripts/permanent/jquery.timepicker.js, css/jquery.timepicker.css MIT, GPL Trent Richardson http://trentrichardson.com
1412
1413=== removed directory 'zz-schemas'
1414=== removed file 'zz-schemas/SSO diagram servers.dia'
1415Binary files zz-schemas/SSO diagram servers.dia 2011-03-27 18:43:25 +0000 and zz-schemas/SSO diagram servers.dia 1970-01-01 00:00:00 +0000 differ
1416=== removed file 'zz-schemas/SSO diagram.dia'
1417Binary files zz-schemas/SSO diagram.dia 2011-03-25 20:23:35 +0000 and zz-schemas/SSO diagram.dia 1970-01-01 00:00:00 +0000 differ
1418=== removed file 'zz-schemas/new_userscheme.dia'
1419Binary files zz-schemas/new_userscheme.dia 2011-03-31 16:36:14 +0000 and zz-schemas/new_userscheme.dia 1970-01-01 00:00:00 +0000 differ
1420=== removed file 'zz-schemas/schemas.readme.txt'
1421--- zz-schemas/schemas.readme.txt 2011-06-28 16:13:01 +0000
1422+++ zz-schemas/schemas.readme.txt 1970-01-01 00:00:00 +0000
1423@@ -1,2 +0,0 @@
1424-These schemas are made with Dia.
1425-Dia is open-source software. Get your copy at http://live.gnome.org/Dia
1426\ No newline at end of file

Subscribers

People subscribed via source and target branches

to all changes: