File indexing completed on 2025-05-04 05:29:06
0001 <?php 0002 /** 0003 * ocs-webserver 0004 * 0005 * Copyright 2016 by pling GmbH. 0006 * 0007 * This file is part of ocs-webserver. 0008 * 0009 * This program is free software: you can redistribute it and/or modify 0010 * it under the terms of the GNU Affero General Public License as 0011 * published by the Free Software Foundation, either version 3 of the 0012 * License, or (at your option) any later version. 0013 * 0014 * This program is distributed in the hope that it will be useful, 0015 * but WITHOUT ANY WARRANTY; without even the implied warranty of 0016 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 0017 * GNU Affero General Public License for more details. 0018 * 0019 * You should have received a copy of the GNU Affero General Public License 0020 * along with this program. If not, see <http://www.gnu.org/licenses/>. 0021 **/ 0022 0023 /** 0024 * What changes from official OCS v1 spec 0025 * 0026 * OCS specification: 0027 * http://www.freedesktop.org/wiki/Specifications/open-collaboration-services/ 0028 * 0029 * ---- 0030 * 0031 * Allow delimiter ',' of value of parameter 'categories' 0032 * 0033 * Example: 0034 * /content/data?categories=1,2,3 0035 * /content/data?categories=1x2x3 0036 * 0037 * ---- 0038 * 0039 * Additional URL queries to '/content/data' 0040 * 0041 * xdg_types 0042 * package_types 0043 * 0044 * Example: 0045 * /content/data?xdg_types=icons,themes,wallpapers 0046 * /content/data?package_types=1,2,3 0047 * 0048 * package_types: 0049 * 1 = AppImage 0050 * 2 = Android (apk) 0051 * 3 = OS X compatible 0052 * 4 = Windows executable 0053 * 5 = Debian 0054 * 6 = Snappy 0055 * 7 = Flatpak 0056 * 8 = Electron-Webapp 0057 * 9 = Arch 0058 * 10 = open/Suse 0059 * 11 = Redhat 0060 * 12 = Source Code 0061 * 0062 * ---- 0063 * 0064 * Additional data field of '/content/categories' 0065 * 0066 * display_name 0067 * parent_id 0068 * xdg_type 0069 * 0070 * ---- 0071 * 0072 * Additional data field of '/content/data' 0073 * 0074 * xdg_type 0075 * download_package_type{n} 0076 * download_package_arch{n} 0077 * 0078 * ---- 0079 * 0080 * Additional data field of '/content/download' 0081 * 0082 * download_package_type 0083 * download_package_arch 0084 * 0085 * ---- 0086 * 0087 * Additional API method for preview picture 0088 * 0089 * /content/previewpic/{contentid} 0090 * 0091 * Example: 0092 * /content/previewpic/123456789 0093 * /content/previewpic/123456789?size=medium 0094 */ 0095 class Ocsv1Controller extends Zend_Controller_Action 0096 { 0097 0098 const COMMENT_TYPE_CONTENT = 1; 0099 const COMMENT_TYPE_FORUM = 4; 0100 const COMMENT_TYPE_KNOWLEDGE = 7; 0101 const COMMENT_TYPE_EVENT = 8; 0102 0103 protected $_authData = null; 0104 0105 protected $_uriScheme = 'https'; 0106 0107 protected $_format = 'xml'; 0108 0109 protected $_config = array( 0110 'id' => 'opendesktop.org', 0111 'location' => 'https://www.opendesktop.org/ocs/v1/', 0112 'name' => 'opendesktop.org', 0113 'icon' => '', 0114 'termsofuse' => 'https://www.opendesktop.org/terms', 0115 'register' => 'https://www.opendesktop.org/register', 0116 'version' => '1.7', 0117 'website' => 'www.opendesktop.org', 0118 'host' => 'www.opendesktop.org', 0119 'contact' => 'contact@opendesktop.org', 0120 'ssl' => true, 0121 'user_host' => 'pling.me' 0122 ); 0123 0124 protected $_params = array(); 0125 0126 public function init() 0127 { 0128 parent::init(); 0129 $this->initView(); 0130 $this->_initUriScheme(); 0131 $this->_initRequestParamsAndFormat(); 0132 $this->_initConfig(); 0133 $this->_initResponseHeader(); 0134 } 0135 0136 public function initView() 0137 { 0138 // Disable render view 0139 $this->_helper->layout->disableLayout(); 0140 $this->_helper->viewRenderer->setNoRender(true); 0141 } 0142 0143 protected function _initUriScheme() 0144 { 0145 if (isset($_SERVER['HTTPS']) && ($_SERVER['HTTPS'] == 'on' || $_SERVER['HTTPS'] === '1')) { 0146 $this->_uriScheme = 'https'; 0147 } else { 0148 $this->_uriScheme = 'http'; 0149 } 0150 } 0151 0152 /** 0153 * @throws Zend_Exception 0154 */ 0155 protected function _initRequestParamsAndFormat() 0156 { 0157 // Set request parameters 0158 switch (strtoupper($_SERVER['REQUEST_METHOD'])) { 0159 case 'GET': 0160 $this->_params = $_GET; 0161 break; 0162 case 'PUT': 0163 parse_str(file_get_contents('php://input'), $_PUT); 0164 $this->_params = $_PUT; 0165 break; 0166 case 'POST': 0167 $this->_params = $_POST; 0168 break; 0169 default: 0170 Zend_Registry::get('logger')->err(__METHOD__ . ' - request method not supported - ' . $_SERVER['REQUEST_METHOD']); 0171 exit('request method not supported'); 0172 } 0173 0174 // Set format option 0175 if (isset($this->_params['format']) && strtolower($this->_params['format']) == 'json') { 0176 $this->_format = 'json'; 0177 } 0178 } 0179 0180 protected function _initConfig() 0181 { 0182 $clientConfig = $this->_loadClientConfig(); 0183 0184 $credentials = ''; 0185 if (!empty($_SERVER['PHP_AUTH_USER']) && !empty($_SERVER['PHP_AUTH_PW'])) { 0186 $credentials = $_SERVER['PHP_AUTH_USER'] . ':' . $_SERVER['PHP_AUTH_PW'] . '@'; 0187 } 0188 0189 $baseUri = $this->_uriScheme . '://' . $credentials . $_SERVER['SERVER_NAME']; 0190 0191 $webSite = $_SERVER['SERVER_NAME']; 0192 0193 //Mask api.kde-look.org to store.kde.org 0194 if (strpos($_SERVER['SERVER_NAME'], 'api.kde-look.org') !== false) { 0195 $webSite = 'store.kde.org'; 0196 } 0197 0198 $this->_config = array( 0199 'id' => $_SERVER['SERVER_NAME'], 0200 'location' => $baseUri . '/ocs/v1/', 0201 'name' => $clientConfig['head']['browser_title'], 0202 'icon' => $baseUri . $clientConfig['logo'], 0203 'termsofuse' => $baseUri . '/content/terms', 0204 'register' => $baseUri . '/register', 0205 'website' => $webSite, 0206 'host' => $_SERVER['SERVER_NAME'] 0207 ) + $this->_config; 0208 } 0209 0210 /** 0211 * @return array|null 0212 */ 0213 protected function _loadClientConfig() 0214 { 0215 $clientConfigReader = new Backend_Model_ClientFileConfig($this->_getNameForStoreClient()); 0216 $clientConfigReader->loadClientConfig(); 0217 0218 return $clientConfigReader->getConfig(); 0219 } 0220 0221 /** 0222 * Returns the name for the store client. 0223 * If no name were found, the name for the standard store client will be returned. 0224 * 0225 * @return string 0226 */ 0227 protected function _getNameForStoreClient() 0228 { 0229 $clientName = Zend_Registry::isRegistered('store_config') ? Zend_Registry::get('store_config')->name : Zend_Registry::get('config')->settings->client->default->name; 0230 0231 0232 return $clientName; 0233 } 0234 0235 protected function _initResponseHeader() 0236 { 0237 $duration = 1800; // in seconds 0238 $expires = gmdate("D, d M Y H:i:s", time() + $duration) . " GMT"; 0239 0240 $this->getResponse() 0241 ->setHeader('X-FRAME-OPTIONS', 'SAMEORIGIN', true) 0242 // ->setHeader('Last-Modified', $modifiedTime, true) 0243 ->setHeader('Expires', $expires, true) 0244 ->setHeader('Pragma', 'cache', true) 0245 ->setHeader('Cache-Control', 'max-age=1800, public', true) 0246 ; 0247 } 0248 0249 public function indexAction() 0250 { 0251 $this->_sendErrorResponse(999, 'unknown request'); 0252 } 0253 0254 protected function _sendErrorResponse($statuscode, $message = '', $local = false) 0255 { 0256 if ($this->_format == 'json') { 0257 $response = array( 0258 'status' => 'failed', 0259 'statuscode' => $statuscode, 0260 'message' => $message 0261 ); 0262 } else { 0263 $response = array( 0264 'meta' => array( 0265 'status' => array('@text' => 'failed'), 0266 'statuscode' => array('@text' => $statuscode), 0267 'message' => array('@text' => $message) 0268 ) 0269 ); 0270 } 0271 0272 $this->_sendResponse($response, $this->_format, $xmlRootTag = 'ocs', $local); 0273 } 0274 0275 protected function _sendResponse($response, $format = 'xml', $xmlRootTag = 'ocs', $local = false) 0276 { 0277 header('Pragma: public'); 0278 header('Cache-Control: cache, must-revalidate'); 0279 $duration = 1800; // in seconds 0280 $expires = gmdate("D, d M Y H:i:s", time() + $duration) . " GMT"; 0281 header('Expires: ' . $expires); 0282 if ($format == 'json') { 0283 header('Content-Type: application/json; charset=UTF-8'); 0284 if($local) { 0285 echo json_encode($response); 0286 } else { 0287 echo $response; 0288 } 0289 } else { 0290 header('Content-Type: application/xml; charset=UTF-8'); 0291 if($local) { 0292 echo $this->_convertXmlDom($response, $xmlRootTag)->saveXML(); 0293 } else { 0294 echo $response; 0295 } 0296 } 0297 0298 exit; 0299 } 0300 0301 protected function _convertXmlDom($values, $tagName = 'data', DOMNode &$dom = null, DOMElement &$element = null) 0302 { 0303 if (!$dom) { 0304 $dom = new DomDocument('1.0', 'UTF-8'); 0305 } 0306 if (!$element) { 0307 $element = $dom->appendChild($dom->createElement($tagName)); 0308 } 0309 if (is_array($values) || is_object($values)) { 0310 foreach ($values as $key => $value) { 0311 if (is_array($value) || is_object($value)) { 0312 $isHash = false; 0313 foreach ($value as $_key => $_value) { 0314 if (ctype_digit((string)$_key)) { 0315 $isHash = true; 0316 } 0317 break; 0318 } 0319 if ($isHash) { 0320 $this->_convertXmlDom($value, $key, $dom, $element); 0321 continue; 0322 } 0323 if (ctype_digit((string)$key)) { 0324 $key = $tagName; 0325 } 0326 $childElement = $element->appendChild($dom->createElement($key)); 0327 $this->_convertXmlDom($value, $key, $dom, $childElement); 0328 } else { 0329 if ($key == '@text') { 0330 if (is_bool($value)) { 0331 $value = var_export($value, true); 0332 } 0333 $element->appendChild($dom->createTextNode($value)); 0334 } else if ($key == '@cdata') { 0335 if (is_bool($value)) { 0336 $value = var_export($value, true); 0337 } 0338 $element->appendChild($dom->createCDATASection($value)); 0339 } else { 0340 if (is_bool($value)) { 0341 $value = var_export($value, true); 0342 } 0343 $element->setAttribute($key, $value); 0344 } 0345 } 0346 } 0347 } 0348 0349 return $dom; 0350 } 0351 0352 public function providersAction() 0353 { 0354 // As providers.xml 0355 $response = array( 0356 'provider' => array( 0357 'id' => array('@text' => $this->_config['id']), 0358 'location' => array('@text' => $this->_config['location']), 0359 'name' => array('@text' => $this->_config['name']), 0360 'icon' => array('@text' => $this->_config['icon']), 0361 'termsofuse' => array('@text' => $this->_config['termsofuse']), 0362 'register' => array('@text' => $this->_config['register']), 0363 'services' => array( 0364 'person' => array('ocsversion' => $this->_config['version']), 0365 'content' => array('ocsversion' => $this->_config['version']) 0366 ) 0367 ) 0368 ); 0369 0370 $this->_sendResponse($response, 'xml', 'providers', true); 0371 } 0372 0373 public function configAction() 0374 { 0375 if ($this->_format == 'json') { 0376 $response = array( 0377 'status' => 'ok', 0378 'statuscode' => 100, 0379 'message' => '', 0380 'data' => array( 0381 'version' => $this->_config['version'], 0382 'website' => $this->_config['website'], 0383 'host' => $this->_config['host'], 0384 'contact' => $this->_config['contact'], 0385 'ssl' => $this->_config['ssl'] 0386 ) 0387 ); 0388 } else { 0389 $response = array( 0390 'meta' => array( 0391 'status' => array('@text' => 'ok'), 0392 'statuscode' => array('@text' => 100), 0393 'message' => array('@text' => '') 0394 ), 0395 'data' => array( 0396 'version' => array('@text' => $this->_config['version']), 0397 'website' => array('@text' => $this->_config['website']), 0398 'host' => array('@text' => $this->_config['host']), 0399 'contact' => array('@text' => $this->_config['contact']), 0400 'ssl' => array('@text' => $this->_config['ssl']) 0401 ) 0402 ); 0403 } 0404 0405 $this->_sendResponse($response, $this->_format, 'ocs', true); 0406 } 0407 0408 public function personcheckAction() 0409 { 0410 $identity = null; 0411 $credential = null; 0412 if (!empty($this->_params['login'])) { 0413 $identity = $this->_params['login']; 0414 } 0415 if (!empty($this->_params['password'])) { 0416 $credential = $this->_params['password']; 0417 } 0418 0419 if (!$identity) { 0420 $this->_sendErrorResponse(101, 'please specify all mandatory fields'); 0421 } else { 0422 if (!$this->_authenticateUser($identity, $credential)) { 0423 $this->_sendErrorResponse(102, 'login not valid'); 0424 } 0425 } 0426 0427 if ($this->_format == 'json') { 0428 $response = array( 0429 'status' => 'ok', 0430 'statuscode' => 100, 0431 'message' => '', 0432 'data' => array( 0433 array( 0434 'details' => 'check', 0435 'personid' => $this->_authData->username, 0436 'ptype' => $this->_authData->password_type 0437 ) 0438 ) 0439 ); 0440 } else { 0441 $response = array( 0442 'meta' => array( 0443 'status' => array('@text' => 'ok'), 0444 'statuscode' => array('@text' => 100), 0445 'message' => array('@text' => '') 0446 ), 0447 'data' => array( 0448 'person' => array( 0449 'details' => 'check', 0450 'personid' => array('@text' => $this->_authData->username), 0451 'ptype' => array('@text' => $this->_authData->password_type) 0452 ) 0453 ) 0454 ); 0455 } 0456 0457 $this->_sendResponse($response, $this->_format, 'ocs', true); 0458 } 0459 0460 protected function _authenticateUser($identity = null, $credential = null, $force = false) 0461 { 0462 //////////////////////////////////////////////////////// 0463 // BasicAuth enabled testing site workaround 0464 if (strrpos($_SERVER['SERVER_NAME'], 'pling.ws') !== false 0465 || strrpos($_SERVER['SERVER_NAME'], 'pling.cc') !== false 0466 || strrpos($_SERVER['SERVER_NAME'], 'pling.to') !== false 0467 || strrpos($_SERVER['SERVER_NAME'], 'ocs-store.com') !== false) { 0468 $authData = new stdClass; 0469 $authData->username = 'dummy'; 0470 $this->_authData = $authData; 0471 0472 return true; 0473 } 0474 //////////////////////////////////////////////////////// 0475 0476 if (!$identity && !empty($_SERVER['PHP_AUTH_USER'])) { 0477 // Will set user identity or API-Key 0478 $identity = $_SERVER['PHP_AUTH_USER']; 0479 } 0480 if (!$credential && !empty($_SERVER['PHP_AUTH_PW'])) { 0481 $credential = $_SERVER['PHP_AUTH_PW']; 0482 } 0483 0484 $loginMethod = null; 0485 //if ($identity && !$credential) { 0486 // $loginMethod = 'api-key'; 0487 //} 0488 0489 if ($identity && ($credential || $loginMethod == 'api-key')) { 0490 $authModel = new Default_Model_Authorization(); 0491 $authData = $authModel->getAuthDataFromApi($identity, $credential, $loginMethod); 0492 if ($authData) { 0493 $this->_authData = $authData; 0494 0495 return true; 0496 } 0497 } 0498 0499 if ($force) { 0500 //header('WWW-Authenticate: Basic realm="Your valid user account or api key"'); 0501 header('WWW-Authenticate: Basic realm="Your valid user account"'); 0502 header('HTTP/1.0 401 Unauthorized'); 0503 exit; 0504 } 0505 0506 return false; 0507 } 0508 0509 public function personselfAction() 0510 { 0511 $this->persondataAction(true); 0512 } 0513 0514 public function persondataAction($self = false) 0515 { 0516 if (!$this->_authenticateUser()) { 0517 $this->_sendErrorResponse(101, 'person not found'); 0518 } 0519 0520 $tableMember = new Default_Model_Member(); 0521 0522 // Self data or specific person data 0523 if ($self || $this->getParam('personid')) { 0524 if ($self) { 0525 $username = $this->_authData->username; 0526 } else { 0527 if ($this->getParam('personid')) { 0528 $username = $this->getParam('personid'); 0529 } 0530 } 0531 0532 $member = $tableMember->findActiveMemberByIdentity($username); 0533 0534 if (!$member) { 0535 $this->_sendErrorResponse(101, 'person not found'); 0536 } 0537 0538 $profilePage = $this->_uriScheme . '://' . $this->_config['user_host'] . '/member/' . $member->member_id; 0539 0540 if ($this->_format == 'json') { 0541 $response = array( 0542 'status' => 'ok', 0543 'statuscode' => 100, 0544 'message' => '', 0545 'data' => array( 0546 array( 0547 'details' => 'full', 0548 'personid' => $member->username, 0549 'privacy' => 0, 0550 'privacytext' => 'public', 0551 'firstname' => $member->firstname, 0552 'lastname' => $member->lastname, 0553 'gender' => '', 0554 'communityrole' => '', 0555 'homepage' => $member->link_website, 0556 'company' => '', 0557 'avatarpic' => $member->profile_image_url, 0558 'avatarpicfound' => true, 0559 'bigavatarpic' => $member->profile_image_url, 0560 'bigavatarpicfound' => true, 0561 'birthday' => '', 0562 'jobstatus' => '', 0563 'city' => $member->city, 0564 'country' => $member->country, 0565 'latitude' => '', 0566 'longitude' => '', 0567 'ircnick' => '', 0568 'ircchannels' => '', 0569 'irclink' => '', 0570 'likes' => '', 0571 'dontlikes' => '', 0572 'interests' => '', 0573 'languages' => '', 0574 'programminglanguages' => '', 0575 'favouritequote' => '', 0576 'favouritemusic' => '', 0577 'favouritetvshows' => '', 0578 'favouritemovies' => '', 0579 'favouritebooks' => '', 0580 'favouritegames' => '', 0581 'description' => $member->biography, 0582 'profilepage' => $profilePage 0583 ) 0584 ) 0585 ); 0586 } else { 0587 $response = array( 0588 'meta' => array( 0589 'status' => array('@text' => 'ok'), 0590 'statuscode' => array('@text' => 100), 0591 'message' => array('@text' => '') 0592 ), 0593 'data' => array( 0594 'person' => array( 0595 'details' => 'full', 0596 'personid' => array('@text' => $member->username), 0597 'privacy' => array('@text' => 0), 0598 'privacytext' => array('@text' => 'public'), 0599 'firstname' => array('@text' => $member->firstname), 0600 'lastname' => array('@text' => $member->lastname), 0601 'gender' => array('@text' => ''), 0602 'communityrole' => array('@text' => ''), 0603 'homepage' => array('@text' => $member->link_website), 0604 'company' => array('@text' => ''), 0605 'avatarpic' => array('@text' => $member->profile_image_url), 0606 'avatarpicfound' => array('@text' => true), 0607 'bigavatarpic' => array('@text' => $member->profile_image_url), 0608 'bigavatarpicfound' => array('@text' => true), 0609 'birthday' => array('@text' => ''), 0610 'jobstatus' => array('@text' => ''), 0611 'city' => array('@text' => $member->city), 0612 'country' => array('@text' => $member->country), 0613 'latitude' => array('@text' => ''), 0614 'longitude' => array('@text' => ''), 0615 'ircnick' => array('@text' => ''), 0616 'ircchannels' => array('@text' => ''), 0617 'irclink' => array('@text' => ''), 0618 'likes' => array('@text' => ''), 0619 'dontlikes' => array('@text' => ''), 0620 'interests' => array('@text' => ''), 0621 'languages' => array('@text' => ''), 0622 'programminglanguages' => array('@text' => ''), 0623 'favouritequote' => array('@text' => ''), 0624 'favouritemusic' => array('@text' => ''), 0625 'favouritetvshows' => array('@text' => ''), 0626 'favouritemovies' => array('@text' => ''), 0627 'favouritebooks' => array('@text' => ''), 0628 'favouritegames' => array('@text' => ''), 0629 'description' => array('@text' => $member->biography), 0630 'profilepage' => array('@text' => $profilePage) 0631 ) 0632 ) 0633 ); 0634 } 0635 0636 $this->_sendResponse($response, $this->_format, 'ocs', true); 0637 } // Find a specific list of persons 0638 else { 0639 $limit = 10; // 1 - 100 0640 $offset = 0; 0641 0642 $tableMemberSelect = $tableMember->select()->where('is_active = ?', 1)->where('is_deleted = ?', 0); 0643 0644 if (!empty($this->_params['name'])) { 0645 $isSearchable = false; 0646 foreach (explode(' ', $this->_params['name']) as $keyword) { 0647 if ($keyword && strlen($keyword) > 2) { 0648 $tableMemberSelect->where('username LIKE ?' . ' OR firstname LIKE ?' . ' OR lastname LIKE ?', "%$keyword%"); 0649 $isSearchable = true; 0650 } 0651 } 0652 if (!$isSearchable) { 0653 $tableMemberSelect->where('username LIKE ?' . ' OR firstname LIKE ?' . ' OR lastname LIKE ?', 0654 "%{$this->_params['name']}%"); 0655 } 0656 } 0657 if (!empty($this->_params['country'])) { 0658 $tableMemberSelect->where('country = ?', $this->_params['country']); 0659 } 0660 if (!empty($this->_params['city'])) { 0661 $tableMemberSelect->where('city = ?', $this->_params['city']); 0662 } 0663 if (!empty($this->_params['description'])) { 0664 $isSearchable = false; 0665 foreach (explode(' ', $this->_params['name']) as $keyword) { 0666 if ($keyword && strlen($keyword) > 2) { 0667 $tableMemberSelect->where('biography LIKE ?', "%$keyword%"); 0668 $isSearchable = true; 0669 } 0670 } 0671 if (!$isSearchable) { 0672 $tableMemberSelect->where('biography LIKE ?', "%$this->_params['description']}%"); 0673 } 0674 } 0675 if (!empty($this->_params['pc'])) { 0676 } 0677 if (!empty($this->_params['software'])) { 0678 } 0679 if (!empty($this->_params['longitude'])) { 0680 } 0681 if (!empty($this->_params['latitude'])) { 0682 } 0683 if (!empty($this->_params['distance'])) { 0684 } 0685 if (!empty($this->_params['attributeapp'])) { 0686 } 0687 if (!empty($this->_params['attributekey'])) { 0688 } 0689 if (!empty($this->_params['attributevalue'])) { 0690 } 0691 if (isset($this->_params['pagesize']) 0692 && ctype_digit((string)$this->_params['pagesize']) 0693 && $this->_params['pagesize'] > 0 0694 && $this->_params['pagesize'] < 101) { 0695 $limit = $this->_params['pagesize']; 0696 } 0697 if (isset($this->_params['page']) 0698 && ctype_digit((string)$this->_params['page'])) { 0699 // page parameter: the first page is 0 0700 $offset = $limit * $this->_params['page']; 0701 } 0702 0703 $members = $tableMember->fetchAll($tableMemberSelect->limit($limit, $offset)); 0704 0705 $tableMemberSelect->reset('columns'); 0706 $tableMemberSelect->reset('limitcount'); 0707 $tableMemberSelect->reset('limitoffset'); 0708 0709 $count = $tableMember->fetchRow($tableMemberSelect->columns(array('count' => 'COUNT(*)'))); 0710 0711 if ($count['count'] > 1000) { 0712 $this->_sendErrorResponse(102, 'more than 1000 people found.' . ' it is not allowed to fetch such a big resultset.' 0713 . ' please specify more search conditions'); 0714 } 0715 0716 if ($this->_format == 'json') { 0717 $response = array( 0718 'status' => 'ok', 0719 'statuscode' => 100, 0720 'message' => '', 0721 'totalitems' => $count['count'], 0722 'itemsperpage' => $limit, 0723 'data' => array() 0724 ); 0725 } else { 0726 $response = array( 0727 'meta' => array( 0728 'status' => array('@text' => 'ok'), 0729 'statuscode' => array('@text' => 100), 0730 'message' => array('@text' => ''), 0731 'totalitems' => array('@text' => $count['count']), 0732 'itemsperpage' => array('@text' => $limit) 0733 ), 0734 'data' => array() 0735 ); 0736 } 0737 0738 if (!count($members)) { 0739 $this->_sendResponse($response, $this->_format, 'ocs', true); 0740 } 0741 0742 $personsList = array(); 0743 foreach ($members as $member) { 0744 if ($this->_format == 'json') { 0745 $personsList[] = array( 0746 'details' => 'summary', 0747 'personid' => $member->username, 0748 'privacy' => 0, 0749 'privacytext' => 'public', 0750 'firstname' => $member->firstname, 0751 'lastname' => $member->lastname, 0752 'gender' => '', 0753 'communityrole' => '', 0754 'company' => '', 0755 'city' => $member->city, 0756 'country' => $member->country 0757 ); 0758 } else { 0759 $personsList[] = array( 0760 'details' => 'summary', 0761 'personid' => array('@text' => $member->username), 0762 'privacy' => array('@text' => 0), 0763 'privacytext' => array('@text' => 'public'), 0764 'firstname' => array('@text' => $member->firstname), 0765 'lastname' => array('@text' => $member->lastname), 0766 'gender' => array('@text' => ''), 0767 'communityrole' => array('@text' => ''), 0768 'company' => array('@text' => ''), 0769 'city' => array('@text' => $member->city), 0770 'country' => array('@text' => $member->country) 0771 ); 0772 } 0773 } 0774 0775 if ($this->_format == 'json') { 0776 $response['data'] = $personsList; 0777 } else { 0778 $response['data'] = array('person' => $personsList); 0779 } 0780 0781 $this->_sendResponse($response, $this->_format, 'ocs', true); 0782 } 0783 } 0784 0785 public function contentcategoriesAction() 0786 { 0787 0788 if (!$this->_authenticateUser()) { 0789 // $this->_sendErrorResponse(999, ''); 0790 } 0791 0792 /** @var Zend_Cache_Core $cache */ 0793 $cache = Zend_Registry::get('cache'); 0794 $storeName = $this->_getNameForStoreClient(); 0795 $cacheName = 'api_content_categories'.md5($storeName); 0796 0797 if (false == ($categoriesList = $cache->load($cacheName))) { 0798 $categoriesList = $this->_buildCategories(); 0799 $cache->save($categoriesList, $cacheName, array(), 1800); 0800 } 0801 0802 if ($this->_format == 'json') { 0803 $response = array( 0804 'status' => 'ok', 0805 'statuscode' => 100, 0806 'message' => '', 0807 'totalitems' => count($categoriesList), 0808 'data' => array() 0809 ); 0810 if (!empty($categoriesList)) { 0811 $response['data'] = $categoriesList; 0812 } 0813 } else { 0814 $response = array( 0815 'meta' => array( 0816 'status' => array('@text' => 'ok'), 0817 'statuscode' => array('@text' => 100), 0818 'message' => array('@text' => ''), 0819 'totalitems' => array('@text' => count($categoriesList)) 0820 ), 0821 'data' => array() 0822 ); 0823 if (!empty($categoriesList)) { 0824 $response['data'] = array('category' => $categoriesList); 0825 } 0826 } 0827 0828 $this->_sendResponse($response, $this->_format, 'ocs', true); 0829 } 0830 0831 protected function _buildCategories() 0832 { 0833 $modelCategoryTree = new Default_Model_ProjectCategory(); 0834 $tree = $modelCategoryTree->fetchCategoryTreeCurrentStore(); 0835 0836 return $this->buildResponseTree($tree); 0837 } 0838 0839 protected function buildResponseTree($tree) 0840 { 0841 $modelCategory = new Default_Model_DbTable_ProjectCategory(); 0842 $result = array(); 0843 foreach ($tree as $element) { 0844 if ($this->_format == 'json') { 0845 $name = (false === empty($element['name_legacy'])) ? $element['name_legacy'] : $element['title']; 0846 //set parent name to name, if neeed 0847 if(isset($element['parent_id'])) { 0848 $parent = $modelCategory->find($element['parent_id'])->current(); 0849 if($parent) { 0850 $name = $parent['title'] . "/ " . $name; 0851 } 0852 } 0853 $result[] = array( 0854 'id' => $element['id'], 0855 'name' => $name, 0856 'display_name' => $element['title'], 0857 'parent_id' => (false === empty($element['parent_id'])) ? $element['parent_id'] : '', 0858 'xdg_type' => (false === empty($element['xdg_type'])) ? $element['xdg_type'] : '' 0859 ); 0860 } else { 0861 $name = (false === empty($element['name_legacy'])) ? $element['name_legacy'] : $element['title']; 0862 0863 //set parent name to name, if neeed 0864 if(isset($element['parent_id'])) { 0865 $parent = $modelCategory->find($element['parent_id'])->current(); 0866 if($parent) { 0867 $name = $parent['title'] . "/ " . $name; 0868 } 0869 } 0870 0871 $result[] = array( 0872 'id' => array('@text' => $element['id']), 0873 'name' => array('@text' => $name), 0874 'display_name' => array('@text' => $element['title']), 0875 'parent_id' => array('@text' => (false === empty($element['parent_id'])) ? $element['parent_id'] : ''), 0876 'xdg_type' => array('@text' => (false === empty($element['xdg_type'])) ? $element['xdg_type'] : '') 0877 ); 0878 0879 } 0880 if ($element['has_children']) { 0881 $sub_tree = $this->buildResponseTree($element['children']); 0882 $result = array_merge($result, $sub_tree); 0883 } 0884 } 0885 0886 return $result; 0887 } 0888 0889 public function contentdataAction() 0890 { 0891 0892 $uri = $this->view->url(); 0893 0894 $params = $this->getRequest()->getParams(); 0895 $params['domain_store_id'] = $this->_getNameForStoreClient(); 0896 0897 $result = $this->_request('GET', $uri, $params); 0898 $this->_sendResponse($result, $this->_format); 0899 0900 /* 0901 0902 if (!$this->_authenticateUser()) { 0903 // $this->_sendErrorResponse(999, ''); 0904 } 0905 0906 $pploadApi = new Ppload_Api(array( 0907 'apiUri' => PPLOAD_API_URI, 0908 'clientId' => PPLOAD_CLIENT_ID, 0909 'secret' => PPLOAD_SECRET 0910 )); 0911 $previewPicSize = array( 0912 'width' => 770, 0913 'height' => 540, 0914 'crop' => 0 0915 ); 0916 $smallPreviewPicSize = array( 0917 'width' => 100, 0918 'height' => 100 0919 ); 0920 0921 // Specific content data 0922 $requestedId = (int)$this->getParam('contentid') ? (int)$this->getParam('contentid') : null; 0923 $requestedTags = $this->getParam('tags') ? $this->getParam('tags') : null; 0924 if ($requestedId) { 0925 $response = $this->fetchContent($requestedId, $requestedTags, $previewPicSize, $smallPreviewPicSize, $pploadApi); 0926 0927 $this->_sendResponse($response, $this->_format); 0928 } // Gets a list of a specific set of contents 0929 else { 0930 $response = $this->fetchCategoryContent($requestedTags, $previewPicSize, $smallPreviewPicSize, $pploadApi); 0931 0932 $this->_sendResponse($response, $this->_format); 0933 } 0934 * 0935 */ 0936 } 0937 0938 /** 0939 * @param int $contentId 0940 * @param array|null $tags 0941 * @param array $previewPicSize 0942 * @param array $smallPreviewPicSize 0943 * @param Ppload_Api $pploadApi 0944 * 0945 * @return array 0946 */ 0947 protected function fetchContent( 0948 $contentId, 0949 $tags, 0950 $previewPicSize, 0951 $smallPreviewPicSize, 0952 $pploadApi 0953 ) { 0954 if(null == $tags) { 0955 $tags = ''; 0956 } 0957 /** @var Zend_Cache_Core $cache */ 0958 $cache = Zend_Registry::get('cache'); 0959 $cacheName = 'api_fetch_content_by_id_' . $contentId . '_tags_' . md5($tags) . '_format_' . $this->_format; 0960 0961 if (($response = $cache->load($cacheName))) { 0962 return $response; 0963 } 0964 0965 $tableProject = new Default_Model_Project(); 0966 $tableProjectSelect = $this->_buildProjectSelect($tableProject); 0967 0968 $project = $tableProject->fetchRow($tableProjectSelect->where('project.project_id = ?', $contentId)); 0969 0970 if (!$project) { 0971 $this->_sendErrorResponse(101, 'content not found'); 0972 } 0973 0974 $project->title = Default_Model_HtmlPurify::purify($project->title); 0975 $project->description = Default_Model_BBCode::renderHtml(Default_Model_HtmlPurify::purify($project->description)); 0976 $project->version = Default_Model_HtmlPurify::purify($project->version); 0977 0978 $categoryXdgType = ''; 0979 if (!empty($project->cat_xdg_type)) { 0980 $categoryXdgType = $project->cat_xdg_type; 0981 } 0982 0983 $created = date('c', strtotime($project->created_at)); 0984 $changed = date('c', strtotime($project->changed_at)); 0985 0986 $previewPage = $this->_uriScheme . '://' . $this->_config['website'] . '/p/' . $project->project_id; 0987 0988 $donationPage = $previewPage; 0989 if (empty($project->paypal_mail) && empty($project->dwolla_id)) { 0990 $donationPage = ''; 0991 } 0992 0993 list($previewPics, $smallPreviewPics) = $this->getGalleryPictures($project, $previewPicSize, $smallPreviewPicSize); 0994 0995 $downloads = $project->count_downloads_hive; 0996 list($downloadItems, $downloads) = $this->getPPLoadInfo($project, $pploadApi, $downloads, $tags); 0997 0998 if ($this->_format == 'json') { 0999 $response = array( 1000 'status' => 'ok', 1001 'statuscode' => 100, 1002 'message' => '', 1003 'data' => array( 1004 array( 1005 'details' => 'full', 1006 'id' => $project->project_id, 1007 'name' => $project->title, 1008 'version' => $project->version, 1009 'typeid' => $project->project_category_id, 1010 'typename' => $project->cat_title, 1011 'xdg_type' => $categoryXdgType, 1012 'language' => '', 1013 'personid' => $project->username, 1014 'created' => $created, 1015 'changed' => $changed, 1016 'downloads' => $downloads, 1017 'score' => $project->laplace_score, 1018 'summary' => '', 1019 'description' => $project->description, 1020 'changelog' => '', 1021 'feedbackurl' => $previewPage, 1022 'homepage' => $previewPage, 1023 'homepagetype' => '', 1024 'donationpage' => $donationPage, 1025 'comments' => $project->count_comments, 1026 'commentspage' => $previewPage, 1027 'fans' => null, 1028 'fanspage' => '', 1029 'knowledgebaseentries' => null, 1030 'knowledgebasepage' => '', 1031 'depend' => '', 1032 'preview1' => $previewPage, 1033 'icon' => '', 1034 'video' => '', 1035 'detailpage' => $previewPage, 1036 'ghns_excluded' => $project->ghns_excluded, 1037 'tags' => $project->tags 1038 ) + $previewPics + $smallPreviewPics + $downloadItems 1039 ) 1040 ); 1041 } else { 1042 foreach ($previewPics as $key => $value) { 1043 $previewPics[$key] = array('@text' => $value); 1044 } 1045 foreach ($smallPreviewPics as $key => $value) { 1046 $smallPreviewPics[$key] = array('@text' => $value); 1047 } 1048 if ($downloadItems) { 1049 foreach ($downloadItems as $key => $value) { 1050 $downloadItems[$key] = array('@text' => $value); 1051 } 1052 } 1053 $response = array( 1054 'meta' => array( 1055 'status' => array('@text' => 'ok'), 1056 'statuscode' => array('@text' => 100), 1057 'message' => array('@text' => '') 1058 ), 1059 'data' => array( 1060 'content' => array( 1061 'details' => 'full', 1062 'id' => array('@text' => $project->project_id), 1063 'name' => array('@text' => $project->title), 1064 'version' => array('@text' => $project->version), 1065 'typeid' => array('@text' => $project->project_category_id), 1066 'typename' => array('@text' => $project->cat_title), 1067 'xdg_type' => array('@text' => $categoryXdgType), 1068 'language' => array('@text' => ''), 1069 'personid' => array('@text' => $project->username), 1070 'created' => array('@text' => $created), 1071 'changed' => array('@text' => $changed), 1072 'downloads' => array('@text' => $downloads), 1073 'score' => array('@text' => $project->laplace_score), 1074 'summary' => array('@text' => ''), 1075 'description' => array('@cdata' => $project->description), 1076 'changelog' => array('@text' => ''), 1077 'feedbackurl' => array('@text' => $previewPage), 1078 'homepage' => array('@text' => $previewPage), 1079 'homepagetype' => array('@text' => ''), 1080 'donationpage' => array('@text' => $donationPage), 1081 'comments' => array('@text' => $project->count_comments), 1082 'commentspage' => array('@text' => $previewPage), 1083 'fans' => array('@text' => null), 1084 'fanspage' => array('@text' => ''), 1085 'knowledgebaseentries' => array('@text' => null), 1086 'knowledgebasepage' => array('@text' => ''), 1087 'depend' => array('@text' => ''), 1088 'preview1' => array('@text' => $previewPage), 1089 'icon' => array('@text' => ''), 1090 'video' => array('@text' => ''), 1091 'detailpage' => array('@text' => $previewPage), 1092 'ghns_excluded' => array('@text' => $project->ghns_excluded), 1093 'tags' => array('@text' => $project->tags) 1094 ) + $previewPics + $smallPreviewPics + $downloadItems 1095 ) 1096 ); 1097 } 1098 1099 $cache->save($response, $cacheName); 1100 1101 return $response; 1102 } 1103 1104 /** 1105 * @param Zend_Db_Table $tableProject 1106 * 1107 * @param bool $withSqlCalcFoundRows 1108 * 1109 * @return Zend_Db_Table_Select 1110 */ 1111 protected function _buildProjectSelect($tableProject, $withSqlCalcFoundRows = false) 1112 { 1113 $tableProjectSelect = $tableProject->select(); 1114 if ($withSqlCalcFoundRows) { 1115 $tableProjectSelect->from(array('project' => 'stat_projects'), array(new Zend_Db_Expr('SQL_CALC_FOUND_ROWS *'))); 1116 } else { 1117 $tableProjectSelect->from(array('project' => 'stat_projects')); 1118 } 1119 $tableProjectSelect->setIntegrityCheck(false)->columns(array( 1120 '*', 1121 'member_username' => 'username', 1122 'category_title' => 'cat_title', 1123 'xdg_type' => 'cat_xdg_type', 1124 'name_legacy' => 'cat_name_legacy' 1125 ))->where('project.status = ?', Default_Model_Project::PROJECT_ACTIVE) 1126 ->where('project.ppload_collection_id IS NOT NULL') 1127 ; 1128 1129 return $tableProjectSelect; 1130 } 1131 1132 /** 1133 * @param Zend_Db_Table_Row_Abstract $project 1134 * @param array $previewPicSize 1135 * @param array $smallPreviewPicSize 1136 * 1137 * @return array 1138 */ 1139 protected function getGalleryPictures($project, $previewPicSize, $smallPreviewPicSize) 1140 { 1141 /** @var Zend_Cache_Core $cache */ 1142 $cache = Zend_Registry::get('cache'); 1143 $cacheName = 'api_fetch_gallery_pics_' . $project->project_id; 1144 1145 if (($previews = $cache->load($cacheName))) { 1146 return $previews; 1147 } 1148 1149 $viewHelperImage = new Default_View_Helper_Image(); 1150 $previewPics = array( 1151 'previewpic1' => $viewHelperImage->Image($project->image_small, $previewPicSize) 1152 ); 1153 $smallPreviewPics = array( 1154 'smallpreviewpic1' => $viewHelperImage->Image($project->image_small, $smallPreviewPicSize) 1155 ); 1156 1157 $tableProject = new Default_Model_Project(); 1158 $galleryPics = $tableProject->getGalleryPictureSources($project->project_id); 1159 if ($galleryPics) { 1160 $i = 2; 1161 foreach ($galleryPics as $galleryPic) { 1162 $previewPics['previewpic' . $i] = $viewHelperImage->Image($galleryPic, $previewPicSize); 1163 $smallPreviewPics['smallpreviewpic' . $i] = $viewHelperImage->Image($galleryPic, $smallPreviewPicSize); 1164 $i++; 1165 } 1166 } 1167 1168 $cache->save(array($previewPics, $smallPreviewPics), $cacheName); 1169 1170 return array($previewPics, $smallPreviewPics); 1171 } 1172 1173 /** 1174 * @param Zend_Db_Table_Row_Abstract $project 1175 * @param Ppload_Api $pploadApi 1176 * @param int $downloads 1177 * 1178 * @return array 1179 */ 1180 protected function getPPLoadInfo($project, $pploadApi, $downloads, $tags) 1181 { 1182 $downloadItems = array(); 1183 1184 if (empty($project->ppload_collection_id)) { 1185 return array($downloadItems, $downloads); 1186 } 1187 1188 /** @var Zend_Cache_Core $cache */ 1189 $cache = Zend_Registry::get('cache'); 1190 $cacheName = 'api_ppload_collection_by_id_' . $project->ppload_collection_id . '_tags_'.md5($tags); 1191 1192 if (($pploadInfo = $cache->load($cacheName))) { 1193 return $pploadInfo; 1194 } 1195 1196 $filesRequest = array( 1197 'collection_id' => $project->ppload_collection_id, 1198 'ocs_compatibility' => 'compatible', 1199 'tags' => $tags, 1200 'perpage' => 1000 1201 ); 1202 1203 $filesResponse = $pploadApi->getFiles($filesRequest); 1204 1205 if (isset($filesResponse->status) && $filesResponse->status == 'success') { 1206 $i = 1; 1207 foreach ($filesResponse->files as $file) { 1208 //create ppload download hash: secret + collection_id + expire-timestamp 1209 $salt = PPLOAD_DOWNLOAD_SECRET; 1210 $collectionID = $project->ppload_collection_id; 1211 $timestamp = time() + (3600 * 12); // 12 hours valid 1212 $hash = md5($salt . $collectionID . $timestamp); 1213 1214 $downloads += (int)$file->downloaded_count; 1215 $tags = $this->_parseFileTags($file->tags); 1216 $downloadLink = PPLOAD_API_URI . 'files/download/id/' . $file->id . '/s/' . $hash . '/t/' . $timestamp . '/o/1/' . $file->name; 1217 $downloadItems['downloadway' . $i] = 1; 1218 $downloadItems['downloadtype' . $i] = ''; 1219 $downloadItems['downloadprice' . $i] = '0'; 1220 $downloadItems['downloadlink' . $i] = $downloadLink; 1221 $downloadItems['downloadname' . $i] = $file->name; 1222 $downloadItems['downloadsize' . $i] = round($file->size / 1024); 1223 $downloadItems['downloadgpgfingerprint' . $i] = ''; 1224 $downloadItems['downloadgpgsignature' . $i] = ''; 1225 $downloadItems['downloadpackagename' . $i] = ''; 1226 $downloadItems['downloadrepository' . $i] = ''; 1227 $downloadItems['download_package_type' . $i] = $tags['packagetypeid']; 1228 $downloadItems['download_package_arch' . $i] = $tags['packagearch']; 1229 $downloadItems['download_architecture' . $i] = $tags['architectureid']; 1230 $downloadItems['downloadtags' . $i] = empty($tags['filetags'])?'':implode(',',$tags['filetags']); 1231 $i++; 1232 } 1233 } 1234 1235 $cache->save(array($downloadItems, $downloads), $cacheName); 1236 1237 return array($downloadItems, $downloads); 1238 } 1239 1240 /** 1241 * @param string $fileTags 1242 * 1243 * @return array 1244 */ 1245 protected function _parseFileTags($fileTags) 1246 { 1247 $tags = explode(',', $fileTags); 1248 $parsedTags = array( 1249 'link' => '', 1250 'licensetype' => '', 1251 'packagetypeid' => '', 1252 'packagearch' => '', 1253 'filetags' => '', 1254 'architectureid' => '' 1255 ); 1256 foreach ($tags as $tag) { 1257 $tag = trim($tag); 1258 if (strpos($tag, 'link##') === 0) { 1259 $parsedTags['link'] = urldecode(str_replace('link##', '', $tag)); 1260 } elseif (strpos($tag, 'licensetype-') === 0) { 1261 $parsedTags['licensetype'] = str_replace('licensetype-', '', $tag); 1262 } elseif (strpos($tag, 'packagetypeid-') === 0) { 1263 $parsedTags['packagetypeid'] = str_replace('packagetypeid-', '', $tag); 1264 } elseif (strpos($tag, 'packagearch-') === 0) { 1265 $parsedTags['packagearch'] = str_replace('packagearch-', '', $tag); 1266 } elseif (strpos($tag, 'architectureid-') === 0) { 1267 $parsedTags['architectureid'] = str_replace('architectureid-', '', $tag); 1268 } elseif (strpos($tag, '@@@') === 0) { 1269 $strTags = substr($tag, 3, strlen($tag) - 2); 1270 $parsedTags['filetags'] = explode('@@', $strTags); 1271 } 1272 } 1273 1274 return $parsedTags; 1275 } 1276 1277 /** 1278 * @param array $tags 1279 * @param array $previewPicSize 1280 * @param array $smallPreviewPicSize 1281 * @param Ppload_Api $pploadApi 1282 * 1283 * @return array 1284 */ 1285 protected function fetchCategoryContent( 1286 $tags, 1287 $previewPicSize, 1288 $smallPreviewPicSize, 1289 $pploadApi 1290 ) { 1291 $limit = 10; // 1 - 100 1292 $offset = 0; 1293 1294 $tableProject = new Default_Model_Project(); 1295 $tableProjectSelect = $this->_buildProjectSelect($tableProject, true); 1296 1297 if (!empty($this->_params['categories'])) { 1298 // categories parameter: values separated by "," 1299 // legacy OCS API compatible: values separated by "x" 1300 if (strpos($this->_params['categories'], ',') !== false) { 1301 $catList = explode(',', $this->_params['categories']); 1302 } else { 1303 $catList = explode('x', $this->_params['categories']); 1304 } 1305 1306 $modelProjectCategories = new Default_Model_DbTable_ProjectCategory(); 1307 $allCategories = array_merge($catList, $modelProjectCategories->fetchChildIds($catList)); 1308 $tableProjectSelect->where('project.project_category_id IN (?)', $allCategories); 1309 } 1310 1311 if (!empty($this->_params['xdg_types'])) { 1312 // xdg_types parameter: values separated by "," 1313 $xdgTypeList = explode(',', $this->_params['xdg_types']); 1314 $tableProjectSelect->where('category.xdg_type IN (?)', $xdgTypeList); 1315 } 1316 1317 if (!empty($this->_params['package_types'])) { 1318 // package_types parameter: values separated by "," 1319 $packageTypeList = explode(',', $this->_params['package_types']); 1320 1321 $storeConfig = Zend_Registry::isRegistered('store_config') ? Zend_Registry::get('store_config') : null; 1322 $storePackageTypeIds = null; 1323 if ($storeConfig) { 1324 $storePackageTypeIds = $storeConfig->package_type; 1325 } 1326 1327 if ($storePackageTypeIds) { 1328 $tableProjectSelect->join(array( 1329 'package_type' => new Zend_Db_Expr('(SELECT DISTINCT project_id FROM project_package_type WHERE ' 1330 . $tableProject->getAdapter()->quoteInto('package_type_id IN (?)', $packageTypeList) . ')') 1331 ), 'project.project_id = package_type.project_id', array()); 1332 } 1333 } 1334 1335 if (!empty($this->_params['tags'])) { 1336 // package_types parameter: values separated by "," 1337 $tagList = explode(',', $this->_params['tags']); 1338 1339 foreach ($tagList as $tag) { 1340 $tagKeyValue = explode('-', $tag); 1341 $tagName = $tagKeyValue[0]; 1342 $tagValue = $tagKeyValue[1]; 1343 1344 if($tagName == 'architectureid') { 1345 $tableProjectSelect->join(array( 1346 $tagName => new Zend_Db_Expr('(SELECT DISTINCT tag_parent_object_id as project_id FROM tag_object WHERE is_deleted = 0 and ' 1347 . $tableProject->getAdapter()->quoteInto('tag_id = ?', $tagValue) 1348 . ' AND ' . $tableProject->getAdapter()->quoteInto('tag_type_id = ?', Default_Model_Tags::TAG_TYPE_FILE) 1349 . ')') 1350 ), 'project.project_id = '.$tagName. '.project_id', array()); 1351 } else { 1352 $tableProjectSelect->join(array( 1353 $tagName => new Zend_Db_Expr('(SELECT DISTINCT tag_object_id as project_id FROM tag_object WHERE is_deleted = 0 and ' 1354 . $tableProject->getAdapter()->quoteInto('tag_id = ?', $tagValue) . ')') 1355 ), 'project.project_id = '.$tagName. '.project_id', array()); 1356 } 1357 } 1358 1359 } 1360 1361 $hasSearchPart = false; 1362 if (!empty($this->_params['search'])) { 1363 foreach (explode(' ', $this->_params['search']) as $keyword) { 1364 if ($keyword && strlen($keyword) > 2) { 1365 $tableProjectSelect->where('project.title LIKE ? OR project.description LIKE ?', "%$keyword%"); 1366 $hasSearchPart = true; 1367 } 1368 } 1369 } 1370 1371 if (!empty($this->_params['user'])) { 1372 $tableProjectSelect->where('member.username = ?', $this->_params['user']); 1373 } 1374 1375 if (!empty($this->_params['external'])) { 1376 } 1377 1378 if (!empty($this->_params['distribution'])) { 1379 // distribution parameter: comma separated list of ids 1380 } 1381 1382 if (!empty($this->_params['license'])) { 1383 // license parameter: comma separated list of ids 1384 } 1385 1386 if (!empty($this->_params['sortmode'])) { 1387 // sortmode parameter: new|alpha|high|down 1388 switch (strtolower($this->_params['sortmode'])) { 1389 case 'new': 1390 $tableProjectSelect->order('project.created_at DESC'); 1391 break; 1392 case 'alpha': 1393 $tableProjectSelect->order('project.title ASC'); 1394 break; 1395 case 'high': 1396 $tableProjectSelect->order(new Zend_Db_Expr('laplace_score(project.count_likes,project.count_dislikes) DESC')); 1397 break; 1398 case 'down': 1399 $tableProjectSelect->joinLeft(array('stat_downloads_quarter_year' => 'stat_downloads_quarter_year'), 1400 'project.project_id = stat_downloads_quarter_year.project_id', array()); 1401 $tableProjectSelect->order('stat_downloads_quarter_year.amount DESC'); 1402 break; 1403 default: 1404 break; 1405 } 1406 } 1407 1408 if (isset($this->_params['pagesize']) 1409 && ctype_digit((string)$this->_params['pagesize']) 1410 && $this->_params['pagesize'] > 0 1411 && $this->_params['pagesize'] < 101) { 1412 $limit = $this->_params['pagesize']; 1413 } 1414 1415 if (isset($this->_params['page']) 1416 && ctype_digit((string)$this->_params['page'])) { 1417 // page parameter: the first page is 0 1418 $offset = $limit * $this->_params['page']; 1419 } 1420 1421 $tableProjectSelect->limit($limit, $offset); 1422 1423 $projects = $tableProject->fetchAll($tableProjectSelect); 1424 $count = $tableProject->getAdapter()->fetchRow('select FOUND_ROWS() AS counter'); 1425 1426 if ($this->_format == 'json') { 1427 $response = array( 1428 'status' => 'ok', 1429 'statuscode' => 100, 1430 'message' => '', 1431 'totalitems' => $count['counter'], 1432 'itemsperpage' => $limit, 1433 'data' => array() 1434 ); 1435 } else { 1436 $response = array( 1437 'meta' => array( 1438 'status' => array('@text' => 'ok'), 1439 'statuscode' => array('@text' => 100), 1440 'message' => array('@text' => ''), 1441 'totalitems' => array('@text' => $count['counter']), 1442 'itemsperpage' => array('@text' => $limit) 1443 ), 1444 'data' => array() 1445 ); 1446 } 1447 1448 if (!count($projects)) { 1449 return $response; 1450 } 1451 1452 /** @var Zend_Cache_Core $cache */ 1453 $cache = Zend_Registry::get('cache'); 1454 $cacheName = 'api_fetch_category_' . md5($tableProjectSelect->__toString().'-'.$tags); 1455 $contentsList = false; 1456 1457 if (false === $hasSearchPart) { 1458 $contentsList = $cache->load($cacheName); 1459 } 1460 1461 if (false == $contentsList) { 1462 $contentsList = $this->_buildContentList($previewPicSize, $smallPreviewPicSize, $pploadApi, $projects, $tags); 1463 1464 if (!count($contentsList)) { 1465 if ($this->_format == 'json') { 1466 $response = array( 1467 'status' => 'ok', 1468 'statuscode' => 100, 1469 'message' => '', 1470 'totalitems' => 0, 1471 'itemsperpage' => $limit, 1472 'data' => array() 1473 ); 1474 } else { 1475 $response = array( 1476 'meta' => array( 1477 'status' => array('@text' => 'ok'), 1478 'statuscode' => array('@text' => 100), 1479 'message' => array('@text' => ''), 1480 'totalitems' => array('@text' => 0), 1481 'itemsperpage' => array('@text' => $limit) 1482 ), 1483 'data' => array() 1484 ); 1485 } 1486 return $response; 1487 } 1488 1489 if (false === $hasSearchPart) { 1490 $cache->save($contentsList, $cacheName, array(), 1800); 1491 } 1492 } 1493 1494 if ($this->_format == 'json') { 1495 $response['totalitems'] = count($contentsList); 1496 $response['data'] = $contentsList; 1497 } else { 1498 $response['meta']['totalitems'] = array('@text' => count($contentsList)); 1499 $response['data'] = array('content' => $contentsList); 1500 } 1501 1502 return $response; 1503 } 1504 1505 /** 1506 * @param $previewPicSize 1507 * @param $smallPreviewPicSize 1508 * @param $pploadApi 1509 * @param $projects 1510 * 1511 * @return array 1512 */ 1513 protected function _buildContentList($previewPicSize, $smallPreviewPicSize, $pploadApi, $projects, $tags) 1514 { 1515 $contentsList = array(); 1516 $helperTruncate = new Default_View_Helper_Truncate(); 1517 foreach ($projects as $project) { 1518 $project->description = $helperTruncate->truncate(Default_Model_BBCode::renderHtml(Default_Model_HtmlPurify::purify($project->description)),300); 1519 1520 $categoryXdgType = ''; 1521 if (!empty($project->xdg_type)) { 1522 $categoryXdgType = $project->xdg_type; 1523 } 1524 1525 $created = date('c', strtotime($project->created_at)); 1526 $changed = date('c', strtotime($project->changed_at)); 1527 1528 $previewPage = $this->_uriScheme . '://' . $this->_config['website'] . '/p/' . $project->project_id; 1529 1530 list($previewPics, $smallPreviewPics) = $this->getGalleryPictures($project, $previewPicSize, $smallPreviewPicSize); 1531 1532 $downloads = $project->count_downloads_hive; 1533 list($downloadItems, $downloads) = $this->getPPLoadInfo($project, $pploadApi, $downloads, $tags); 1534 1535 if(count($downloadItems)>0) { 1536 if ($this->_format == 'json') { 1537 $contentsList[] = array( 1538 'details' => 'summary', 1539 'id' => $project->project_id, 1540 'name' => $project->title, 1541 'version' => $project->version, 1542 'typeid' => $project->project_category_id, 1543 'typename' => $project->cat_title, 1544 'xdg_type' => $categoryXdgType, 1545 'language' => '', 1546 'personid' => $project->member_username, 1547 'created' => $created, 1548 'changed' => $changed, 1549 'downloads' => $downloads, 1550 'score' => $project->laplace_score, 1551 'summary' => '', 1552 'description' => $project->description, 1553 'comments' => $project->count_comments, 1554 'ghns_excluded' => $project->ghns_excluded, 1555 'preview1' => $previewPage, 1556 'detailpage' => $previewPage, 1557 'tags' => $project->tags 1558 ) + $previewPics + $smallPreviewPics + $downloadItems; 1559 } else { 1560 foreach ($previewPics as $key => $value) { 1561 $previewPics[$key] = array('@text' => $value); 1562 } 1563 foreach ($smallPreviewPics as $key => $value) { 1564 $smallPreviewPics[$key] = array('@text' => $value); 1565 } 1566 if ($downloadItems) { 1567 foreach ($downloadItems as $key => $value) { 1568 $downloadItems[$key] = array('@text' => $value); 1569 } 1570 } 1571 $contentsList[] = array( 1572 'details' => 'summary', 1573 'id' => array('@text' => $project->project_id), 1574 'name' => array('@text' => $project->title), 1575 'version' => array('@text' => $project->version), 1576 'typeid' => array('@text' => $project->project_category_id), 1577 'typename' => array('@text' => $project->cat_title), 1578 'xdg_type' => array('@text' => $categoryXdgType), 1579 'language' => array('@text' => ''), 1580 'personid' => array('@text' => $project->member_username), 1581 'created' => array('@text' => $created), 1582 'changed' => array('@text' => $changed), 1583 'downloads' => array('@text' => $downloads), 1584 'score' => array('@text' => $project->laplace_score), 1585 'summary' => array('@text' => ''), 1586 'description' => array('@cdata' => $project->description), 1587 'comments' => array('@text' => $project->count_comments), 1588 'ghns_excluded' => array('@text' => $project->ghns_excluded), 1589 'preview1' => array('@text' => $previewPage), 1590 'detailpage' => array('@text' => $previewPage), 1591 'tags' => array('@text' => $project->tags) 1592 ) + $previewPics + $smallPreviewPics + $downloadItems; 1593 } 1594 } 1595 } 1596 1597 return $contentsList; 1598 } 1599 1600 public function contentdownloadAction() 1601 { 1602 1603 $uri = $this->view->url(); 1604 1605 $params = $this->getRequest()->getParams(); 1606 $params['domain_store_id'] = $this->_getNameForStoreClient(); 1607 1608 $result = $this->_request('GET', $uri, $params); 1609 $this->_sendResponse($result, $this->_format); 1610 1611 /* 1612 1613 if (!$this->_authenticateUser()) { 1614 //$this->_sendErrorResponse(999, ''); 1615 } 1616 1617 $pploadApi = new Ppload_Api(array( 1618 'apiUri' => PPLOAD_API_URI, 1619 'clientId' => PPLOAD_CLIENT_ID, 1620 'secret' => PPLOAD_SECRET 1621 )); 1622 1623 $project = null; 1624 $file = null; 1625 1626 if ($this->getParam('contentid')) { 1627 $tableProject = new Default_Model_Project(); 1628 $project = $tableProject->fetchRow( 1629 $tableProject->select() 1630 ->where('project_id = ?', $this->getParam('contentid')) 1631 ->where('status = ?', Default_Model_Project::PROJECT_ACTIVE)); 1632 } 1633 1634 if (!$project) { 1635 $this->_sendErrorResponse(101, 'content not found'); 1636 } 1637 1638 if ($project->ppload_collection_id 1639 && $this->getParam('itemid') 1640 && ctype_digit((string)$this->getParam('itemid')) 1641 ) { 1642 $filesRequest = array( 1643 'collection_id' => $project->ppload_collection_id, 1644 'ocs_compatibility' => 'compatible', 1645 'perpage' => 1, 1646 'page' => $this->getParam('itemid') 1647 ); 1648 1649 $filesResponse = $pploadApi->getFiles($filesRequest); 1650 1651 if (isset($filesResponse->status) 1652 && $filesResponse->status == 'success') { 1653 $i = 0; 1654 $file = $filesResponse->files->$i; 1655 } 1656 } 1657 1658 if (!$file) { 1659 $this->_sendErrorResponse(103, 'content item not found'); 1660 } 1661 1662 //create ppload download hash: secret + collection_id + expire-timestamp 1663 $salt = PPLOAD_DOWNLOAD_SECRET; 1664 $collectionID = $project->ppload_collection_id; 1665 $timestamp = time() + (3600 * 12); // 12 hours valid 1666 $hash = md5($salt . $collectionID . $timestamp); 1667 1668 $tags = $this->_parseFileTags($file->tags); 1669 $downloadLink = PPLOAD_API_URI . 'files/download/id/' . $file->id . '/s/' . $hash . '/t/' . $timestamp . '/o/1/' . $file->name; 1670 1671 if ($this->_format == 'json') { 1672 $response = array( 1673 'status' => 'ok', 1674 'statuscode' => 100, 1675 'message' => '', 1676 'data' => array( 1677 array( 1678 'details' => 'download', 1679 'downloadway' => 1, 1680 'downloadlink' => $downloadLink, 1681 'mimetype' => $file->type, 1682 'gpgfingerprint' => '', 1683 'gpgsignature' => '', 1684 'packagename' => '', 1685 'repository' => '', 1686 'download_package_type' => $tags['packagetypeid'], 1687 'download_package_arch' => $tags['packagearch'], 1688 'architecture' => $tags['architectureid'], 1689 'downloadtags' => empty($tags['filetags'])?'':implode(',',$tags['filetags']) 1690 ) 1691 ) 1692 ); 1693 } else { 1694 $response = array( 1695 'meta' => array( 1696 'status' => array('@text' => 'ok'), 1697 'statuscode' => array('@text' => 100), 1698 'message' => array('@text' => '') 1699 ), 1700 'data' => array( 1701 'content' => array( 1702 'details' => 'download', 1703 'downloadway' => array('@text' => 1), 1704 'downloadlink' => array('@text' => $downloadLink), 1705 'mimetype' => array('@text' => $file->type), 1706 'gpgfingerprint' => array('@text' => ''), 1707 'gpgsignature' => array('@text' => ''), 1708 'packagename' => array('@text' => ''), 1709 'repository' => array('@text' => ''), 1710 'download_package_type' => array('@text' => $tags['packagetypeid']), 1711 'download_package_arch' => array('@text' => $tags['packagearch']), 1712 'architecture' => array('@text' => $tags['architectureid']), 1713 'downloadtags' => array('@text' => empty($tags['filetags'])?'':implode(',',$tags['filetags'])) 1714 ) 1715 ) 1716 ); 1717 } 1718 1719 $this->_sendResponse($response, $this->_format); 1720 * 1721 */ 1722 } 1723 1724 public function contentpreviewpicAction() 1725 { 1726 1727 $uri = $this->view->url(); 1728 1729 $params = $this->getRequest()->getParams(); 1730 $params['domain_store_id'] = $this->_getNameForStoreClient(); 1731 1732 $result = $this->_request('GET', $uri, $params); 1733 $this->_sendResponse($result, $this->_format); 1734 1735 1736 1737 /* 1738 if (!$this->_authenticateUser()) { 1739 //$this->_sendErrorResponse(999, ''); 1740 } 1741 1742 $project = null; 1743 1744 if ($this->getParam('contentid')) { 1745 $tableProject = new Default_Model_Project(); 1746 $project = $tableProject->fetchRow($tableProject->select() 1747 ->where('project_id = ?', $this->getParam('contentid')) 1748 ->where('status = ?', Default_Model_Project::PROJECT_ACTIVE)); 1749 } 1750 1751 if (!$project) { 1752 //$this->_sendErrorResponse(101, 'content not found'); 1753 header('Location: ' . $this->_config['icon']); 1754 exit; 1755 } 1756 1757 $viewHelperImage = new Default_View_Helper_Image(); 1758 $previewPicSize = array( 1759 'width' => 100, 1760 'height' => 100 1761 ); 1762 1763 if (!empty($this->_params['size']) 1764 && strtolower($this->_params['size']) == 'medium') { 1765 $previewPicSize = array( 1766 'width' => 770, 1767 'height' => 540 1768 ); 1769 } 1770 1771 $previewPicUri = $viewHelperImage->Image($project->image_small, $previewPicSize); 1772 1773 header('Location: ' . $previewPicUri); 1774 exit; 1775 * 1776 */ 1777 } 1778 1779 /** 1780 * @param null $tableCategories 1781 * @param null $parentCategoryId 1782 * @param array $categoriesList 1783 * 1784 * @return array 1785 * @deprecated 1786 */ 1787 protected function _buildCategoriesList($tableCategories = null, $parentCategoryId = null, $categoriesList = array()) 1788 { 1789 $categories = null; 1790 1791 // Top-level categories 1792 if (!$tableCategories) { 1793 $tableCategories = new Default_Model_DbTable_ProjectCategory(); 1794 if (Zend_Registry::isRegistered('store_category_list')) { 1795 $categories = $tableCategories->fetchActive(Zend_Registry::get('store_category_list')); 1796 } else { 1797 $categories = $tableCategories->fetchAllActive(); 1798 } 1799 } // Sub-categories 1800 else { 1801 if ($parentCategoryId) { 1802 $categories = $tableCategories->fetchImmediateChildren($parentCategoryId); 1803 } 1804 } 1805 1806 // Build categories list 1807 if (!empty($categories)) { 1808 foreach ($categories as $category) { 1809 if (is_array($category)) { 1810 $category = (object)$category; 1811 } 1812 1813 $categoryName = $category->title; 1814 $categoryDisplayName = $category->title; 1815 if (!empty($category->name_legacy)) { 1816 $categoryName = $category->name_legacy; 1817 } 1818 $categoryParentId = ''; 1819 if (!empty($parentCategoryId)) { 1820 $categoryParentId = $parentCategoryId; 1821 } 1822 $categoryXdgType = ''; 1823 if (!empty($category->xdg_type)) { 1824 $categoryXdgType = $category->xdg_type; 1825 } 1826 1827 if ($this->_format == 'json') { 1828 $categoriesList[] = array( 1829 'id' => $category->project_category_id, 1830 'name' => $categoryName, 1831 'display_name' => $categoryDisplayName, 1832 'parent_id' => $categoryParentId, 1833 'xdg_type' => $categoryXdgType 1834 ); 1835 } else { 1836 $categoriesList[] = array( 1837 'id' => array('@text' => $category->project_category_id), 1838 'name' => array('@text' => $categoryName), 1839 'display_name' => array('@text' => $categoryDisplayName), 1840 'parent_id' => array('@text' => $categoryParentId), 1841 'xdg_type' => array('@text' => $categoryXdgType) 1842 ); 1843 } 1844 1845 // Update the list recursive 1846 $categoriesList = $this->_buildCategoriesList($tableCategories, $category->project_category_id, $categoriesList); 1847 } 1848 } 1849 1850 return $categoriesList; 1851 } 1852 1853 public function commentsAction() 1854 { 1855 $uri = $this->view->url(); 1856 1857 $params = $this->getRequest()->getParams(); 1858 $params['domain_store_id'] = $this->_getNameForStoreClient(); 1859 1860 $result = $this->_request('GET', $uri, $params); 1861 $this->_sendResponse($result, $this->_format); 1862 1863 /* 1864 if ($this->_format == 'json') { 1865 $response = array( 1866 'status' => 'ok', 1867 'statuscode' => 100, 1868 'message' => '', 1869 'data' => array() 1870 ); 1871 } else { 1872 $response = array( 1873 'meta' => array( 1874 'status' => array('@text' => 'ok'), 1875 'statuscode' => array('@text' => 100), 1876 'message' => array('@text' => ''), 1877 ), 1878 'data' => array() 1879 ); 1880 } 1881 1882 $commentType = (int)$this->getParam('comment_type', -1); 1883 if ($commentType != self::COMMENT_TYPE_CONTENT) { 1884 $this->_sendResponse($response, $this->_format); 1885 } 1886 1887 $contentId = (int)$this->getParam('content_id', null); 1888 if (empty($contentId)) { 1889 $this->_sendResponse($response, $this->_format); 1890 } 1891 1892 $page = (int)$this->getParam('page', 0) + 1; 1893 $pagesize = (int)$this->getParam('pagesize', 10); 1894 1895 ** @var Zend_Cache_Core $cache * 1896 $cache = Zend_Registry::get('cache'); 1897 $cacheName = 'api_fetch_comments_' . md5("{$commentType}, {$contentId}, {$page}, {$pagesize}" . '_format_' . $this->_format); 1898 1899 if (($cachedResponse = $cache->load($cacheName))) { 1900 $this->_sendResponse($cachedResponse, $this->_format); 1901 } 1902 1903 $modelComments = new Default_Model_ProjectComments(); 1904 $comments = $modelComments->getCommentsHierarchic($contentId); 1905 1906 if ($comments->count() == 0) { 1907 $this->_sendResponse($response, $this->_format); 1908 } 1909 1910 $comments->setCurrentPageNumber($page); 1911 $comments->setItemCountPerPage($pagesize); 1912 1913 $response['data'] = array('comment' => $this->_buildCommentList($comments->getCurrentItems())); 1914 $cache->save($response, $cacheName, array(), 1800); 1915 1916 $this->_sendResponse($response, $this->_format); 1917 * 1918 */ 1919 } 1920 1921 /** 1922 * @param Traversable $currentItems 1923 * 1924 * @return array 1925 */ 1926 protected function _buildCommentList($currentItems) 1927 { 1928 $commentList = array(); 1929 foreach ($currentItems as $current_item) { 1930 if ($this->_format == 'json') { 1931 $comment = array( 1932 'id' => $current_item['comment_id'], 1933 'subject' => '', 1934 'text' => Default_Model_HtmlPurify::purify($current_item['comment_text']), 1935 'childcount' => $current_item['childcount'], 1936 'user' => $current_item['username'], 1937 'date' => date('c', strtotime($current_item['comment_created_at'])), 1938 'score' => 0 1939 ); 1940 if ($current_item['childcount'] > 0) { 1941 $comment['children'] = $this->_buildCommentList($current_item['children']); 1942 } 1943 } else { 1944 $comment = array( 1945 'id' => array('@text' => $current_item['comment_id']), 1946 'subject' => array('@text' => ''), 1947 'text' => array('@text' => Default_Model_HtmlPurify::purify($current_item['comment_text'])), 1948 'childcount' => array('@text' => $current_item['childcount']), 1949 'user' => array('@text' => $current_item['username']), 1950 'date' => array('@text' => date('c', strtotime($current_item['comment_created_at']))), 1951 'score' => array('@text' => 0) 1952 ); 1953 if ($current_item['childcount'] > 0) { 1954 $comment['children'] = $this->_buildCommentList($current_item['children']); 1955 } 1956 } 1957 $commentList[] = $comment; 1958 } 1959 1960 return $commentList; 1961 } 1962 1963 1964 protected function _request($method, $uri = '', array $params = null) 1965 { 1966 1967 $config = Zend_Registry::get('config'); 1968 $static_config = $config->settings->ocs_server; 1969 1970 $ocsServer = $static_config->apiUri; 1971 1972 $timeout = 60; 1973 $postFields = array(); 1974 if ($params) { 1975 $postFields = $postFields + $params; 1976 } 1977 if (isset($postFields['file'])) { 1978 $timeout = 600; 1979 if ($postFields['file'][0] != '@') { 1980 $postFields['file'] = $this->_getCurlValue($postFields['file']); 1981 } 1982 } 1983 else { 1984 $postFields = http_build_query($postFields, '', '&'); 1985 } 1986 1987 //var_dump($ocsServer . $uri . '?' . $postFields); 1988 1989 1990 $curl = curl_init(); 1991 curl_setopt_array($curl, array( 1992 CURLOPT_URL => $ocsServer . $uri, 1993 CURLOPT_HEADER => false, 1994 CURLOPT_POST => true, 1995 CURLOPT_POSTFIELDS => $postFields, 1996 CURLOPT_RETURNTRANSFER => true, 1997 CURLOPT_TIMEOUT => $timeout 1998 )); 1999 2000 $response = curl_exec($curl); 2001 curl_close($curl); 2002 2003 if ($response) { 2004 return $response; 2005 } 2006 return false; 2007 } 2008 2009 public function voteAction() 2010 { 2011 $this->_sendErrorResponse(405, 'method not allowed', true); 2012 } 2013 2014 }