├── .htaccess ├── LICENSE ├── README.md ├── api ├── OAuth.php ├── callback.php ├── clearsessions.php ├── comment.php ├── config.php ├── functions.php ├── gc.php ├── getpost.php ├── index.htm ├── indexmaker.php ├── login.php ├── logout.php ├── mysql.php ├── post.php ├── twa.php ├── ustatus.php └── vote.php ├── assets ├── app.js ├── bootstrap.min.css ├── handlebars-v1.3.0.js ├── index.htm └── main.css ├── db.php └── index.htm /.htaccess: -------------------------------------------------------------------------------- 1 | RewriteEngine on 2 | RewriteCond %{REQUEST_FILENAME} !-f 3 | RewriteCond %{REQUEST_FILENAME} !-d 4 | RewriteRule ^(.*)$ /index.htm#$1 [L] 5 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014 Rukshan Ranatunge 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Helius - A HackerNews Clone 2 | ======= 3 |  4 | 5 | If you are interested in becoming a contributer let me know 6 | 7 | Introduction 8 | ------------ 9 | A simple HackerNews clone written using PHP, and EmberJS. It requires users signing in using a Twitter account. Inspired by Product Hunt and HackerNews and all the HackerNews clones focusing on different sub categories (HackerNews for Bitcoin etc) 10 | 11 | This was made as a weekend project while learning EmberJS, you can easily customize this and host it as your own HackerNews for your favourite topic. 12 | 13 | It uses Twitter Bootstrap therefor responsive in design. 14 | 15 | Installation 16 | ------------ 17 | The source code is available at [https://github.com/rukshn/helius.git](https://github.com/rukshn/helius.git). Clone the repository by: 18 | 19 | [root@localhost ~]# git clone https://github.com/rukshn/helius.git 20 | 21 | How to use 22 | ------------------ 23 | Here is a brief introduction to the directories in the repository. 24 | 25 | **API :** Contains all the files that handle the backend functions. 26 | 27 | **Assets:** Contains the CSS and image files. 28 | 29 | **After installation,** 30 | 31 | 1. Create a Twitter app from developer page and replace the consumer key, consumer secret and callback URL variables in the **/api/config.php** file. 32 | 2. Add your database database name, username, password in the **/api/mysql.php** file. 33 | 3. Add the same database name, username, password to db.php file in the root folder and run it to create necessary tables and delete it after that. 34 | 4. Modify the index.htm according to your project by replacing the names of my project and links to Facebook, Twitter, Newsletter etc. 35 | 5. You are good to go after that. 36 | 37 | Before you finish reading 38 | ------- 39 | 40 | 1. It was a weekend project so the coding was in a rush and it might not follow your best practices in coding. 41 | 2. The documentation might be little. 42 | 3. There is lot of room for improvement, please improve on this, fork it, correct errors. 43 | 4. If you like contribute to the project. 44 | 5. If you hate PHP don't blame me, it may not be perfect but it works. 45 | 46 | Dependencies 47 | ------- 48 | 49 | - Jquery 50 | - Twitter Bootstrap 51 | - Handlebars JS 52 | - Ember JS 53 | - Moment JS 54 | 55 | -------------------------------------------------------------------------------- /api/OAuth.php: -------------------------------------------------------------------------------- 1 | key = $key; 18 | $this->secret = $secret; 19 | $this->callback_url = $callback_url; 20 | } 21 | 22 | function __toString() { 23 | return "OAuthConsumer[key=$this->key,secret=$this->secret]"; 24 | } 25 | } 26 | 27 | class OAuthToken { 28 | // access tokens and request tokens 29 | public $key; 30 | public $secret; 31 | 32 | /** 33 | * key = the token 34 | * secret = the token secret 35 | */ 36 | function __construct($key, $secret) { 37 | $this->key = $key; 38 | $this->secret = $secret; 39 | } 40 | 41 | /** 42 | * generates the basic string serialization of a token that a server 43 | * would respond to request_token and access_token calls with 44 | */ 45 | function to_string() { 46 | return "oauth_token=" . 47 | OAuthUtil::urlencode_rfc3986($this->key) . 48 | "&oauth_token_secret=" . 49 | OAuthUtil::urlencode_rfc3986($this->secret); 50 | } 51 | 52 | function __toString() { 53 | return $this->to_string(); 54 | } 55 | } 56 | 57 | /** 58 | * A class for implementing a Signature Method 59 | * See section 9 ("Signing Requests") in the spec 60 | */ 61 | abstract class OAuthSignatureMethod { 62 | /** 63 | * Needs to return the name of the Signature Method (ie HMAC-SHA1) 64 | * @return string 65 | */ 66 | abstract public function get_name(); 67 | 68 | /** 69 | * Build up the signature 70 | * NOTE: The output of this function MUST NOT be urlencoded. 71 | * the encoding is handled in OAuthRequest when the final 72 | * request is serialized 73 | * @param OAuthRequest $request 74 | * @param OAuthConsumer $consumer 75 | * @param OAuthToken $token 76 | * @return string 77 | */ 78 | abstract public function build_signature($request, $consumer, $token); 79 | 80 | /** 81 | * Verifies that a given signature is correct 82 | * @param OAuthRequest $request 83 | * @param OAuthConsumer $consumer 84 | * @param OAuthToken $token 85 | * @param string $signature 86 | * @return bool 87 | */ 88 | public function check_signature($request, $consumer, $token, $signature) { 89 | $built = $this->build_signature($request, $consumer, $token); 90 | return $built == $signature; 91 | } 92 | } 93 | 94 | /** 95 | * The HMAC-SHA1 signature method uses the HMAC-SHA1 signature algorithm as defined in [RFC2104] 96 | * where the Signature Base String is the text and the key is the concatenated values (each first 97 | * encoded per Parameter Encoding) of the Consumer Secret and Token Secret, separated by an '&' 98 | * character (ASCII code 38) even if empty. 99 | * - Chapter 9.2 ("HMAC-SHA1") 100 | */ 101 | class OAuthSignatureMethod_HMAC_SHA1 extends OAuthSignatureMethod { 102 | function get_name() { 103 | return "HMAC-SHA1"; 104 | } 105 | 106 | public function build_signature($request, $consumer, $token) { 107 | $base_string = $request->get_signature_base_string(); 108 | $request->base_string = $base_string; 109 | 110 | $key_parts = array( 111 | $consumer->secret, 112 | ($token) ? $token->secret : "" 113 | ); 114 | 115 | $key_parts = OAuthUtil::urlencode_rfc3986($key_parts); 116 | $key = implode('&', $key_parts); 117 | 118 | return base64_encode(hash_hmac('sha1', $base_string, $key, true)); 119 | } 120 | } 121 | 122 | /** 123 | * The PLAINTEXT method does not provide any security protection and SHOULD only be used 124 | * over a secure channel such as HTTPS. It does not use the Signature Base String. 125 | * - Chapter 9.4 ("PLAINTEXT") 126 | */ 127 | class OAuthSignatureMethod_PLAINTEXT extends OAuthSignatureMethod { 128 | public function get_name() { 129 | return "PLAINTEXT"; 130 | } 131 | 132 | /** 133 | * oauth_signature is set to the concatenated encoded values of the Consumer Secret and 134 | * Token Secret, separated by a '&' character (ASCII code 38), even if either secret is 135 | * empty. The result MUST be encoded again. 136 | * - Chapter 9.4.1 ("Generating Signatures") 137 | * 138 | * Please note that the second encoding MUST NOT happen in the SignatureMethod, as 139 | * OAuthRequest handles this! 140 | */ 141 | public function build_signature($request, $consumer, $token) { 142 | $key_parts = array( 143 | $consumer->secret, 144 | ($token) ? $token->secret : "" 145 | ); 146 | 147 | $key_parts = OAuthUtil::urlencode_rfc3986($key_parts); 148 | $key = implode('&', $key_parts); 149 | $request->base_string = $key; 150 | 151 | return $key; 152 | } 153 | } 154 | 155 | /** 156 | * The RSA-SHA1 signature method uses the RSASSA-PKCS1-v1_5 signature algorithm as defined in 157 | * [RFC3447] section 8.2 (more simply known as PKCS#1), using SHA-1 as the hash function for 158 | * EMSA-PKCS1-v1_5. It is assumed that the Consumer has provided its RSA public key in a 159 | * verified way to the Service Provider, in a manner which is beyond the scope of this 160 | * specification. 161 | * - Chapter 9.3 ("RSA-SHA1") 162 | */ 163 | abstract class OAuthSignatureMethod_RSA_SHA1 extends OAuthSignatureMethod { 164 | public function get_name() { 165 | return "RSA-SHA1"; 166 | } 167 | 168 | // Up to the SP to implement this lookup of keys. Possible ideas are: 169 | // (1) do a lookup in a table of trusted certs keyed off of consumer 170 | // (2) fetch via http using a url provided by the requester 171 | // (3) some sort of specific discovery code based on request 172 | // 173 | // Either way should return a string representation of the certificate 174 | protected abstract function fetch_public_cert(&$request); 175 | 176 | // Up to the SP to implement this lookup of keys. Possible ideas are: 177 | // (1) do a lookup in a table of trusted certs keyed off of consumer 178 | // 179 | // Either way should return a string representation of the certificate 180 | protected abstract function fetch_private_cert(&$request); 181 | 182 | public function build_signature($request, $consumer, $token) { 183 | $base_string = $request->get_signature_base_string(); 184 | $request->base_string = $base_string; 185 | 186 | // Fetch the private key cert based on the request 187 | $cert = $this->fetch_private_cert($request); 188 | 189 | // Pull the private key ID from the certificate 190 | $privatekeyid = openssl_get_privatekey($cert); 191 | 192 | // Sign using the key 193 | $ok = openssl_sign($base_string, $signature, $privatekeyid); 194 | 195 | // Release the key resource 196 | openssl_free_key($privatekeyid); 197 | 198 | return base64_encode($signature); 199 | } 200 | 201 | public function check_signature($request, $consumer, $token, $signature) { 202 | $decoded_sig = base64_decode($signature); 203 | 204 | $base_string = $request->get_signature_base_string(); 205 | 206 | // Fetch the public key cert based on the request 207 | $cert = $this->fetch_public_cert($request); 208 | 209 | // Pull the public key ID from the certificate 210 | $publickeyid = openssl_get_publickey($cert); 211 | 212 | // Check the computed signature against the one passed in the query 213 | $ok = openssl_verify($base_string, $decoded_sig, $publickeyid); 214 | 215 | // Release the key resource 216 | openssl_free_key($publickeyid); 217 | 218 | return $ok == 1; 219 | } 220 | } 221 | 222 | class OAuthRequest { 223 | private $parameters; 224 | private $http_method; 225 | private $http_url; 226 | // for debug purposes 227 | public $base_string; 228 | public static $version = '1.0'; 229 | public static $POST_INPUT = 'php://input'; 230 | 231 | function __construct($http_method, $http_url, $parameters=NULL) { 232 | @$parameters or $parameters = array(); 233 | $parameters = array_merge( OAuthUtil::parse_parameters(parse_url($http_url, PHP_URL_QUERY)), $parameters); 234 | $this->parameters = $parameters; 235 | $this->http_method = $http_method; 236 | $this->http_url = $http_url; 237 | } 238 | 239 | 240 | /** 241 | * attempt to build up a request from what was passed to the server 242 | */ 243 | public static function from_request($http_method=NULL, $http_url=NULL, $parameters=NULL) { 244 | $scheme = (!isset($_SERVER['HTTPS']) || $_SERVER['HTTPS'] != "on") 245 | ? 'http' 246 | : 'https'; 247 | @$http_url or $http_url = $scheme . 248 | '://' . $_SERVER['HTTP_HOST'] . 249 | ':' . 250 | $_SERVER['SERVER_PORT'] . 251 | $_SERVER['REQUEST_URI']; 252 | @$http_method or $http_method = $_SERVER['REQUEST_METHOD']; 253 | 254 | // We weren't handed any parameters, so let's find the ones relevant to 255 | // this request. 256 | // If you run XML-RPC or similar you should use this to provide your own 257 | // parsed parameter-list 258 | if (!$parameters) { 259 | // Find request headers 260 | $request_headers = OAuthUtil::get_headers(); 261 | 262 | // Parse the query-string to find GET parameters 263 | $parameters = OAuthUtil::parse_parameters($_SERVER['QUERY_STRING']); 264 | 265 | // It's a POST request of the proper content-type, so parse POST 266 | // parameters and add those overriding any duplicates from GET 267 | if ($http_method == "POST" 268 | && @strstr($request_headers["Content-Type"], 269 | "application/x-www-form-urlencoded") 270 | ) { 271 | $post_data = OAuthUtil::parse_parameters( 272 | file_get_contents(self::$POST_INPUT) 273 | ); 274 | $parameters = array_merge($parameters, $post_data); 275 | } 276 | 277 | // We have a Authorization-header with OAuth data. Parse the header 278 | // and add those overriding any duplicates from GET or POST 279 | if (@substr($request_headers['Authorization'], 0, 6) == "OAuth ") { 280 | $header_parameters = OAuthUtil::split_header( 281 | $request_headers['Authorization'] 282 | ); 283 | $parameters = array_merge($parameters, $header_parameters); 284 | } 285 | 286 | } 287 | 288 | return new OAuthRequest($http_method, $http_url, $parameters); 289 | } 290 | 291 | /** 292 | * pretty much a helper function to set up the request 293 | */ 294 | public static function from_consumer_and_token($consumer, $token, $http_method, $http_url, $parameters=NULL) { 295 | @$parameters or $parameters = array(); 296 | $defaults = array("oauth_version" => OAuthRequest::$version, 297 | "oauth_nonce" => OAuthRequest::generate_nonce(), 298 | "oauth_timestamp" => OAuthRequest::generate_timestamp(), 299 | "oauth_consumer_key" => $consumer->key); 300 | if ($token) 301 | $defaults['oauth_token'] = $token->key; 302 | 303 | $parameters = array_merge($defaults, $parameters); 304 | 305 | return new OAuthRequest($http_method, $http_url, $parameters); 306 | } 307 | 308 | public function set_parameter($name, $value, $allow_duplicates = true) { 309 | if ($allow_duplicates && isset($this->parameters[$name])) { 310 | // We have already added parameter(s) with this name, so add to the list 311 | if (is_scalar($this->parameters[$name])) { 312 | // This is the first duplicate, so transform scalar (string) 313 | // into an array so we can add the duplicates 314 | $this->parameters[$name] = array($this->parameters[$name]); 315 | } 316 | 317 | $this->parameters[$name][] = $value; 318 | } else { 319 | $this->parameters[$name] = $value; 320 | } 321 | } 322 | 323 | public function get_parameter($name) { 324 | return isset($this->parameters[$name]) ? $this->parameters[$name] : null; 325 | } 326 | 327 | public function get_parameters() { 328 | return $this->parameters; 329 | } 330 | 331 | public function unset_parameter($name) { 332 | unset($this->parameters[$name]); 333 | } 334 | 335 | /** 336 | * The request parameters, sorted and concatenated into a normalized string. 337 | * @return string 338 | */ 339 | public function get_signable_parameters() { 340 | // Grab all parameters 341 | $params = $this->parameters; 342 | 343 | // Remove oauth_signature if present 344 | // Ref: Spec: 9.1.1 ("The oauth_signature parameter MUST be excluded.") 345 | if (isset($params['oauth_signature'])) { 346 | unset($params['oauth_signature']); 347 | } 348 | 349 | return OAuthUtil::build_http_query($params); 350 | } 351 | 352 | /** 353 | * Returns the base string of this request 354 | * 355 | * The base string defined as the method, the url 356 | * and the parameters (normalized), each urlencoded 357 | * and the concated with &. 358 | */ 359 | public function get_signature_base_string() { 360 | $parts = array( 361 | $this->get_normalized_http_method(), 362 | $this->get_normalized_http_url(), 363 | $this->get_signable_parameters() 364 | ); 365 | 366 | $parts = OAuthUtil::urlencode_rfc3986($parts); 367 | 368 | return implode('&', $parts); 369 | } 370 | 371 | /** 372 | * just uppercases the http method 373 | */ 374 | public function get_normalized_http_method() { 375 | return strtoupper($this->http_method); 376 | } 377 | 378 | /** 379 | * parses the url and rebuilds it to be 380 | * scheme://host/path 381 | */ 382 | public function get_normalized_http_url() { 383 | $parts = parse_url($this->http_url); 384 | 385 | $port = @$parts['port']; 386 | $scheme = $parts['scheme']; 387 | $host = $parts['host']; 388 | $path = @$parts['path']; 389 | 390 | $port or $port = ($scheme == 'https') ? '443' : '80'; 391 | 392 | if (($scheme == 'https' && $port != '443') 393 | || ($scheme == 'http' && $port != '80')) { 394 | $host = "$host:$port"; 395 | } 396 | return "$scheme://$host$path"; 397 | } 398 | 399 | /** 400 | * builds a url usable for a GET request 401 | */ 402 | public function to_url() { 403 | $post_data = $this->to_postdata(); 404 | $out = $this->get_normalized_http_url(); 405 | if ($post_data) { 406 | $out .= '?'.$post_data; 407 | } 408 | return $out; 409 | } 410 | 411 | /** 412 | * builds the data one would send in a POST request 413 | */ 414 | public function to_postdata() { 415 | return OAuthUtil::build_http_query($this->parameters); 416 | } 417 | 418 | /** 419 | * builds the Authorization: header 420 | */ 421 | public function to_header($realm=null) { 422 | $first = true; 423 | if($realm) { 424 | $out = 'Authorization: OAuth realm="' . OAuthUtil::urlencode_rfc3986($realm) . '"'; 425 | $first = false; 426 | } else 427 | $out = 'Authorization: OAuth'; 428 | 429 | $total = array(); 430 | foreach ($this->parameters as $k => $v) { 431 | if (substr($k, 0, 5) != "oauth") continue; 432 | if (is_array($v)) { 433 | throw new OAuthException('Arrays not supported in headers'); 434 | } 435 | $out .= ($first) ? ' ' : ','; 436 | $out .= OAuthUtil::urlencode_rfc3986($k) . 437 | '="' . 438 | OAuthUtil::urlencode_rfc3986($v) . 439 | '"'; 440 | $first = false; 441 | } 442 | return $out; 443 | } 444 | 445 | public function __toString() { 446 | return $this->to_url(); 447 | } 448 | 449 | 450 | public function sign_request($signature_method, $consumer, $token) { 451 | $this->set_parameter( 452 | "oauth_signature_method", 453 | $signature_method->get_name(), 454 | false 455 | ); 456 | $signature = $this->build_signature($signature_method, $consumer, $token); 457 | $this->set_parameter("oauth_signature", $signature, false); 458 | } 459 | 460 | public function build_signature($signature_method, $consumer, $token) { 461 | $signature = $signature_method->build_signature($this, $consumer, $token); 462 | return $signature; 463 | } 464 | 465 | /** 466 | * util function: current timestamp 467 | */ 468 | private static function generate_timestamp() { 469 | return time(); 470 | } 471 | 472 | /** 473 | * util function: current nonce 474 | */ 475 | private static function generate_nonce() { 476 | $mt = microtime(); 477 | $rand = mt_rand(); 478 | 479 | return md5($mt . $rand); // md5s look nicer than numbers 480 | } 481 | } 482 | 483 | class OAuthServer { 484 | protected $timestamp_threshold = 300; // in seconds, five minutes 485 | protected $version = '1.0'; // hi blaine 486 | protected $signature_methods = array(); 487 | 488 | protected $data_store; 489 | 490 | function __construct($data_store) { 491 | $this->data_store = $data_store; 492 | } 493 | 494 | public function add_signature_method($signature_method) { 495 | $this->signature_methods[$signature_method->get_name()] = 496 | $signature_method; 497 | } 498 | 499 | // high level functions 500 | 501 | /** 502 | * process a request_token request 503 | * returns the request token on success 504 | */ 505 | public function fetch_request_token(&$request) { 506 | $this->get_version($request); 507 | 508 | $consumer = $this->get_consumer($request); 509 | 510 | // no token required for the initial token request 511 | $token = NULL; 512 | 513 | $this->check_signature($request, $consumer, $token); 514 | 515 | // Rev A change 516 | $callback = $request->get_parameter('oauth_callback'); 517 | $new_token = $this->data_store->new_request_token($consumer, $callback); 518 | 519 | return $new_token; 520 | } 521 | 522 | /** 523 | * process an access_token request 524 | * returns the access token on success 525 | */ 526 | public function fetch_access_token(&$request) { 527 | $this->get_version($request); 528 | 529 | $consumer = $this->get_consumer($request); 530 | 531 | // requires authorized request token 532 | $token = $this->get_token($request, $consumer, "request"); 533 | 534 | $this->check_signature($request, $consumer, $token); 535 | 536 | // Rev A change 537 | $verifier = $request->get_parameter('oauth_verifier'); 538 | $new_token = $this->data_store->new_access_token($token, $consumer, $verifier); 539 | 540 | return $new_token; 541 | } 542 | 543 | /** 544 | * verify an api call, checks all the parameters 545 | */ 546 | public function verify_request(&$request) { 547 | $this->get_version($request); 548 | $consumer = $this->get_consumer($request); 549 | $token = $this->get_token($request, $consumer, "access"); 550 | $this->check_signature($request, $consumer, $token); 551 | return array($consumer, $token); 552 | } 553 | 554 | // Internals from here 555 | /** 556 | * version 1 557 | */ 558 | private function get_version(&$request) { 559 | $version = $request->get_parameter("oauth_version"); 560 | if (!$version) { 561 | // Service Providers MUST assume the protocol version to be 1.0 if this parameter is not present. 562 | // Chapter 7.0 ("Accessing Protected Ressources") 563 | $version = '1.0'; 564 | } 565 | if ($version !== $this->version) { 566 | throw new OAuthException("OAuth version '$version' not supported"); 567 | } 568 | return $version; 569 | } 570 | 571 | /** 572 | * figure out the signature with some defaults 573 | */ 574 | private function get_signature_method(&$request) { 575 | $signature_method = 576 | @$request->get_parameter("oauth_signature_method"); 577 | 578 | if (!$signature_method) { 579 | // According to chapter 7 ("Accessing Protected Ressources") the signature-method 580 | // parameter is required, and we can't just fallback to PLAINTEXT 581 | throw new OAuthException('No signature method parameter. This parameter is required'); 582 | } 583 | 584 | if (!in_array($signature_method, 585 | array_keys($this->signature_methods))) { 586 | throw new OAuthException( 587 | "Signature method '$signature_method' not supported " . 588 | "try one of the following: " . 589 | implode(", ", array_keys($this->signature_methods)) 590 | ); 591 | } 592 | return $this->signature_methods[$signature_method]; 593 | } 594 | 595 | /** 596 | * try to find the consumer for the provided request's consumer key 597 | */ 598 | private function get_consumer(&$request) { 599 | $consumer_key = @$request->get_parameter("oauth_consumer_key"); 600 | if (!$consumer_key) { 601 | throw new OAuthException("Invalid consumer key"); 602 | } 603 | 604 | $consumer = $this->data_store->lookup_consumer($consumer_key); 605 | if (!$consumer) { 606 | throw new OAuthException("Invalid consumer"); 607 | } 608 | 609 | return $consumer; 610 | } 611 | 612 | /** 613 | * try to find the token for the provided request's token key 614 | */ 615 | private function get_token(&$request, $consumer, $token_type="access") { 616 | $token_field = @$request->get_parameter('oauth_token'); 617 | $token = $this->data_store->lookup_token( 618 | $consumer, $token_type, $token_field 619 | ); 620 | if (!$token) { 621 | throw new OAuthException("Invalid $token_type token: $token_field"); 622 | } 623 | return $token; 624 | } 625 | 626 | /** 627 | * all-in-one function to check the signature on a request 628 | * should guess the signature method appropriately 629 | */ 630 | private function check_signature(&$request, $consumer, $token) { 631 | // this should probably be in a different method 632 | $timestamp = @$request->get_parameter('oauth_timestamp'); 633 | $nonce = @$request->get_parameter('oauth_nonce'); 634 | 635 | $this->check_timestamp($timestamp); 636 | $this->check_nonce($consumer, $token, $nonce, $timestamp); 637 | 638 | $signature_method = $this->get_signature_method($request); 639 | 640 | $signature = $request->get_parameter('oauth_signature'); 641 | $valid_sig = $signature_method->check_signature( 642 | $request, 643 | $consumer, 644 | $token, 645 | $signature 646 | ); 647 | 648 | if (!$valid_sig) { 649 | throw new OAuthException("Invalid signature"); 650 | } 651 | } 652 | 653 | /** 654 | * check that the timestamp is new enough 655 | */ 656 | private function check_timestamp($timestamp) { 657 | if( ! $timestamp ) 658 | throw new OAuthException( 659 | 'Missing timestamp parameter. The parameter is required' 660 | ); 661 | 662 | // verify that timestamp is recentish 663 | $now = time(); 664 | if (abs($now - $timestamp) > $this->timestamp_threshold) { 665 | throw new OAuthException( 666 | "Expired timestamp, yours $timestamp, ours $now" 667 | ); 668 | } 669 | } 670 | 671 | /** 672 | * check that the nonce is not repeated 673 | */ 674 | private function check_nonce($consumer, $token, $nonce, $timestamp) { 675 | if( ! $nonce ) 676 | throw new OAuthException( 677 | 'Missing nonce parameter. The parameter is required' 678 | ); 679 | 680 | // verify that the nonce is uniqueish 681 | $found = $this->data_store->lookup_nonce( 682 | $consumer, 683 | $token, 684 | $nonce, 685 | $timestamp 686 | ); 687 | if ($found) { 688 | throw new OAuthException("Nonce already used: $nonce"); 689 | } 690 | } 691 | 692 | } 693 | 694 | class OAuthDataStore { 695 | function lookup_consumer($consumer_key) { 696 | // implement me 697 | } 698 | 699 | function lookup_token($consumer, $token_type, $token) { 700 | // implement me 701 | } 702 | 703 | function lookup_nonce($consumer, $token, $nonce, $timestamp) { 704 | // implement me 705 | } 706 | 707 | function new_request_token($consumer, $callback = null) { 708 | // return a new token attached to this consumer 709 | } 710 | 711 | function new_access_token($token, $consumer, $verifier = null) { 712 | // return a new access token attached to this consumer 713 | // for the user associated with this token if the request token 714 | // is authorized 715 | // should also invalidate the request token 716 | } 717 | 718 | } 719 | 720 | class OAuthUtil { 721 | public static function urlencode_rfc3986($input) { 722 | if (is_array($input)) { 723 | return array_map(array('OAuthUtil', 'urlencode_rfc3986'), $input); 724 | } else if (is_scalar($input)) { 725 | return str_replace( 726 | '+', 727 | ' ', 728 | str_replace('%7E', '~', rawurlencode($input)) 729 | ); 730 | } else { 731 | return ''; 732 | } 733 | } 734 | 735 | 736 | // This decode function isn't taking into consideration the above 737 | // modifications to the encoding process. However, this method doesn't 738 | // seem to be used anywhere so leaving it as is. 739 | public static function urldecode_rfc3986($string) { 740 | return urldecode($string); 741 | } 742 | 743 | // Utility function for turning the Authorization: header into 744 | // parameters, has to do some unescaping 745 | // Can filter out any non-oauth parameters if needed (default behaviour) 746 | public static function split_header($header, $only_allow_oauth_parameters = true) { 747 | $pattern = '/(([-_a-z]*)=("([^"]*)"|([^,]*)),?)/'; 748 | $offset = 0; 749 | $params = array(); 750 | while (preg_match($pattern, $header, $matches, PREG_OFFSET_CAPTURE, $offset) > 0) { 751 | $match = $matches[0]; 752 | $header_name = $matches[2][0]; 753 | $header_content = (isset($matches[5])) ? $matches[5][0] : $matches[4][0]; 754 | if (preg_match('/^oauth_/', $header_name) || !$only_allow_oauth_parameters) { 755 | $params[$header_name] = OAuthUtil::urldecode_rfc3986($header_content); 756 | } 757 | $offset = $match[1] + strlen($match[0]); 758 | } 759 | 760 | if (isset($params['realm'])) { 761 | unset($params['realm']); 762 | } 763 | 764 | return $params; 765 | } 766 | 767 | // helper to try to sort out headers for people who aren't running apache 768 | public static function get_headers() { 769 | if (function_exists('apache_request_headers')) { 770 | // we need this to get the actual Authorization: header 771 | // because apache tends to tell us it doesn't exist 772 | $headers = apache_request_headers(); 773 | 774 | // sanitize the output of apache_request_headers because 775 | // we always want the keys to be Cased-Like-This and arh() 776 | // returns the headers in the same case as they are in the 777 | // request 778 | $out = array(); 779 | foreach( $headers AS $key => $value ) { 780 | $key = str_replace( 781 | " ", 782 | "-", 783 | ucwords(strtolower(str_replace("-", " ", $key))) 784 | ); 785 | $out[$key] = $value; 786 | } 787 | } else { 788 | // otherwise we don't have apache and are just going to have to hope 789 | // that $_SERVER actually contains what we need 790 | $out = array(); 791 | if( isset($_SERVER['CONTENT_TYPE']) ) 792 | $out['Content-Type'] = $_SERVER['CONTENT_TYPE']; 793 | if( isset($_ENV['CONTENT_TYPE']) ) 794 | $out['Content-Type'] = $_ENV['CONTENT_TYPE']; 795 | 796 | foreach ($_SERVER as $key => $value) { 797 | if (substr($key, 0, 5) == "HTTP_") { 798 | // this is chaos, basically it is just there to capitalize the first 799 | // letter of every word that is not an initial HTTP and strip HTTP 800 | // code from przemek 801 | $key = str_replace( 802 | " ", 803 | "-", 804 | ucwords(strtolower(str_replace("_", " ", substr($key, 5)))) 805 | ); 806 | $out[$key] = $value; 807 | } 808 | } 809 | } 810 | return $out; 811 | } 812 | 813 | // This function takes a input like a=b&a=c&d=e and returns the parsed 814 | // parameters like this 815 | // array('a' => array('b','c'), 'd' => 'e') 816 | public static function parse_parameters( $input ) { 817 | if (!isset($input) || !$input) return array(); 818 | 819 | $pairs = explode('&', $input); 820 | 821 | $parsed_parameters = array(); 822 | foreach ($pairs as $pair) { 823 | $split = explode('=', $pair, 2); 824 | $parameter = OAuthUtil::urldecode_rfc3986($split[0]); 825 | $value = isset($split[1]) ? OAuthUtil::urldecode_rfc3986($split[1]) : ''; 826 | 827 | if (isset($parsed_parameters[$parameter])) { 828 | // We have already recieved parameter(s) with this name, so add to the list 829 | // of parameters with this name 830 | 831 | if (is_scalar($parsed_parameters[$parameter])) { 832 | // This is the first duplicate, so transform scalar (string) into an array 833 | // so we can add the duplicates 834 | $parsed_parameters[$parameter] = array($parsed_parameters[$parameter]); 835 | } 836 | 837 | $parsed_parameters[$parameter][] = $value; 838 | } else { 839 | $parsed_parameters[$parameter] = $value; 840 | } 841 | } 842 | return $parsed_parameters; 843 | } 844 | 845 | public static function build_http_query($params) { 846 | if (!$params) return ''; 847 | 848 | // Urlencode both keys and values 849 | $keys = OAuthUtil::urlencode_rfc3986(array_keys($params)); 850 | $values = OAuthUtil::urlencode_rfc3986(array_values($params)); 851 | $params = array_combine($keys, $values); 852 | 853 | // Parameters are sorted by name, using lexicographical byte value ordering. 854 | // Ref: Spec: 9.1.1 (1) 855 | uksort($params, 'strcmp'); 856 | 857 | $pairs = array(); 858 | foreach ($params as $parameter => $value) { 859 | if (is_array($value)) { 860 | // If two or more parameters share the same name, they are sorted by their value 861 | // Ref: Spec: 9.1.1 (1) 862 | natsort($value); 863 | foreach ($value as $duplicate_value) { 864 | $pairs[] = $parameter . '=' . $duplicate_value; 865 | } 866 | } else { 867 | $pairs[] = $parameter . '=' . $value; 868 | } 869 | } 870 | // For each parameter, the name is separated from the corresponding value by an '=' character (ASCII code 61) 871 | // Each name-value pair is separated by an '&' character (ASCII code 38) 872 | return implode('&', $pairs); 873 | } 874 | } 875 | -------------------------------------------------------------------------------- /api/callback.php: -------------------------------------------------------------------------------- 1 | getAccessToken($_REQUEST['oauth_verifier']); 23 | $content = $connection->get('account/verify_credentials'); 24 | /* Save the access tokens. Normally these would be saved in a database for future use. */ 25 | $_SESSION['access_token'] = $access_token; 26 | /* Remove no longer needed request tokens */ 27 | unset($_SESSION['oauth_token']); 28 | unset($_SESSION['oauth_token_secret']); 29 | /* If HTTP response is 200 continue otherwise send to connect page to retry */ 30 | if (200 == $connection->http_code) { 31 | /* The user has been verified and the access tokens can be saved for future use */ 32 | $_SESSION['status'] = 'verified'; 33 | 34 | $arrays = objectToArray($content); 35 | 36 | $user_id = $arrays['id']; 37 | $name = $arrays['name']; 38 | $propic = $arrays['profile_image_url']; 39 | 40 | $token = sha1(generateRandomString(10).$userid); 41 | $twitter_token = $access_token["oauth_token"]; 42 | $twitter_secret = $access_token["oauth_token_secret"]; 43 | 44 | //check if the user exists 45 | $query = $conn->prepare("SELECT * FROM users WHERE userid = :userid LIMIT 1"); 46 | $query->bindValue(':userid', $user_id); 47 | $query->execute(); 48 | 49 | $row = $query->fetchAll(PDO::FETCH_ASSOC); 50 | 51 | if($row==true) 52 | { 53 | $_SESSION['user_id'] = $user_id; 54 | $_SESSION['propic'] = $propic; 55 | $_SESSION['myname'] = $name; 56 | $_SESSION['user_status'] = true; 57 | 58 | $query = $conn->prepare("UPDATE users 59 | SET token = :token 60 | , propic = :propic WHERE userid = :userid"); 61 | $query->bindValue(':token', $token); 62 | $query->bindValue(':propic', $propic); 63 | $query->bindValue(':userid', $user_id); 64 | 65 | $query->execute(); 66 | 67 | $cookie_name = 'info'; 68 | $cookie_value = $token; 69 | setcookie($cookie_name, $cookie_value, time() + (86400 * 30), '/'); // 86400 = 1 day 70 | header('Location: /'); 71 | 72 | } 73 | else 74 | { 75 | $_SESSION['user_id'] = $user_id; 76 | $_SESSION['propic'] = $propic; 77 | $_SESSION['myname'] = $name; 78 | $_SESSION['user_status'] = true; 79 | 80 | $query = $conn->prepare("INSERT into users (name,userid,propic,token,twitter_token,twitter_secret) VALUES (:name, :userid, :propic, :token, :twtoken, :twsecret)"); 81 | 82 | $query->execute(array(':name' => $name, ':userid' => $user_id, ':propic' => $propic, ':token' => $token, ':twtoken' => $twitter_token, ':twsecret' => $twitter_secret)); 83 | 84 | $cookie_name = 'info'; 85 | $cookie_value = $token; 86 | setcookie($cookie_name, $cookie_value, time() + (86400 * 30), '/'); // 86400 = 1 day 87 | 88 | header('Location: /'); 89 | } 90 | 91 | 92 | } else { 93 | /* Save HTTP status for error dialog on connnect page.*/ 94 | header('Location: ./clearsessions.php'); 95 | } 96 | -------------------------------------------------------------------------------- /api/clearsessions.php: -------------------------------------------------------------------------------- 1 | prepare("SELECT 1 FROM comments WHERE commentid = :rand"); 13 | do { 14 | $random_string = generateRandomString(5); 15 | $query->bindValue(':rand', $random_string); 16 | $query->execute(); 17 | } 18 | while 19 | ( 20 | $query->rowCount() > 0 21 | 22 | ); 23 | return $random_string; 24 | } 25 | 26 | 27 | if($_SESSION['user_status']==true) 28 | { 29 | $user = $_SESSION['user_id']; 30 | $comment_id = postex($conn); 31 | 32 | $query = $conn->prepare("INSERT INTO comments (comment, post_id, user_id, commentid, ctime) VALUES (:comment, :post, :user, :commentid, :time)"); 33 | $query->execute(array(':comment' => $comment, ':time' => $time, ':user' => $user, ':post' => $post, ":commentid" => $comment_id)); 34 | echo $comment_id; 35 | } 36 | else 37 | { 38 | echo "nouser"; 39 | } 40 | 41 | 42 | ?> 43 | -------------------------------------------------------------------------------- /api/config.php: -------------------------------------------------------------------------------- 1 | prepare("SELECT * FROM votes WHERE user_id = :user AND post_id = :id LIMIT 1"); 41 | $query->bindValue(':user', $cuser); 42 | $query->bindValue(':id', $id); 43 | $query->execute(); 44 | $getcuser = $query->fetchAll(PDO::FETCH_ASSOC); 45 | 46 | if($getcuser == true) 47 | { 48 | return true; 49 | } 50 | else 51 | { 52 | return false; 53 | } 54 | } 55 | else 56 | { 57 | return false; 58 | } 59 | 60 | } 61 | 62 | function totalvotes($id,$conn) 63 | { 64 | $getvotes = $conn->prepare("SELECT post_id FROM votes WHERE post_id = :id"); 65 | $getvotes->bindValue(':id', $id); 66 | $getvotes->execute(); 67 | $getvotes = $getvotes->rowCount(); 68 | 69 | return $getvotes; 70 | } 71 | 72 | function totalcomments($id, $conn) 73 | { 74 | $query = $conn->prepare("SELECT COUNT(*) FROM comments WHERE post_id = :id"); 75 | $query->bindValue(':id', $id); 76 | $query->execute(); 77 | 78 | $row = $query->fetch(PDO::FETCH_ASSOC); 79 | $gc = $row["COUNT(*)"]; 80 | return $gc; 81 | } 82 | -------------------------------------------------------------------------------- /api/gc.php: -------------------------------------------------------------------------------- 1 | prepare("SELECT * FROM comments WHERE post_id = :id"); 11 | $query->bindValue(':id', $id); 12 | $query->execute(); 13 | 14 | 15 | while ($row = $query->fetch(PDO::FETCH_ASSOC)) { 16 | $user_id = $row['user_id']; 17 | $post_id = $row['post_id']; 18 | $comment = $row['comment']; 19 | $comment_id = $row['commentid']; 20 | $ctime = $row['ctime']; 21 | 22 | $gu = $conn->prepare("SELECT * FROM users WHERE userid = :user LIMIT 1"); 23 | $gu->bindValue(':user', $user_id); 24 | $gu->execute(); 25 | $ru = $gu->fetchAll(PDO::FETCH_ASSOC); 26 | 27 | $user_name = $ru[0]['name']; 28 | $propic = $ru[0]['propic']; 29 | 30 | $commentz[] = [comment => $comment, 31 | commentid => $comment_id, 32 | ctime => $ctime, 33 | post_id => $post_id, 34 | user_id => $user_id, 35 | user_name => $user_name, 36 | propic => $propic 37 | ]; 38 | 39 | } 40 | 41 | $jcom = json_encode($commentz); 42 | print $jcom; 43 | 44 | 45 | 46 | ?> 47 | -------------------------------------------------------------------------------- /api/getpost.php: -------------------------------------------------------------------------------- 1 | prepare("SELECT * FROM posts WHERE postid = :id LIMIT 1"); 11 | $query->execute(array(':id' => $id)); 12 | $row = $query->fetch(PDO::FETCH_ASSOC); 13 | 14 | if( $row == true) 15 | { 16 | $title = $row['title']; 17 | $tagline = $row['tagline']; 18 | $link = $row['link']; 19 | $time = $row['post_time']; 20 | $user = $row['user']; 21 | 22 | $query = $conn->prepare("SELECT * FROM users WHERE userid = :user LIMIT 1"); 23 | $query->execute(array(':user' => $user)); 24 | $getuser = $query->fetch(PDO::FETCH_ASSOC); 25 | 26 | $user_name = $getuser['name']; 27 | $pro_pic = $getuser['propic']; 28 | 29 | $isvoted = isuservoted($id,$conn); 30 | $total_votes = totalvotes($id,$conn); 31 | 32 | $post_status = [ 33 | 'title' => $title, 34 | 'tagline' => $tagline, 35 | 'isVoted' => $isvoted, 36 | 'datalink' => $id, 37 | 'user' => $user_name, 38 | 'upropic' => $pro_pic, 39 | 'votecount' => $total_votes, 40 | 'post_date' => $time, 41 | 'post_url' => $link 42 | 43 | ]; 44 | $post_status = json_encode($post_status); 45 | print $post_status; 46 | } 47 | else 48 | { 49 | print "nopost"; 50 | } 51 | 52 | ?> 53 | -------------------------------------------------------------------------------- /api/index.htm: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /api/indexmaker.php: -------------------------------------------------------------------------------- 1 | 0) 13 | { 14 | $sign = 1; 15 | } 16 | elseif($s < 0) 17 | { 18 | $sign = -1; 19 | } 20 | else 21 | { 22 | $sign = 0; 23 | } 24 | 25 | $seconds = $time - 1412433234; 26 | $signxorder = $sign * $order; 27 | $signxorderpseconds = $signxorder + $seconds; 28 | $score = round($signxorderpseconds / 45000 ,7); 29 | return $score; 30 | 31 | } 32 | 33 | $query = $conn->prepare("SELECT * FROM posts ORDER BY id DESC LIMIT 100"); 34 | $query->execute(); 35 | 36 | while ($row = $query->fetch(PDO::FETCH_ASSOC)) 37 | { 38 | $postid = $row['postid']; 39 | $userid = $row['user']; 40 | $title = $row['title']; 41 | $tagling = $row['tagline']; 42 | $link = $row['link']; 43 | $post_time = $row['post_time']; 44 | 45 | $total_votes = totalvotes($postid,$conn); 46 | $hotrank = getscore($total_votes, $post_time); 47 | $isvoted = isuservoted($postid,$conn); 48 | 49 | $gu = $conn->prepare("SELECT * FROM users WHERE userid = :id LIMIT 1"); 50 | $gu->execute(array(':id' => $userid)); 51 | 52 | $gur = $gu->fetch(PDO::FETCH_ASSOC); 53 | $user_name = $gur['name']; 54 | $user_propic = $gur['propic']; 55 | 56 | $gcoms = totalcomments($postid,$conn); 57 | 58 | $allposts[] = ['datalink' => $postid, 59 | 'user_id' => $userid, 60 | 'upropic' => $user_propic, 61 | 'user' => $user_name, 62 | 'title' => $title, 63 | 'tag_line' => $tagling, 64 | 'post_url' => $link, 65 | 'votecount' => $total_votes, 66 | 'hot_rank' => $hotrank, 67 | 'isVoted' => $isvoted, 68 | 'post_time' => $post_time, 69 | 'num_comments' => $gcoms]; 70 | } 71 | 72 | usort($allposts, function($a, $b) { 73 | return ($a['hot_rank'] < $b['hot_rank']) ? -1 : 1; 74 | // return $a['hot_rank'] - $b['hot_rank']; 75 | }); 76 | 77 | $rsl = array_reverse($allposts); 78 | $sl = array_slice($rsl, 0, 20); 79 | 80 | if(isset($_REQUEST['pre'])) 81 | { 82 | echo "
"; 83 | var_dump($sl); 84 | echo ""; 85 | } 86 | else 87 | { 88 | print(json_encode($sl)); 89 | } 90 | ?> 91 | -------------------------------------------------------------------------------- /api/login.php: -------------------------------------------------------------------------------- 1 | getRequestToken(OAUTH_CALLBACK); 10 | /* Save temporary credentials to session. */ 11 | $_SESSION['oauth_token'] = $token = $request_token['oauth_token']; 12 | $_SESSION['oauth_token_secret'] = $request_token['oauth_token_secret']; 13 | /* If last connection failed don't display authorization link. */ 14 | switch ($connection->http_code) { 15 | case 200: 16 | /* Build authorize URL and redirect user to Twitter. */ 17 | $url = $connection->getAuthorizeURL($token); 18 | header('Location: ' . $url); 19 | break; 20 | default: 21 | /* Show notification if something went wrong. */ 22 | echo 'Could not connect to Twitter. Refresh the page or try again later.'; 23 | } 24 | -------------------------------------------------------------------------------- /api/logout.php: -------------------------------------------------------------------------------- 1 | prepare("SELECT 1 FROM posts WHERE postid = :rand"); 13 | do { 14 | $random_string = generateRandomString(5); 15 | $query->bindValue(':rand', $random_string); 16 | $query->execute(); 17 | } while 18 | ( 19 | $query->rowCount() > 0 20 | 21 | ); 22 | return $random_string; 23 | } 24 | 25 | if($_SESSION['user_status']== true) 26 | { 27 | $url = strip_tags($_POST['purl']); 28 | $title = strip_tags($_POST['ptitle']); 29 | $tagling = strip_tags($_POST['ptagline']); 30 | 31 | $query = $conn->prepare("SELECT postid FROM posts WHERE link = :url LIMIT 1"); 32 | $query->execute(array(':url' => $url)); 33 | $row = $query->fetchAll(PDO::FETCH_ASSOC); 34 | 35 | if($row == true) 36 | { 37 | print $row[0]['postid']; 38 | } 39 | else 40 | { 41 | $randid = postex($conn); 42 | $query = $conn->prepare("INSERT INTO posts (postid,title,tagline,link,user,post_time) 43 | VALUES (:raid, :title, :tagline, :url, :userid, :timest)"); 44 | $query->execute(array(':raid' => $randid, ':title' => $title, ':tagline' => $tagling, ':url' => $url, ':userid' => $_SESSION['user_id'], ':timest' => time())); 45 | 46 | $query = $conn->prepare("INSERT INTO votes (post_id,user_id, op_id) VALUES (:post, :user, :opid)"); 47 | $query->execute(array(':post'=>$randid, ':user' => $_SESSION['user_id'], ':opid' => $_SESSION['user_id'])); 48 | print $randid; 49 | 50 | } 51 | } 52 | else 53 | { 54 | echo "User out"; 55 | } 56 | ?> 57 | -------------------------------------------------------------------------------- /api/twa.php: -------------------------------------------------------------------------------- 1 | http_status; } 54 | function lastAPICall() { return $this->last_api_call; } 55 | 56 | /** 57 | * construct TwitterOAuth object 58 | */ 59 | function __construct($consumer_key, $consumer_secret, $oauth_token = NULL, $oauth_token_secret = NULL) { 60 | $this->sha1_method = new OAuthSignatureMethod_HMAC_SHA1(); 61 | $this->consumer = new OAuthConsumer($consumer_key, $consumer_secret); 62 | if (!empty($oauth_token) && !empty($oauth_token_secret)) { 63 | $this->token = new OAuthConsumer($oauth_token, $oauth_token_secret); 64 | } else { 65 | $this->token = NULL; 66 | } 67 | } 68 | 69 | 70 | /** 71 | * Get a request_token from Twitter 72 | * 73 | * @returns a key/value array containing oauth_token and oauth_token_secret 74 | */ 75 | function getRequestToken($oauth_callback) { 76 | $parameters = array(); 77 | $parameters['oauth_callback'] = $oauth_callback; 78 | $request = $this->oAuthRequest($this->requestTokenURL(), 'GET', $parameters); 79 | $token = OAuthUtil::parse_parameters($request); 80 | $this->token = new OAuthConsumer($token['oauth_token'], $token['oauth_token_secret']); 81 | return $token; 82 | } 83 | 84 | /** 85 | * Get the authorize URL 86 | * 87 | * @returns a string 88 | */ 89 | function getAuthorizeURL($token, $sign_in_with_twitter = TRUE) { 90 | if (is_array($token)) { 91 | $token = $token['oauth_token']; 92 | } 93 | if (empty($sign_in_with_twitter)) { 94 | return $this->authorizeURL() . "?oauth_token={$token}"; 95 | } else { 96 | return $this->authenticateURL() . "?oauth_token={$token}"; 97 | } 98 | } 99 | 100 | /** 101 | * Exchange request token and secret for an access token and 102 | * secret, to sign API calls. 103 | * 104 | * @returns array("oauth_token" => "the-access-token", 105 | * "oauth_token_secret" => "the-access-secret", 106 | * "user_id" => "9436992", 107 | * "screen_name" => "abraham") 108 | */ 109 | function getAccessToken($oauth_verifier) { 110 | $parameters = array(); 111 | $parameters['oauth_verifier'] = $oauth_verifier; 112 | $request = $this->oAuthRequest($this->accessTokenURL(), 'GET', $parameters); 113 | $token = OAuthUtil::parse_parameters($request); 114 | $this->token = new OAuthConsumer($token['oauth_token'], $token['oauth_token_secret']); 115 | return $token; 116 | } 117 | 118 | /** 119 | * One time exchange of username and password for access token and secret. 120 | * 121 | * @returns array("oauth_token" => "the-access-token", 122 | * "oauth_token_secret" => "the-access-secret", 123 | * "user_id" => "9436992", 124 | * "screen_name" => "abraham", 125 | * "x_auth_expires" => "0") 126 | */ 127 | function getXAuthToken($username, $password) { 128 | $parameters = array(); 129 | $parameters['x_auth_username'] = $username; 130 | $parameters['x_auth_password'] = $password; 131 | $parameters['x_auth_mode'] = 'client_auth'; 132 | $request = $this->oAuthRequest($this->accessTokenURL(), 'POST', $parameters); 133 | $token = OAuthUtil::parse_parameters($request); 134 | $this->token = new OAuthConsumer($token['oauth_token'], $token['oauth_token_secret']); 135 | return $token; 136 | } 137 | 138 | /** 139 | * GET wrapper for oAuthRequest. 140 | */ 141 | function get($url, $parameters = array()) { 142 | $response = $this->oAuthRequest($url, 'GET', $parameters); 143 | if ($this->format === 'json' && $this->decode_json) { 144 | return json_decode($response); 145 | } 146 | return $response; 147 | } 148 | 149 | /** 150 | * POST wrapper for oAuthRequest. 151 | */ 152 | function post($url, $parameters = array()) { 153 | $response = $this->oAuthRequest($url, 'POST', $parameters); 154 | if ($this->format === 'json' && $this->decode_json) { 155 | return json_decode($response); 156 | } 157 | return $response; 158 | } 159 | 160 | /** 161 | * DELETE wrapper for oAuthReqeust. 162 | */ 163 | function delete($url, $parameters = array()) { 164 | $response = $this->oAuthRequest($url, 'DELETE', $parameters); 165 | if ($this->format === 'json' && $this->decode_json) { 166 | return json_decode($response); 167 | } 168 | return $response; 169 | } 170 | 171 | /** 172 | * Format and sign an OAuth / API request 173 | */ 174 | function oAuthRequest($url, $method, $parameters) { 175 | if (strrpos($url, 'https://') !== 0 && strrpos($url, 'http://') !== 0) { 176 | $url = "{$this->host}{$url}.{$this->format}"; 177 | } 178 | $request = OAuthRequest::from_consumer_and_token($this->consumer, $this->token, $method, $url, $parameters); 179 | $request->sign_request($this->sha1_method, $this->consumer, $this->token); 180 | switch ($method) { 181 | case 'GET': 182 | return $this->http($request->to_url(), 'GET'); 183 | default: 184 | return $this->http($request->get_normalized_http_url(), $method, $request->to_postdata()); 185 | } 186 | } 187 | 188 | /** 189 | * Make an HTTP request 190 | * 191 | * @return API results 192 | */ 193 | function http($url, $method, $postfields = NULL) { 194 | $this->http_info = array(); 195 | $ci = curl_init(); 196 | /* Curl settings */ 197 | curl_setopt($ci, CURLOPT_USERAGENT, $this->useragent); 198 | curl_setopt($ci, CURLOPT_CONNECTTIMEOUT, $this->connecttimeout); 199 | curl_setopt($ci, CURLOPT_TIMEOUT, $this->timeout); 200 | curl_setopt($ci, CURLOPT_RETURNTRANSFER, TRUE); 201 | curl_setopt($ci, CURLOPT_HTTPHEADER, array('Expect:')); 202 | curl_setopt($ci, CURLOPT_SSL_VERIFYPEER, $this->ssl_verifypeer); 203 | curl_setopt($ci, CURLOPT_HEADERFUNCTION, array($this, 'getHeader')); 204 | curl_setopt($ci, CURLOPT_HEADER, FALSE); 205 | 206 | switch ($method) { 207 | case 'POST': 208 | curl_setopt($ci, CURLOPT_POST, TRUE); 209 | if (!empty($postfields)) { 210 | curl_setopt($ci, CURLOPT_POSTFIELDS, $postfields); 211 | } 212 | break; 213 | case 'DELETE': 214 | curl_setopt($ci, CURLOPT_CUSTOMREQUEST, 'DELETE'); 215 | if (!empty($postfields)) { 216 | $url = "{$url}?{$postfields}"; 217 | } 218 | } 219 | 220 | curl_setopt($ci, CURLOPT_URL, $url); 221 | $response = curl_exec($ci); 222 | $this->http_code = curl_getinfo($ci, CURLINFO_HTTP_CODE); 223 | $this->http_info = array_merge($this->http_info, curl_getinfo($ci)); 224 | $this->url = $url; 225 | curl_close ($ci); 226 | return $response; 227 | } 228 | 229 | /** 230 | * Get the header info to store. 231 | */ 232 | function getHeader($ch, $header) { 233 | $i = strpos($header, ':'); 234 | if (!empty($i)) { 235 | $key = str_replace('-', '_', strtolower(substr($header, 0, $i))); 236 | $value = trim(substr($header, $i + 2)); 237 | $this->http_header[$key] = $value; 238 | } 239 | return strlen($header); 240 | } 241 | } 242 | -------------------------------------------------------------------------------- /api/ustatus.php: -------------------------------------------------------------------------------- 1 | $user_status]; 20 | return json_encode($array); 21 | 22 | } 23 | else 24 | { 25 | $cookie_name = "info"; 26 | $cvalue = $_COOKIE[$cookie_name]; 27 | 28 | $query = $conn->prepare("SELECT * FROM users WHERE token = :token LIMIT 1"); 29 | $query->bindValue(':token', $cvalue, PDO::PARAM_STR); 30 | $query->execute(); 31 | $rows = $query->fetchAll(PDO::FETCH_ASSOC); 32 | 33 | if($rows) 34 | { 35 | $token = $rows[0]['twitter_token']; 36 | $secret = $rows[0]['twitter_secret']; 37 | $user_id = $rows[0]['userid']; 38 | 39 | 40 | $connection = new TwitterOAuth(CONSUMER_KEY, CONSUMER_SECRET, $token , $secret); 41 | $content = $connection->get('account/verify_credentials'); 42 | 43 | $arrays = objectToArray($content); 44 | $userid = $arrays['id']; 45 | $name = $arrays['name']; 46 | $propic = $arrays['profile_image_url']; 47 | 48 | if($user_id==$userid) 49 | { 50 | 51 | $_SESSION['user_status'] = $user_status = true; 52 | $_SESSION['user_id'] = $user_id; 53 | $_SESSION['myname'] = $name; 54 | $_SESSION['propic'] = $propic; 55 | 56 | $array = [ 57 | user_id => $_SESSION['user_id'], 58 | user_status => $_SESSION['user_status'], 59 | name => $name, 60 | propic => $propic]; 61 | 62 | $query = $conn->prepare("UPDATE users 63 | SET name = :name 64 | , propic = :propic WHERE userid= :usserid"); 65 | 66 | $query->bindValue(':name', $name); 67 | $query->bindValue(':propic', $propic); 68 | $query->bindValue(':usserid', $userid); 69 | return json_encode($array); 70 | } 71 | else 72 | { 73 | session_destroy(); 74 | $user_status = false; 75 | $array = [user_status => $user_status]; 76 | return json_encode($array); 77 | 78 | } 79 | } 80 | else 81 | { 82 | session_destroy(); 83 | $user_status = false; 84 | $array = [user_status => $user_status]; 85 | return json_encode($array); 86 | } 87 | } 88 | 89 | } 90 | elseif($_SESSION['user_status'] == true) 91 | { 92 | 93 | $array = [ 94 | 'user_id' => $_SESSION['user_id'], 95 | 'user_status' => $_SESSION['user_status'], 96 | 'name' => $_SESSION['myname'], 97 | 'propic' => $_SESSION['propic'] 98 | ]; 99 | return json_encode($array); 100 | } 101 | } 102 | 103 | function checkuser() 104 | { 105 | if($_SESSION['user_status'] == true) 106 | { 107 | $array = [ 108 | 'user_id' => $_SESSION['user_id'], 109 | 'user_status' => $_SESSION['user_status'], 110 | 'name' => $_SESSION['myname'], 111 | 'propic' => $_SESSION['propic'] 112 | ]; 113 | return json_encode($array); 114 | } 115 | else 116 | { 117 | userlogin(); 118 | $array = [ 119 | 'user_id' => $_SESSION['user_id'], 120 | 'user_status' => $_SESSION['user_status'], 121 | 'name' => $myname, 122 | 'propic' => $propic 123 | ]; 124 | return json_encode($array); 125 | } 126 | 127 | } 128 | 129 | print(userlogin($conn)); 130 | 131 | ?> 132 | -------------------------------------------------------------------------------- /api/vote.php: -------------------------------------------------------------------------------- 1 | prepare("SELECT * FROM posts WHERE postid = :id LIMIT 1"); 16 | $query->execute(array(':id' => $post)); 17 | $result = $query -> fetch(PDO::FETCH_ASSOC); 18 | $user_id = $result['user']; 19 | 20 | if($user_id == $user) 21 | { 22 | echo "X"; 23 | } 24 | elseif($user_id != $user) 25 | { 26 | $gp = $conn->prepare("SELECT * FROM votes WHERE post_id = :post AND user_id = :user LIMIT 1") or die(); 27 | $gp->execute(array(':post' => $post , ':user' => $user)); 28 | $result = $gp->rowCount(); 29 | 30 | if($result > 0) 31 | { 32 | $dq = $conn->prepare("DELETE FROM votes WHERE post_id = :post AND user_id = :user"); 33 | $dq->execute(array(':post'=> $post, ':user' => $user)); 34 | 35 | $vc = $conn->prepare("SELECT * FROM votes WHERE post_id = :post"); 36 | $vc->execute(array(':post' => $post)); 37 | print $vc->rowCount(); 38 | } 39 | else 40 | { 41 | $aq = $conn->prepare("INSERT INTO votes (post_id,user_id, op_id) VALUES (:post, :user, :op)"); 42 | $aq->execute(array(':post' => $post, ':user' => $user, ':op' => $user_id)); 43 | 44 | $vc = $conn->prepare("SELECT * FROM votes WHERE post_id = :post"); 45 | $vc->execute(array(':post' => $post)); 46 | print $vc->rowCount(); 47 | } 48 | } 49 | } 50 | else 51 | { 52 | echo "L"; 53 | } 54 | ?> 55 | -------------------------------------------------------------------------------- /assets/app.js: -------------------------------------------------------------------------------- 1 | App = Ember.Application.create(); 2 | 3 | //Routers 4 | 5 | App.Router.map(function() { 6 | this.resource('index', {path : '/'} , function() { 7 | this.resource('post', { path: '/p/:post_id' }); 8 | this.resource('login'); 9 | this.resource('about'); 10 | }); 11 | }); 12 | 13 | //Location API, keep auto for browser history API and none for # URL, hashbang for #! URLs to bettter SEO 14 | App.Router.reopen({ 15 | // location: 'auto' 16 | location : 'hashbang' 17 | }); 18 | 19 | //Controllers 20 | App.IndexController = Ember.ObjectController.extend({ 21 | showSubmit: false, 22 | actions : { 23 | toggleSubmit : function() { //showing new submit 24 | this.set('showSubmit', !this.get('showSubmit')); 25 | } 26 | }, 27 | 28 | submit : function(){ //submitting new story 29 | this.set('onsubmit' , true); 30 | var url = this.get("purl"); 31 | var tagline = this.get("ptagline"); 32 | var title = this.get("ptitle"); 33 | this.set("ptitle" , ''); 34 | this.set("ptagline",""); 35 | this.set("purl",""); 36 | 37 | var self= this; 38 | this.set('onsubmit', false); 39 | $.post( "/api/post.php", { purl: url, ptagline: tagline, ptitle: title }) 40 | .done(function(data) { 41 | self.set('showSubmit', !self.get('showSubmit')); 42 | self.transitionTo('post', data); 43 | }); 44 | } 45 | 46 | }); 47 | 48 | App.BookController = Ember.ObjectController.extend({ 49 | 50 | islg : false, 51 | 52 | actions: { 53 | voteup: function(e) { //upvoting function 54 | this.set('isVoted', false); 55 | 56 | var self = this; 57 | $.post('/api/vote.php', {post_id : e}) 58 | .done(function(data){ 59 | if(data == "L") 60 | { 61 | self.set('islg' , true); 62 | } 63 | else 64 | { 65 | self.set('votecount', data); 66 | } 67 | }); 68 | console.log(e); 69 | }, 70 | 71 | votedown: function(e) { //votedown function 72 | this.set('isVoted', true); 73 | var self = this; 74 | $.post('/api/vote.php', {post_id : e}) 75 | .done(function(data){ 76 | if(data == "L") 77 | { 78 | self.set('islg', true); 79 | } 80 | else 81 | { 82 | self.set('votecount', data); 83 | } 84 | }); 85 | console.log(e); 86 | } 87 | } 88 | }); 89 | 90 | App.PostController = Ember.ObjectController.extend({ 91 | voop : false, 92 | islg : false, 93 | actions: { 94 | voteup: function(e) { //vote up fucntion 95 | this.set('uposts.isVoted', false); 96 | var self = this; 97 | $.post('/api/vote.php', {post_id : e}) 98 | .done(function(data){ 99 | if(data == "X") 100 | { 101 | self.set('voop' , true); 102 | } 103 | else if(dara == "L") 104 | { 105 | self.set('islg', true); 106 | } 107 | else 108 | { 109 | self.set('uposts.votecount', data); 110 | } 111 | }); 112 | console.log(e); 113 | }, 114 | 115 | votedown: function(e) { //vote down function 116 | this.set('uposts.isVoted', true); 117 | var self = this; 118 | $.post('/api/vote.php', {post_id : e}) 119 | .done(function(data){ 120 | if(data == "X") 121 | { 122 | self.set('voop' , true); 123 | } 124 | else if(data == "L") 125 | { 126 | self.set('islg', true); 127 | } 128 | else 129 | { 130 | self.set('uposts.votecount', data); 131 | } 132 | }); 133 | console.log(e); 134 | }, 135 | report : function(e){ //report story 136 | $.post('/api/report.php' , {postid : e}) 137 | .done(function(data){ 138 | alert('reported' + data); 139 | }); 140 | }, 141 | 142 | twshare: function(e){ //twitter share 143 | var url = e; 144 | window.location.href = 'http://twitter.com/share?url=http://picnicy.com/p/' + e + '&via=picnicyco&hashtags=tech'; 145 | }, 146 | 147 | fbshare : function(e){ //facebook share 148 | var url = e; 149 | window.location.href = 'https://www.facebook.com/sharer/sharer.php?u=http://picnicy.com/p/' + e; 150 | }, 151 | 152 | submit: function(e){ 153 | var comment = this.get("ncomment"); 154 | var datalink = e; 155 | this.set("ncomment",""); 156 | var self = this; 157 | 158 | $.post('/api/comment.php' , {comment : comment, postid : datalink }) 159 | .done(function(){ 160 | self.send('track'); 161 | }); 162 | } 163 | } 164 | }); 165 | 166 | //Routes 167 | 168 | App.PostRoute = Ember.Route.extend({ //post route 169 | model: function(params) { 170 | return Em.RSVP.hash({ 171 | uposts: $.getJSON('/api/getpost.php' , {postid : params.post_id}), 172 | ustat: $.getJSON('/api/ustatus.php'), 173 | comment : $.getJSON('/api/gc.php', {postid : params.post_id}) 174 | }); 175 | // return posts.findBy('datalink', params.post_id); 176 | }, 177 | actions: { 178 | track: function() { 179 | this.refresh(); 180 | } 181 | } 182 | 183 | 184 | }); 185 | 186 | 187 | 188 | 189 | App.IndexRoute = Ember.Route.extend({ //index route 190 | 191 | model: function(params) { 192 | return Em.RSVP.hash({ 193 | uposts: $.getJSON("/api/indexmaker.php"), 194 | ustat: $.getJSON("/api/ustatus.php") 195 | }); 196 | } 197 | }); 198 | 199 | //Custom text fields 200 | 201 | Ember.TextField.reopen({ //custom text input 202 | attributeBindings: ['required'] 203 | }); 204 | 205 | Ember.LinkView.reopen({ //custom links 206 | attributeBindings: ['class'] 207 | }); 208 | 209 | Ember.TextArea.reopen({ //custom textarea 210 | attributeBindings: ['required' , 'class', 'rows'] 211 | }); 212 | 213 | 214 | //helpers 215 | 216 | Ember.Handlebars.helper('format-date', function(datem) { 217 | return moment(datem, 'X').fromNow(); 218 | }); 219 | 220 | Ember.Handlebars.helper('format-url', function(url) { 221 | pathArray = String(url).split( '/' ); 222 | return pathArray[2]; 223 | }); 224 | 225 | var loading = {"loading":true}; 226 | 227 | 228 | $("img").error(function () { 229 | $(this).unbind("error").attr("src", "http://www.piraten-oberpfalz.de/files/2009/08/orange-twitter-egg.jpg"); 230 | }); 231 | 232 | //The hashbang for better Goolge crawling 233 | 234 | Ember.Location.registerImplementation('hashbang', Ember.HashLocation.extend({ 235 | getURL: function () { 236 | return Ember.get(this, 'location').hash.substr(2); 237 | }, 238 | 239 | setURL: function (path) { 240 | Ember.get(this, 'location').hash = '!' + path; 241 | Ember.set(this, 'lastSetURL', '!' + path); 242 | }, 243 | 244 | onUpdateURL: function (callback) { 245 | var self = this; 246 | var guid = Ember.guidFor(this); 247 | 248 | Ember.$(window).bind('hashchange.ember-location-' + guid, function () { 249 | Ember.run(function() { 250 | var path = location.hash.substr(2); 251 | if (Ember.get(self, 'lastSetURL') === path) { return; } 252 | Ember.set(self, 'lastSetURL', null); 253 | callback(path); 254 | }); 255 | }); 256 | }, 257 | 258 | formatURL: function (url) { 259 | return '#!' + url; 260 | } 261 | })); 262 | 263 | -------------------------------------------------------------------------------- /assets/handlebars-v1.3.0.js: -------------------------------------------------------------------------------- 1 | /*! 2 | 3 | handlebars v1.3.0 4 | 5 | Copyright (C) 2011 by Yehuda Katz 6 | 7 | Permission is hereby granted, free of charge, to any person obtaining a copy 8 | of this software and associated documentation files (the "Software"), to deal 9 | in the Software without restriction, including without limitation the rights 10 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | copies of the Software, and to permit persons to whom the Software is 12 | furnished to do so, subject to the following conditions: 13 | 14 | The above copyright notice and this permission notice shall be included in 15 | all copies or substantial portions of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 23 | THE SOFTWARE. 24 | 25 | @license 26 | */ 27 | /* exported Handlebars */ 28 | var Handlebars = (function() { 29 | // handlebars/safe-string.js 30 | var __module4__ = (function() { 31 | "use strict"; 32 | var __exports__; 33 | // Build out our basic SafeString type 34 | function SafeString(string) { 35 | this.string = string; 36 | } 37 | 38 | SafeString.prototype.toString = function() { 39 | return "" + this.string; 40 | }; 41 | 42 | __exports__ = SafeString; 43 | return __exports__; 44 | })(); 45 | 46 | // handlebars/utils.js 47 | var __module3__ = (function(__dependency1__) { 48 | "use strict"; 49 | var __exports__ = {}; 50 | /*jshint -W004 */ 51 | var SafeString = __dependency1__; 52 | 53 | var escape = { 54 | "&": "&", 55 | "<": "<", 56 | ">": ">", 57 | '"': """, 58 | "'": "'", 59 | "`": "`" 60 | }; 61 | 62 | var badChars = /[&<>"'`]/g; 63 | var possible = /[&<>"'`]/; 64 | 65 | function escapeChar(chr) { 66 | return escape[chr] || "&"; 67 | } 68 | 69 | function extend(obj, value) { 70 | for(var key in value) { 71 | if(Object.prototype.hasOwnProperty.call(value, key)) { 72 | obj[key] = value[key]; 73 | } 74 | } 75 | } 76 | 77 | __exports__.extend = extend;var toString = Object.prototype.toString; 78 | __exports__.toString = toString; 79 | // Sourced from lodash 80 | // https://github.com/bestiejs/lodash/blob/master/LICENSE.txt 81 | var isFunction = function(value) { 82 | return typeof value === 'function'; 83 | }; 84 | // fallback for older versions of Chrome and Safari 85 | if (isFunction(/x/)) { 86 | isFunction = function(value) { 87 | return typeof value === 'function' && toString.call(value) === '[object Function]'; 88 | }; 89 | } 90 | var isFunction; 91 | __exports__.isFunction = isFunction; 92 | var isArray = Array.isArray || function(value) { 93 | return (value && typeof value === 'object') ? toString.call(value) === '[object Array]' : false; 94 | }; 95 | __exports__.isArray = isArray; 96 | 97 | function escapeExpression(string) { 98 | // don't escape SafeStrings, since they're already safe 99 | if (string instanceof SafeString) { 100 | return string.toString(); 101 | } else if (!string && string !== 0) { 102 | return ""; 103 | } 104 | 105 | // Force a string conversion as this will be done by the append regardless and 106 | // the regex test will do this transparently behind the scenes, causing issues if 107 | // an object's to string has escaped characters in it. 108 | string = "" + string; 109 | 110 | if(!possible.test(string)) { return string; } 111 | return string.replace(badChars, escapeChar); 112 | } 113 | 114 | __exports__.escapeExpression = escapeExpression;function isEmpty(value) { 115 | if (!value && value !== 0) { 116 | return true; 117 | } else if (isArray(value) && value.length === 0) { 118 | return true; 119 | } else { 120 | return false; 121 | } 122 | } 123 | 124 | __exports__.isEmpty = isEmpty; 125 | return __exports__; 126 | })(__module4__); 127 | 128 | // handlebars/exception.js 129 | var __module5__ = (function() { 130 | "use strict"; 131 | var __exports__; 132 | 133 | var errorProps = ['description', 'fileName', 'lineNumber', 'message', 'name', 'number', 'stack']; 134 | 135 | function Exception(message, node) { 136 | var line; 137 | if (node && node.firstLine) { 138 | line = node.firstLine; 139 | 140 | message += ' - ' + line + ':' + node.firstColumn; 141 | } 142 | 143 | var tmp = Error.prototype.constructor.call(this, message); 144 | 145 | // Unfortunately errors are not enumerable in Chrome (at least), so `for prop in tmp` doesn't work. 146 | for (var idx = 0; idx < errorProps.length; idx++) { 147 | this[errorProps[idx]] = tmp[errorProps[idx]]; 148 | } 149 | 150 | if (line) { 151 | this.lineNumber = line; 152 | this.column = node.firstColumn; 153 | } 154 | } 155 | 156 | Exception.prototype = new Error(); 157 | 158 | __exports__ = Exception; 159 | return __exports__; 160 | })(); 161 | 162 | // handlebars/base.js 163 | var __module2__ = (function(__dependency1__, __dependency2__) { 164 | "use strict"; 165 | var __exports__ = {}; 166 | var Utils = __dependency1__; 167 | var Exception = __dependency2__; 168 | 169 | var VERSION = "1.3.0"; 170 | __exports__.VERSION = VERSION;var COMPILER_REVISION = 4; 171 | __exports__.COMPILER_REVISION = COMPILER_REVISION; 172 | var REVISION_CHANGES = { 173 | 1: '<= 1.0.rc.2', // 1.0.rc.2 is actually rev2 but doesn't report it 174 | 2: '== 1.0.0-rc.3', 175 | 3: '== 1.0.0-rc.4', 176 | 4: '>= 1.0.0' 177 | }; 178 | __exports__.REVISION_CHANGES = REVISION_CHANGES; 179 | var isArray = Utils.isArray, 180 | isFunction = Utils.isFunction, 181 | toString = Utils.toString, 182 | objectType = '[object Object]'; 183 | 184 | function HandlebarsEnvironment(helpers, partials) { 185 | this.helpers = helpers || {}; 186 | this.partials = partials || {}; 187 | 188 | registerDefaultHelpers(this); 189 | } 190 | 191 | __exports__.HandlebarsEnvironment = HandlebarsEnvironment;HandlebarsEnvironment.prototype = { 192 | constructor: HandlebarsEnvironment, 193 | 194 | logger: logger, 195 | log: log, 196 | 197 | registerHelper: function(name, fn, inverse) { 198 | if (toString.call(name) === objectType) { 199 | if (inverse || fn) { throw new Exception('Arg not supported with multiple helpers'); } 200 | Utils.extend(this.helpers, name); 201 | } else { 202 | if (inverse) { fn.not = inverse; } 203 | this.helpers[name] = fn; 204 | } 205 | }, 206 | 207 | registerPartial: function(name, str) { 208 | if (toString.call(name) === objectType) { 209 | Utils.extend(this.partials, name); 210 | } else { 211 | this.partials[name] = str; 212 | } 213 | } 214 | }; 215 | 216 | function registerDefaultHelpers(instance) { 217 | instance.registerHelper('helperMissing', function(arg) { 218 | if(arguments.length === 2) { 219 | return undefined; 220 | } else { 221 | throw new Exception("Missing helper: '" + arg + "'"); 222 | } 223 | }); 224 | 225 | instance.registerHelper('blockHelperMissing', function(context, options) { 226 | var inverse = options.inverse || function() {}, fn = options.fn; 227 | 228 | if (isFunction(context)) { context = context.call(this); } 229 | 230 | if(context === true) { 231 | return fn(this); 232 | } else if(context === false || context == null) { 233 | return inverse(this); 234 | } else if (isArray(context)) { 235 | if(context.length > 0) { 236 | return instance.helpers.each(context, options); 237 | } else { 238 | return inverse(this); 239 | } 240 | } else { 241 | return fn(context); 242 | } 243 | }); 244 | 245 | instance.registerHelper('each', function(context, options) { 246 | var fn = options.fn, inverse = options.inverse; 247 | var i = 0, ret = "", data; 248 | 249 | if (isFunction(context)) { context = context.call(this); } 250 | 251 | if (options.data) { 252 | data = createFrame(options.data); 253 | } 254 | 255 | if(context && typeof context === 'object') { 256 | if (isArray(context)) { 257 | for(var j = context.length; i