⌈⌋ branch:  freshcode


Hex Artifact Content

Artifact 6b1f3660871e719e17c5368812b0acf81a33567d:

  • File handler_api.php — part of check-in [49047f4b8d] at 2015-04-21 19:52:03 on branch trunk — Return just HTTP 200 status with project:{name:null} on non-existing entries. Alias "hide" and "hidden" fields. (user: mario size: 22962)

0000: 3c 3f 70 68 70 0a 2f 2a 2a 0a 20 2a 20 61 70 69  <?php./**. * api
0010: 3a 20 66 72 65 73 68 63 6f 64 65 0a 20 2a 20 74  : freshcode. * t
0020: 69 74 6c 65 3a 20 53 75 62 6d 69 74 20 41 50 49  itle: Submit API
0030: 0a 20 2a 20 64 65 73 63 72 69 70 74 69 6f 6e 3a  . * description:
0040: 20 49 6d 70 6c 65 6d 65 6e 74 73 20 74 68 65 20   Implements the 
0050: 46 72 65 65 63 6f 64 65 20 4a 53 4f 4e 20 52 65  Freecode JSON Re
0060: 73 74 20 41 50 49 20 66 6f 72 20 72 65 6c 65 61  st API for relea
0070: 73 65 20 75 70 64 61 74 65 73 0a 20 2a 20 76 65  se updates. * ve
0080: 72 73 69 6f 6e 3a 20 30 2e 36 0a 20 2a 20 74 79  rsion: 0.6. * ty
0090: 70 65 3a 20 68 61 6e 64 6c 65 72 0a 20 2a 20 63  pe: handler. * c
00a0: 61 74 65 67 6f 72 79 3a 20 41 50 49 0a 20 2a 20  ategory: API. * 
00b0: 64 6f 63 3a 20 68 74 74 70 3a 2f 2f 66 6f 73 73  doc: http://foss
00c0: 69 6c 2e 69 6e 63 6c 75 64 65 2d 6f 6e 63 65 2e  il.include-once.
00d0: 6f 72 67 2f 66 72 65 73 68 63 6f 64 65 2f 77 69  org/freshcode/wi
00e0: 6b 69 2f 41 50 49 32 0a 20 2a 20 61 75 74 68 6f  ki/API2. * autho
00f0: 72 3a 20 6d 61 72 69 6f 0a 20 2a 20 6c 69 63 65  r: mario. * lice
0100: 6e 73 65 3a 20 41 47 50 4c 0a 20 2a 0a 20 2a 20  nse: AGPL. *. * 
0110: 54 68 69 73 20 75 74 69 6c 69 74 79 20 63 6f 64  This utility cod
0120: 65 20 70 72 6f 76 69 64 65 73 20 61 20 70 72 6f  e provides a pro
0130: 6a 65 63 74 2b 72 65 6c 65 61 73 65 20 73 75 62  ject+release sub
0140: 6d 69 73 73 69 6f 6e 20 41 50 49 20 66 6f 72 0a  mission API for.
0150: 20 2a 20 66 72 65 65 63 6f 64 65 2d 73 75 62 6d   * freecode-subm
0160: 69 74 20 61 6e 64 20 73 69 6d 69 6c 61 72 20 74  it and similar t
0170: 6f 6f 6c 73 2e 20 54 68 65 20 62 61 73 65 20 66  ools. The base f
0180: 65 61 74 75 72 65 73 20 66 69 74 20 77 65 6c 6c  eatures fit well
0190: 20 77 69 74 68 0a 20 2a 20 74 68 65 20 66 72 65   with. * the fre
01a0: 73 68 63 6f 64 65 2e 63 6c 75 62 20 64 61 74 61  shcode.club data
01b0: 62 61 73 65 20 73 63 68 65 6d 65 2e 20 49 74 20  base scheme. It 
01c0: 68 61 73 20 62 65 65 6e 20 73 69 6d 70 6c 69 66  has been simplif
01d0: 69 65 64 20 74 6f 0a 20 2a 20 61 6c 6c 6f 77 20  ied to. * allow 
01e0: 6d 6f 72 65 20 6c 69 74 65 72 61 6c 20 61 63 63  more literal acc
01f0: 65 73 73 20 61 6e 64 20 63 6f 6e 74 72 6f 6c 2e  ess and control.
0200: 0a 20 2a 0a 20 2a 20 4f 75 72 20 52 65 77 72 69  . *. * Our Rewri
0210: 74 65 52 75 6c 65 73 20 6d 61 70 20 66 6f 6c 6c  teRules map foll
0220: 6f 77 69 6e 67 20 72 65 71 75 65 73 74 20 73 63  owing request sc
0230: 68 65 6d 65 73 3a 0a 20 2a 0a 20 2a 20 20 20 20  hemes:. *. *    
0240: 20 20 20 47 45 54 20 20 20 70 72 6f 6a 65 63 74     GET   project
0250: 73 2f 3c 6e 61 6d 65 3e 2e 6a 73 6f 6e 20 20 20  s/<name>.json   
0260: 20 20 20 20 20 20 20 20 20 20 20 20 20 71 75 65               que
0270: 72 79 0a 20 2a 20 20 20 20 43 52 45 41 54 45 20  ry. *    CREATE 
0280: 20 20 70 72 6f 6a 65 63 74 73 2f 3c 6e 61 6d 65    projects/<name
0290: 3e 2e 6a 73 6f 6e 20 20 20 20 20 20 20 20 20 20  >.json          
02a0: 20 20 20 20 20 20 6e 65 77 5f 70 72 6f 6a 65 63        new_projec
02b0: 74 0a 20 2a 20 20 20 20 20 20 20 50 55 54 20 20  t. *       PUT  
02c0: 20 70 72 6f 6a 65 63 74 73 2f 3c 6e 61 6d 65 3e   projects/<name>
02d0: 2e 6a 73 6f 6e 20 20 20 20 20 20 20 20 20 20 20  .json           
02e0: 20 20 20 20 20 75 70 64 61 74 65 5f 63 6f 72 65       update_core
02f0: 0a 20 2a 20 20 20 20 20 20 50 4f 53 54 20 20 20  . *      POST   
0300: 70 72 6f 6a 65 63 74 73 2f 3c 6e 61 6d 65 3e 2f  projects/<name>/
0310: 72 65 6c 65 61 73 65 73 2e 6a 73 6f 6e 20 20 20  releases.json   
0320: 20 20 20 20 28 72 65 64 75 6e 64 61 6e 74 29 0a      (redundant).
0330: 20 2a 20 20 20 20 20 20 20 50 55 54 20 20 20 70   *       PUT   p
0340: 72 6f 6a 65 63 74 73 2f 3c 6e 61 6d 65 3e 2f 75  rojects/<name>/u
0350: 72 6c 73 2e 6a 73 6f 6e 20 20 20 20 20 20 20 20  rls.json        
0360: 20 20 20 28 72 65 64 75 6e 64 61 6e 74 29 0a 20     (redundant). 
0370: 2a 20 20 20 20 44 45 4c 45 54 45 20 20 20 70 72  *    DELETE   pr
0380: 6f 6a 65 63 74 73 2f 3c 6e 61 6d 65 3e 2f 72 65  ojects/<name>/re
0390: 6c 65 61 73 65 73 2f 3c 76 73 3e 2e 6a 73 6f 6e  leases/<vs>.json
03a0: 20 20 76 65 72 73 69 6f 6e 5f 44 45 4c 45 54 45    version_DELETE
03b0: 0a 20 2a 20 20 20 20 20 20 20 47 45 54 20 20 20  . *       GET   
03c0: 66 65 65 64 2f 3c 6e 61 6d 65 3e 2e 6a 73 6f 6e  feed/<name>.json
03d0: 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20                  
03e0: 20 20 20 20 65 78 74 65 72 6e 61 6c 20 28 64 61      external (da
03f0: 74 61 20 66 65 64 65 72 61 74 69 6f 6e 29 0a 20  ta federation). 
0400: 2a 0a 20 2a 20 41 6c 6c 20 72 65 71 75 65 73 74  *. * All request
0410: 73 20 73 68 6f 75 6c 64 20 62 65 20 73 65 6e 74  s should be sent
0420: 20 6f 6e 74 6f 20 60 68 74 74 70 73 3a 2f 2f 61   onto `https://a
0430: 70 69 20 2e 66 72 65 73 68 63 6f 64 65 2e 63 6c  pi .freshcode.cl
0440: 75 62 2f 2e 2e 2e 60 2c 0a 20 2a 20 77 68 65 72  ub/...`,. * wher
0450: 65 20 6f 6e 6c 79 20 43 52 45 41 54 45 20 72 65  e only CREATE re
0460: 71 75 69 72 65 73 20 61 20 63 6c 69 65 6e 74 20  quires a client 
0470: 53 53 4c 20 63 65 72 74 2c 20 73 65 65 20 60 73  SSL cert, see `s
0480: 75 62 6d 69 74 2e 70 65 6d 60 2e 0a 20 2a 0a 20  ubmit.pem`.. *. 
0490: 2a 20 52 65 74 72 69 65 76 61 6c 20 72 65 71 75  * Retrieval requ
04a0: 65 73 74 73 20 75 73 75 61 6c 6c 79 20 63 6f 6d  ests usually com
04b0: 65 20 77 69 74 68 20 61 6e 20 3f 61 75 74 68 5f  e with an ?auth_
04c0: 63 6f 64 65 3d 20 74 6f 6b 65 6e 2e 20 46 6f 72  code= token. For
04d0: 20 50 4f 53 54 0a 20 2a 20 6f 72 20 50 55 54 20   POST. * or PUT 
04e0: 61 63 63 65 73 73 20 69 74 27 73 20 70 61 72 74  access it's part
04f0: 20 6f 66 20 74 68 65 20 4a 53 4f 4e 20 72 65 71   of the JSON req
0500: 75 65 73 74 20 62 6f 64 79 2e 20 57 68 69 63 68  uest body. Which
0510: 20 63 61 6e 20 68 61 76 65 0a 20 2a 20 76 61 72   can have. * var
0520: 79 69 6e 67 20 70 61 79 6c 6f 61 64 73 20 64 65  ying payloads de
0530: 70 65 6e 64 69 6e 67 20 6f 6e 20 72 65 71 75 65  pending on reque
0540: 73 74 20 74 79 70 65 3a 0a 20 2a 0a 20 2a 20 20  st type:. *. *  
0550: 20 7b 0a 20 2a 20 20 20 20 20 22 61 75 74 68 5f   {. *     "auth_
0560: 63 6f 64 65 22 3a 20 22 70 77 31 32 33 22 2c 0a  code": "pw123",.
0570: 20 2a 20 20 20 20 20 22 70 72 6f 6a 65 63 74 22   *     "project"
0580: 3a 20 7b 0a 20 2a 20 20 20 20 20 20 20 22 6c 69  : {. *       "li
0590: 63 65 6e 73 65 5f 6c 69 73 74 22 3a 20 22 47 4e  cense_list": "GN
05a0: 55 20 47 50 4c 22 2c 0a 20 2a 20 20 20 20 20 20  U GPL",. *      
05b0: 20 22 70 72 6f 6a 65 63 74 5f 74 61 67 73 22 3a   "project_tags":
05c0: 20 22 6b 65 72 6e 65 6c 2c 6f 70 65 72 61 74 69   "kernel,operati
05d0: 6e 67 2d 73 79 73 74 65 6d 22 2c 0a 20 2a 20 20  ng-system",. *  
05e0: 20 20 20 20 20 22 73 75 6d 6d 61 72 79 22 3a 20       "summary": 
05f0: 22 4c 69 6e 75 78 20 6b 65 72 6e 65 6c 20 64 65  "Linux kernel de
0600: 73 63 22 2c 0a 20 2a 20 20 20 20 20 20 20 22 64  sc",. *       "d
0610: 65 73 63 72 69 70 74 69 6f 6e 22 3a 20 22 44 6f  escription": "Do
0620: 65 73 20 74 68 69 73 20 61 6e 64 20 74 68 61 74  es this and that
0630: 2e 2e 22 0a 20 2a 20 20 20 20 20 7d 2c 0a 20 2a  ..". *     },. *
0640: 20 20 20 20 20 22 75 72 6c 73 22 3a 20 7b 0a 20       "urls": {. 
0650: 2a 20 20 20 20 20 20 20 22 68 6f 6d 65 70 61 67  *       "homepag
0660: 65 22 3a 20 22 68 74 74 70 3a 2f 2f 65 78 61 6d  e": "http://exam
0670: 70 6c 65 2e 6f 72 67 2f 22 2c 0a 20 2a 20 20 20  ple.org/",. *   
0680: 20 20 20 20 22 68 67 2d 72 65 70 6f 22 3a 20 22      "hg-repo": "
0690: 68 74 74 70 3a 2f 2f 68 67 2e 65 78 61 6d 70 6c  http://hg.exampl
06a0: 65 2e 6f 72 67 2f 22 2c 0a 20 2a 20 20 20 20 20  e.org/",. *     
06b0: 7d 0a 20 2a 20 20 20 20 20 22 72 65 6c 65 61 73  }. *     "releas
06c0: 65 22 3a 20 7b 0a 20 2a 20 20 20 20 20 20 20 22  e": {. *       "
06d0: 76 65 72 73 69 6f 6e 22 3a 20 22 34 2e 30 2e 30  version": "4.0.0
06e0: 22 2c 0a 20 2a 20 20 20 20 20 20 20 22 63 68 61  ",. *       "cha
06f0: 6e 67 65 73 22 3a 20 22 42 75 67 66 69 78 20 66  nges": "Bugfix f
0700: 6f 72 20 66 6f 6f 20 61 6e 64 20 62 61 72 2e 22  or foo and bar."
0710: 0a 20 2a 20 20 20 20 20 7d 0a 20 2a 20 20 20 7d  . *     }. *   }
0720: 0a 20 2a 0a 20 2a 20 41 6e 79 20 63 72 79 70 74  . *. * Any crypt
0730: 28 33 29 20 70 61 73 73 77 6f 72 64 20 68 61 73  (3) password has
0740: 68 20 69 6e 20 61 20 70 72 6f 6a 65 63 74 73 20  h in a projects 
0750: 60 6c 6f 63 6b 60 20 66 69 65 6c 64 20 77 69 6c  `lock` field wil
0760: 6c 20 62 65 20 63 68 65 63 6b 65 64 0a 20 2a 20  l be checked. * 
0770: 61 67 61 69 6e 73 74 20 74 68 65 20 70 6c 61 69  against the plai
0780: 6e 20 60 61 75 74 68 5f 63 6f 64 65 60 2e 0a 20  n `auth_code`.. 
0790: 2a 20 57 68 65 6e 20 43 52 45 41 54 45 69 6e 67  * When CREATEing
07a0: 20 61 20 6e 65 77 20 70 72 6f 6a 65 63 74 2c 20   a new project, 
07b0: 74 68 65 20 61 75 74 68 5f 63 6f 64 65 20 77 69  the auth_code wi
07c0: 6c 6c 20 62 65 20 73 74 6f 72 65 64 20 61 73 20  ll be stored as 
07d0: 68 61 73 68 2e 0a 20 2a 0a 20 2a 20 41 74 20 74  hash.. *. * At t
07e0: 68 69 73 20 70 6f 69 6e 74 20 65 76 65 72 79 74  his point everyt
07f0: 68 69 6e 67 20 77 65 6e 74 20 74 68 72 6f 75 67  hing went throug
0800: 68 20 69 6e 64 65 78 2e 70 68 70 20 61 6c 72 65  h index.php alre
0810: 61 64 79 3b 20 72 75 6e 74 69 6d 65 20 65 6e 76  ady; runtime env
0820: 0a 20 2a 20 74 68 75 73 20 69 6e 69 74 69 61 6c  . * thus initial
0830: 69 7a 65 64 2e 20 54 68 65 72 65 66 6f 72 65 20  ized. Therefore 
0840: 41 50 49 20 6d 65 74 68 6f 64 73 20 63 61 6e 20  API methods can 
0850: 62 65 20 69 6e 76 6f 6b 65 64 20 64 69 72 65 63  be invoked direc
0860: 74 6c 79 2c 20 77 68 69 63 68 0a 20 2a 20 65 69  tly, which. * ei
0870: 74 68 65 72 20 72 65 74 72 69 65 76 65 20 6f 72  ther retrieve or
0880: 20 73 74 6f 72 65 20 70 72 6f 6a 65 63 74 20 64   store project d
0890: 61 74 61 2c 20 61 6e 64 20 70 72 65 70 61 72 65  ata, and prepare
08a0: 20 61 20 4a 53 4f 4e 20 72 65 73 70 6f 6e 73 65   a JSON response
08b0: 2e 0a 20 2a 0a 20 2a 2f 0a 0a 23 69 66 64 65 66  .. *. */..#ifdef
08c0: 20 54 45 53 54 49 4e 47 5f 4f 4e 4c 59 20 23 23   TESTING_ONLY ##
08d0: 23 23 23 0a 64 62 28 6e 65 77 20 50 44 4f 28 22  ###.db(new PDO("
08e0: 73 71 6c 69 74 65 3a 2e 2f 74 65 73 74 2e 64 62  sqlite:./test.db
08f0: 22 29 29 3b 20 20 20 2f 2f 40 54 4f 44 4f 3a 20  "));   //@TODO: 
0900: 50 72 65 73 65 74 20 69 6e 20 60 63 6f 6e 66 69  Preset in `confi
0910: 67 2e 6c 6f 63 61 6c 2e 70 68 70 60 20 66 6f 72  g.local.php` for
0920: 20 68 74 74 70 3a 2f 2f 61 70 69 2e 20 61 6e 64   http://api. and
0930: 20 68 74 74 70 3a 2f 2f 74 65 73 74 2e 0a 23 65   http://test..#e
0940: 6e 64 69 66 20 23 23 23 23 23 23 23 23 23 23 23  ndif ###########
0950: 23 23 23 23 23 23 23 0a 0a 0a 2f 2a 0a 20 40 54  #######.../*. @T
0960: 65 73 74 20 40 73 68 0a 0a 20 40 74 20 71 75 65  est @sh.. @t que
0970: 72 79 0a 20 20 20 77 67 65 74 20 68 74 74 70 3a  ry.   wget http:
0980: 2f 2f 66 72 65 73 68 63 6f 64 65 2f 70 72 6f 6a  //freshcode/proj
0990: 65 63 74 73 2f 6c 69 6e 75 78 2e 6a 73 6f 6e 3f  ects/linux.json?
09a0: 61 75 74 68 5f 63 6f 64 65 3d 75 6e 75 73 65 64  auth_code=unused
09b0: 20 2d 4f 2d 0a 20 20 20 2e 2f 66 63 2d 73 75 62   -O-.   ./fc-sub
09c0: 6d 69 74 20 2d 71 20 6c 69 6e 75 78 0a 0a 20 40  mit -q linux.. @
09d0: 74 20 63 68 61 6e 67 65 5f 63 6f 72 65 0a 20 20  t change_core.  
09e0: 20 2e 2f 66 63 2d 73 75 62 6d 69 74 20 2d 50 20   ./fc-submit -P 
09f0: 6c 69 6e 75 78 20 2d 44 20 22 6e 65 77 20 70 72  linux -D "new pr
0a00: 6f 6a 22 20 2d 53 20 22 6f 6e 65 6c 69 6e 65 72  oj" -S "oneliner
0a10: 22 20 2d 4c 20 22 47 4e 55 20 47 50 4c 22 20 2d  " -L "GNU GPL" -
0a20: 54 20 22 6b 65 72 6e 65 6c 2c 6c 69 6e 75 78 22  T "kernel,linux"
0a30: 20 2d 6e 20 2d 56 0a 0a 20 40 74 20 70 75 62 6c   -n -V.. @t publ
0a40: 69 73 68 0a 20 20 20 2e 2f 66 63 2d 73 75 62 6d  ish.   ./fc-subm
0a50: 69 74 20 2d 50 20 6c 69 6e 75 78 20 2d 76 20 22  it -P linux -v "
0a60: 33 2e 35 35 2e 31 22 20 2d 63 20 22 43 68 61 6e  3.55.1" -c "Chan
0a70: 67 65 20 61 6c 6c 20 74 68 65 20 74 68 69 6e 67  ge all the thing
0a80: 73 22 20 2d 74 20 22 6d 61 6a 6f 72 2c 62 75 67  s" -t "major,bug
0a90: 66 69 78 22 20 2d 6e 20 2d 56 0a 0a 20 40 74 20  fix" -n -V.. @t 
0aa0: 64 65 6c 65 74 65 0a 20 20 20 2e 2f 66 63 2d 73  delete.   ./fc-s
0ab0: 75 62 6d 69 74 20 2d 50 20 6c 69 6e 75 78 20 2d  ubmit -P linux -
0ac0: 76 20 22 33 2e 35 35 2e 31 22 20 2d 64 20 2d 6e  v "3.55.1" -d -n
0ad0: 20 2d 56 0a 0a 20 40 74 20 75 72 6c 73 0a 20 20   -V.. @t urls.  
0ae0: 20 77 67 65 74 20 68 74 74 70 3a 2f 2f 66 72 65   wget http://fre
0af0: 73 68 63 6f 64 65 2f 70 72 6f 6a 65 63 74 73 2f  shcode/projects/
0b00: 6c 69 6e 75 78 2f 75 72 6c 73 2e 6a 73 6f 6e 3f  linux/urls.json?
0b10: 61 75 74 68 5f 63 6f 64 65 3d 30 20 2d 4f 2d 0a  auth_code=0 -O-.
0b20: 2a 2f 0a 0a 0a 0a 2f 2f 20 57 72 61 70 73 20 41  */....// Wraps A
0b30: 50 49 20 6d 65 74 68 6f 64 73 20 61 6e 64 20 75  PI methods and u
0b40: 74 69 6c 69 74 79 20 63 6f 64 65 0a 63 6c 61 73  tility code.clas
0b50: 73 20 46 72 65 65 43 6f 64 65 5f 41 50 49 20 7b  s FreeCode_API {
0b60: 0a 0a 0a 20 20 20 20 2f 2f 20 48 54 54 50 20 6d  ...    // HTTP m
0b70: 65 74 68 6f 64 0a 20 20 20 20 76 61 72 20 24 6d  ethod.    var $m
0b80: 65 74 68 6f 64 3b 0a 0a 20 20 20 20 2f 2f 20 41  ethod;..    // A
0b90: 50 49 20 66 75 6e 63 74 69 6f 6e 0a 20 20 20 20  PI function.    
0ba0: 76 61 72 20 24 61 70 69 3b 0a 0a 20 20 20 20 2f  var $api;..    /
0bb0: 2f 20 50 72 6f 6a 65 63 74 20 6e 61 6d 65 0a 20  / Project name. 
0bc0: 20 20 20 76 61 72 20 24 6e 61 6d 65 3b 0a 0a 20     var $name;.. 
0bd0: 20 20 20 2f 2f 20 4f 70 74 69 6f 6e 61 6c 20 72     // Optional r
0be0: 65 76 69 73 69 6f 6e 20 49 44 20 28 6a 75 73 74  evision ID (just
0bf0: 20 75 73 65 64 20 66 6f 72 20 72 65 6c 65 61 73   used for releas
0c00: 65 73 2f 3b 20 65 69 74 68 65 72 20 22 70 65 6e  es/; either "pen
0c10: 64 69 6e 67 22 20 6f 72 20 74 5f 70 75 62 6c 69  ding" or t_publi
0c20: 73 68 65 64 20 74 69 6d 65 73 74 61 6d 70 29 20  shed timestamp) 
0c30: 0a 20 20 20 20 76 61 72 20 24 72 65 76 3b 0a 20  .    var $rev;. 
0c40: 20 20 20 0a 20 20 20 20 2f 2f 20 69 6e 6e 65 72     .    // inner
0c50: 20 40 61 72 72 61 79 20 66 72 6f 6d 20 4a 53 4f   @array from JSO
0c60: 4e 20 72 65 71 75 65 73 74 20 62 6f 64 79 0a 20  N request body. 
0c70: 20 20 20 76 61 72 20 24 62 6f 64 79 3b 0a 20 20     var $body;.  
0c80: 20 20 0a 20 20 20 20 2f 2f 20 4f 70 74 69 6f 6e    .    // Option
0c90: 61 6c 20 61 75 74 68 5f 63 6f 64 65 20 28 66 72  al auth_code (fr
0ca0: 6f 6d 20 55 52 4c 20 6f 72 20 4a 53 4f 4e 20 62  om URL or JSON b
0cb0: 6f 64 79 29 0a 20 20 20 20 76 61 72 20 24 61 75  ody).    var $au
0cc0: 74 68 5f 63 6f 64 65 3b 0a 20 20 20 20 0a 20 20  th_code;.    .  
0cd0: 20 20 0a 20 20 20 20 2f 2f 20 4c 6f 67 67 69 6e    .    // Loggin
0ce0: 67 0a 20 20 20 20 76 61 72 20 24 6c 6f 67 20 3d  g.    var $log =
0cf0: 20 54 52 55 45 3b 0a 20 20 20 20 76 61 72 20 24   TRUE;.    var $
0d00: 74 69 6d 65 73 74 61 6d 70 20 3d 20 30 3b 0a 0a  timestamp = 0;..
0d10: 20 20 20 20 2f 2f 20 64 65 66 61 75 6c 74 73 0a      // defaults.
0d20: 20 20 20 20 63 6f 6e 73 74 20 45 44 49 54 4f 52      const EDITOR
0d30: 5f 4e 4f 54 45 20 3d 20 22 53 75 62 6d 69 74 74  _NOTE = "Submitt
0d40: 65 64 20 76 69 61 20 41 50 49 2e 20 59 6f 75 20  ed via API. You 
0d50: 63 61 6e 20 61 64 64 20 61 6e 20 65 78 74 72 61  can add an extra
0d60: 20 4f 70 65 6e 49 44 20 68 61 6e 64 6c 65 20 6f   OpenID handle o
0d70: 72 20 66 75 72 74 68 65 72 20 70 61 73 73 77 6f  r further passwo
0d80: 72 64 73 2c 20 62 79 20 72 65 76 69 73 69 74 69  rds, by revisiti
0d90: 6e 67 20 74 68 65 20 2f 6c 6f 67 69 6e 2c 20 61  ng the /login, a
0da0: 6e 64 20 72 65 61 70 70 6c 79 69 6e 67 20 74 68  nd reapplying th
0db0: 65 20 60 6c 6f 63 6b 60 20 28 67 72 65 65 6e 20  e `lock` (green 
0dc0: 61 63 74 69 6f 6e 20 6c 69 6e 6b 29 20 62 65 6c  action link) bel
0dd0: 6f 77 2e 22 3b 0a 0a 0a 0a 20 20 20 20 2f 2a 2a  ow.";....    /**
0de0: 0a 20 20 20 20 20 2a 20 49 6e 69 74 69 61 6c 69  .     * Initiali
0df0: 7a 65 20 70 61 72 61 6d 73 20 66 72 6f 6d 20 52  ze params from R
0e00: 65 77 72 69 74 65 52 75 6c 65 20 61 72 67 73 2e  ewriteRule args.
0e10: 0a 20 20 20 20 20 2a 0a 20 20 20 20 20 2a 2f 0a  .     *.     */.
0e20: 20 20 20 20 66 75 6e 63 74 69 6f 6e 20 5f 5f 63      function __c
0e30: 6f 6e 73 74 72 75 63 74 28 29 20 7b 0a 20 20 20  onstruct() {.   
0e40: 20 0a 20 20 20 20 20 20 20 20 2f 2f 20 55 52 4c   .        // URL
0e50: 20 70 61 72 61 6d 73 0a 20 20 20 20 20 20 20 20   params.        
0e60: 24 74 68 69 73 2d 3e 6e 61 6d 65 20 3d 20 24 5f  $this->name = $_
0e70: 47 45 54 2d 3e 70 72 6f 6a 5f 6e 61 6d 65 5b 22  GET->proj_name["
0e80: 6e 61 6d 65 22 5d 3b 0a 20 20 20 20 20 20 20 20  name"];.        
0e90: 24 74 68 69 73 2d 3e 61 70 69 20 3d 20 24 5f 47  $this->api = $_G
0ea0: 45 54 2d 3e 69 64 2d 3e 73 74 72 74 6f 6c 6f 77  ET->id->strtolow
0eb0: 65 72 2d 3e 69 6e 5f 61 72 72 61 79 28 22 61 70  er->in_array("ap
0ec0: 69 22 2c 20 22 71 75 65 72 79 2c 75 70 64 61 74  i", "query,updat
0ed0: 65 5f 63 6f 72 65 2c 6e 65 77 5f 70 72 6f 6a 65  e_core,new_proje
0ee0: 63 74 2c 70 75 62 6c 69 73 68 2c 75 72 6c 73 2c  ct,publish,urls,
0ef0: 76 65 72 73 69 6f 6e 5f 67 65 74 2c 76 65 72 73  version_get,vers
0f00: 69 6f 6e 5f 64 65 6c 65 74 65 22 29 3b 0a 20 20  ion_delete");.  
0f10: 20 20 20 20 20 20 24 74 68 69 73 2d 3e 6d 65 74        $this->met
0f20: 68 6f 64 20 3d 20 24 5f 53 45 52 56 45 52 2d 3e  hod = $_SERVER->
0f30: 69 64 2d 3e 73 74 72 74 6f 75 70 70 65 72 5b 22  id->strtoupper["
0f40: 52 45 51 55 45 53 54 5f 4d 45 54 48 4f 44 22 5d  REQUEST_METHOD"]
0f50: 3b 0a 20 20 20 20 20 20 20 20 24 74 68 69 73 2d  ;.        $this-
0f60: 3e 61 75 74 68 5f 63 6f 64 65 20 3d 20 24 5f 52  >auth_code = $_R
0f70: 45 51 55 45 53 54 2d 3e 74 65 78 74 5b 22 61 75  EQUEST->text["au
0f80: 74 68 5f 63 6f 64 65 22 5d 3b 0a 20 20 20 20 20  th_code"];.     
0f90: 20 20 20 24 74 68 69 73 2d 3e 72 65 76 20 3d 20     $this->rev = 
0fa0: 24 5f 52 45 51 55 45 53 54 2d 3e 74 65 78 74 5b  $_REQUEST->text[
0fb0: 22 69 64 22 5d 3b 20 20 2f 2f 20 6f 70 74 69 6f  "id"];  // optio
0fc0: 6e 61 6c 20 70 61 72 61 6d 2c 20 6e 6f 77 20 6c  nal param, now l
0fd0: 69 74 65 72 61 6c 20 60 76 65 72 73 69 6f 6e 60  iteral `version`
0fe0: 20 73 74 72 69 6e 67 0a 20 20 20 20 20 20 20 20   string.        
0ff0: 0a 20 20 20 20 20 20 20 20 2f 2f 20 52 65 71 75  .        // Requ
1000: 65 73 74 20 62 6f 64 79 20 69 73 20 6f 6e 6c 79  est body is only
1010: 20 63 6f 70 69 65 64 2c 20 62 65 63 61 75 73 65   copied, because
1020: 20 69 74 20 63 6f 6d 65 73 20 77 69 74 68 20 76   it comes with v
1030: 61 72 79 69 6e 67 20 70 61 79 6c 6f 61 64 73 20  arying payloads 
1040: 28 72 65 6c 65 61 73 65 2c 20 70 72 6f 6a 65 63  (release, projec
1050: 74 2c 20 75 72 6c 73 29 0a 20 20 20 20 20 20 20  t, urls).       
1060: 20 69 66 20 28 24 5f 53 45 52 56 45 52 2d 3e 69   if ($_SERVER->i
1070: 6e 74 5b 22 43 4f 4e 54 45 4e 54 5f 4c 45 4e 47  nt["CONTENT_LENG
1080: 54 48 22 5d 20 26 26 20 24 5f 53 45 52 56 45 52  TH"] && $_SERVER
1090: 2d 3e 73 74 72 69 70 6f 73 e2 80 a6 6a 73 6f 6e  ->stripos...json
10a0: 2d 3e 69 73 5f 69 6e 74 5b 22 43 4f 4e 54 45 4e  ->is_int["CONTEN
10b0: 54 5f 54 59 50 45 22 5d 29 20 7b 0a 20 20 20 20  T_TYPE"]) {.    
10c0: 20 20 20 20 20 20 20 20 24 74 68 69 73 2d 3e 62          $this->b
10d0: 6f 64 79 20 3d 20 6a 73 6f 6e 5f 64 65 63 6f 64  ody = json_decod
10e0: 65 28 66 69 6c 65 5f 67 65 74 5f 63 6f 6e 74 65  e(file_get_conte
10f0: 6e 74 73 28 22 70 68 70 3a 2f 2f 69 6e 70 75 74  nts("php://input
1100: 22 29 2c 20 54 52 55 45 29 3b 0a 20 20 20 20 20  "), TRUE);.     
1110: 20 20 20 20 20 20 20 24 74 68 69 73 2d 3e 61 75         $this->au
1120: 74 68 5f 63 6f 64 65 20 3d 20 24 74 68 69 73 2d  th_code = $this-
1130: 3e 62 6f 64 79 5b 22 61 75 74 68 5f 63 6f 64 65  >body["auth_code
1140: 22 5d 3b 0a 20 20 20 20 20 20 20 20 7d 0a 20 20  "];.        }.  
1150: 20 20 20 20 20 20 0a 20 20 20 20 20 20 20 20 2f        .        /
1160: 2f 20 4c 6f 67 67 69 6e 67 0a 20 20 20 20 20 20  / Logging.      
1170: 20 20 24 74 68 69 73 2d 3e 74 69 6d 65 73 74 61    $this->timesta
1180: 6d 70 20 3d 20 73 70 72 69 6e 74 66 28 22 25 73  mp = sprintf("%s
1190: 20 28 25 73 29 22 2c 20 74 69 6d 65 28 29 2c 20   (%s)", time(), 
11a0: 67 6d 64 61 74 65 28 44 41 54 45 5f 49 53 4f 38  gmdate(DATE_ISO8
11b0: 36 30 31 2c 20 74 69 6d 65 28 29 29 29 3b 0a 20  601, time()));. 
11c0: 20 20 20 20 20 20 20 24 74 68 69 73 2d 3e 6c 6f         $this->lo
11d0: 67 28 24 74 68 69 73 2c 20 22 5c 6e 5c 6e 5c 6e  g($this, "\n\n\n
11e0: 2f 2a 20 3c 3c 20 52 45 51 55 45 53 54 20 2a 2f  /* << REQUEST */
11f0: 22 29 3b 0a 20 20 20 20 20 20 20 20 2f 2f 20 54  ");.        // T
1200: 65 73 74 69 6e 67 0a 20 20 20 20 20 20 20 20 73  esting.        s
1210: 65 74 5f 65 72 72 6f 72 5f 68 61 6e 64 6c 65 72  et_error_handler
1220: 28 66 75 6e 63 74 69 6f 6e 28 24 65 72 72 6e 6f  (function($errno
1230: 2c 20 24 73 74 72 2c 20 24 66 6e 2c 20 24 6c 69  , $str, $fn, $li
1240: 6e 65 2c 20 24 63 74 78 29 20 7b 0a 20 20 20 20  ne, $ctx) {.    
1250: 20 20 20 20 20 20 20 20 24 74 68 69 73 2d 3e 6c          $this->l
1260: 6f 67 28 22 22 2c 20 22 23 23 23 20 52 75 6e 74  og("", "### Runt
1270: 69 6d 65 20 57 61 72 6e 69 6e 67 20 5b 24 65 72  ime Warning [$er
1280: 72 6e 6f 5d 3a 20 24 73 74 72 20 28 24 66 6e 3a  rno]: $str ($fn:
1290: 24 6c 69 6e 65 29 20 23 23 23 22 29 3b 0a 20 20  $line) ###");.  
12a0: 20 20 20 20 20 20 7d 29 3b 0a 20 20 20 20 7d 0a        });.    }.
12b0: 20 20 20 20 0a 20 20 20 20 0a 20 20 20 20 2f 2a      .    .    /*
12c0: 2a 0a 20 20 20 20 20 2a 20 4c 6f 67 20 69 6e 63  *.     * Log inc
12d0: 6f 6d 69 6e 67 20 72 65 71 75 65 73 74 2c 20 6f  oming request, o
12e0: 75 74 67 6f 69 6e 67 20 72 65 73 70 6f 6e 73 65  utgoing response
12f0: 2c 20 6f 72 20 64 61 74 61 20 73 65 74 20 61 73  , or data set as
1300: 20 70 72 65 70 61 72 65 64 20 70 72 69 6f 72 20   prepared prior 
1310: 75 70 64 61 74 69 6e 67 20 44 42 2e 0a 20 20 20  updating DB..   
1320: 20 20 2a 0a 20 20 20 20 20 2a 2f 0a 20 20 20 20    *.     */.    
1330: 66 75 6e 63 74 69 6f 6e 20 6c 6f 67 28 24 77 68  function log($wh
1340: 61 74 2c 20 24 70 72 65 66 69 78 29 20 7b 0a 20  at, $prefix) {. 
1350: 20 20 20 20 20 20 20 69 66 20 28 24 74 68 69 73         if ($this
1360: 2d 3e 6c 6f 67 29 20 7b 0a 20 20 20 20 20 20 20  ->log) {.       
1370: 20 20 20 20 20 66 69 6c 65 5f 70 75 74 5f 63 6f       file_put_co
1380: 6e 74 65 6e 74 73 28 22 61 70 69 2d 6c 6f 67 2e  ntents("api-log.
1390: 74 78 74 22 2c 20 22 24 70 72 65 66 69 78 5c 6e  txt", "$prefix\n
13a0: 22 20 2e 20 6a 73 6f 6e 5f 65 6e 63 6f 64 65 28  " . json_encode(
13b0: 24 77 68 61 74 2c 20 4a 53 4f 4e 5f 50 52 45 54  $what, JSON_PRET
13c0: 54 59 5f 50 52 49 4e 54 20 7c 20 4a 53 4f 4e 5f  TY_PRINT | JSON_
13d0: 55 4e 45 53 43 41 50 45 44 5f 53 4c 41 53 48 45  UNESCAPED_SLASHE
13e0: 53 29 20 2e 20 22 5c 6e 22 2c 20 46 49 4c 45 5f  S) . "\n", FILE_
13f0: 41 50 50 45 4e 44 29 3b 0a 20 20 20 20 20 20 20  APPEND);.       
1400: 20 7d 0a 20 20 20 20 20 20 20 20 72 65 74 75 72   }.        retur
1410: 6e 20 24 77 68 61 74 3b 0a 20 20 20 20 7d 0a 0a  n $what;.    }..
1420: 0a 20 20 20 20 0a 20 20 20 20 2f 2a 2a 0a 20 20  .    .    /**.  
1430: 20 20 20 2a 20 49 6e 76 6f 6b 65 20 41 50 49 20     * Invoke API 
1440: 74 61 72 67 65 74 20 66 75 6e 63 74 69 6f 6e 2e  target function.
1450: 0a 20 20 20 20 20 2a 20 41 66 74 65 72 20 72 65  .     * After re
1460: 74 72 69 65 76 69 6e 67 20 63 75 72 72 65 6e 74  trieving current
1470: 20 70 72 6f 6a 65 63 74 20 64 61 74 61 2e 0a 20   project data.. 
1480: 20 20 20 20 2a 0a 20 20 20 20 20 2a 2f 0a 20 20      *.     */.  
1490: 20 20 66 75 6e 63 74 69 6f 6e 20 64 69 73 70 61    function dispa
14a0: 74 63 68 28 29 20 7b 0a 20 20 20 20 0a 20 20 20  tch() {.    .   
14b0: 20 20 20 20 20 2f 2f 20 46 65 74 63 68 20 6c 61       // Fetch la
14c0: 74 65 73 74 20 72 65 76 69 73 69 6f 6e 0a 20 20  test revision.  
14d0: 20 20 20 20 20 20 24 70 72 6f 6a 65 63 74 20 3d        $project =
14e0: 20 6e 65 77 20 72 65 6c 65 61 73 65 28 24 74 68   new release($th
14f0: 69 73 2d 3e 6e 61 6d 65 29 3b 0a 20 20 20 20 20  is->name);.     
1500: 20 20 20 69 66 20 28 65 6d 70 74 79 28 24 70 72     if (empty($pr
1510: 6f 6a 65 63 74 5b 22 6e 61 6d 65 22 5d 29 20 26  oject["name"]) &
1520: 26 20 28 24 74 68 69 73 2d 3e 61 70 69 20 21 3d  & ($this->api !=
1530: 3d 20 22 6e 65 77 5f 70 72 6f 6a 65 63 74 22 29  = "new_project")
1540: 29 20 7b 0a 20 20 20 20 20 20 20 20 20 20 20 20  ) {.            
1550: 2f 2f 20 52 65 74 75 72 6e 20 32 30 34 20 77 69  // Return 204 wi
1560: 74 68 20 65 6d 70 74 79 20 e2 86 92 70 72 6f 6a  th empty ...proj
1570: 65 63 74 e2 86 92 6e 61 6d 65 20 66 69 65 6c 64  ect...name field
1580: 2e 0a 20 20 20 20 20 20 20 20 20 20 20 20 24 74  ..            $t
1590: 68 69 73 2d 3e 65 72 72 6f 72 5f 65 78 69 74 28  his->error_exit(
15a0: 4e 55 4c 4c 2c 20 22 32 30 30 20 4e 6f 20 63 6f  NULL, "200 No co
15b0: 6e 74 65 6e 74 22 2c 20 22 55 6e 6b 6e 6f 77 6e  ntent", "Unknown
15c0: 20 70 72 6f 6a 65 63 74 20 6e 61 6d 65 22 29 3b   project name");
15d0: 0a 20 20 20 20 20 20 20 20 7d 0a 20 20 20 20 20  .        }.     
15e0: 20 20 20 0a 20 20 20 20 20 20 20 20 2f 2f 20 52     .        // R
15f0: 75 6e 20 64 69 61 6c 65 64 20 6d 65 74 68 6f 64  un dialed method
1600: 2c 20 74 68 65 6e 20 6f 75 74 70 75 74 20 4a 53  , then output JS
1610: 4f 4e 20 72 65 73 70 6f 6e 73 65 2e 0a 20 20 20  ON response..   
1620: 20 20 20 20 20 69 66 20 28 24 74 68 69 73 2d 3e       if ($this->
1630: 61 70 69 29 20 7b 0a 20 20 20 20 20 20 20 20 20  api) {.         
1640: 20 20 20 24 74 68 69 73 2d 3e 6a 73 6f 6e 5f 65     $this->json_e
1650: 78 69 74 28 24 74 68 69 73 2d 3e 7b 24 74 68 69  xit($this->{$thi
1660: 73 2d 3e 61 70 69 7d 28 24 70 72 6f 6a 65 63 74  s->api}($project
1670: 29 29 3b 0a 20 20 20 20 20 20 20 20 7d 0a 20 20  ));.        }.  
1680: 20 20 20 20 20 20 65 6c 73 65 20 7b 0a 20 20 20        else {.   
1690: 20 20 20 20 20 20 20 20 20 24 74 68 69 73 2d 3e           $this->
16a0: 65 72 72 6f 72 5f 65 78 69 74 28 4e 55 4c 4c 2c  error_exit(NULL,
16b0: 20 22 35 30 31 20 4e 6f 74 20 69 6d 70 6c 65 6d   "501 Not implem
16c0: 65 6e 74 65 64 22 2c 20 22 55 6e 6b 6e 6f 77 6e  ented", "Unknown
16d0: 20 72 65 71 75 65 73 74 20 73 63 68 65 6d 65 22   request scheme"
16e0: 29 3b 0a 20 20 20 20 20 20 20 20 7d 0a 20 20 20  );.        }.   
16f0: 20 7d 0a 0a 0a 0a 20 20 20 20 2f 2a 2a 0a 20 20   }....    /**.  
1700: 20 20 20 2a 20 47 45 54 20 70 72 6f 6a 65 63 74     * GET project
1710: 20 64 65 73 63 72 69 70 74 69 6f 6e 0a 20 20 20   description.   
1720: 20 20 2a 20 2d 2d 2d 2d 2d 2d 2d 2d 2d 2d 2d 2d    * ------------
1730: 2d 2d 2d 2d 2d 2d 2d 2d 2d 2d 2d 0a 20 20 20 20  -----------.    
1740: 20 2a 0a 20 20 20 20 20 2a 20 40 75 6e 61 75 74   *.     * @unaut
1750: 68 6f 72 69 7a 65 64 0a 20 20 20 20 20 2a 0a 20  horized.     *. 
1760: 20 20 20 20 2a 20 4a 75 73 74 20 72 65 74 75 72      * Just retur
1770: 6e 73 20 74 68 65 20 63 75 72 72 65 6e 74 20 70  ns the current p
1780: 72 6f 6a 65 63 74 20 64 65 73 63 72 69 70 74 69  roject descripti
1790: 6f 6e 2c 20 75 72 6c 73 20 61 6e 64 20 72 65 6c  on, urls and rel
17a0: 65 61 73 65 20 66 69 65 6c 64 73 3a 0a 20 20 20  ease fields:.   
17b0: 20 20 2a 0a 20 20 20 20 20 2a 20 20 20 e2 86 92    *.     *   ...
17c0: 20 6e 61 6d 65 0a 20 20 20 20 20 2a 20 20 20 e2   name.     *   .
17d0: 86 92 20 74 69 74 6c 65 0a 20 20 20 20 20 2a 20  .. title.     * 
17e0: 20 20 e2 86 92 20 73 75 6d 6d 61 72 79 0a 20 20    ... summary.  
17f0: 20 20 20 2a 20 20 20 e2 86 92 20 64 65 73 63 72     *   ... descr
1800: 69 70 74 69 6f 6e 0a 20 20 20 20 20 2a 20 20 20  iption.     *   
1810: e2 86 92 20 6c 69 63 65 6e 73 65 5f 6c 69 73 74  ... license_list
1820: 0a 20 20 20 20 20 2a 20 20 20 e2 86 92 20 70 72  .     *   ... pr
1830: 6f 6a 65 63 74 5f 74 61 67 73 0a 20 20 20 20 20  oject_tags.     
1840: 2a 20 20 20 e2 86 92 20 68 6f 6d 65 70 61 67 65  *   ... homepage
1850: 0a 20 20 20 20 20 2a 20 20 20 e2 86 92 20 75 72  .     *   ... ur
1860: 6c 73 20 7b 7d 0a 20 20 20 20 20 2a 20 20 20 e2  ls {}.     *   .
1870: 86 92 20 76 65 72 73 69 6f 6e 0a 20 20 20 20 20  .. version.     
1880: 2a 20 20 20 e2 86 92 20 63 68 61 6e 67 65 73 0a  *   ... changes.
1890: 20 20 20 20 20 2a 20 20 20 e2 86 92 20 72 65 6c       *   ... rel
18a0: 65 61 73 65 5f 74 61 67 73 0a 20 20 20 20 20 2a  ease_tags.     *
18b0: 20 20 20 e2 86 92 20 70 72 6f 6a 65 63 74 5f 74     ... project_t
18c0: 61 67 73 0a 20 20 20 20 20 2a 20 20 20 e2 86 92  ags.     *   ...
18d0: 20 64 6f 77 6e 6c 6f 61 64 0a 20 20 20 20 20 2a   download.     *
18e0: 20 20 20 e2 86 92 20 61 75 74 68 6f 72 2f 73 75     ... author/su
18f0: 62 6d 69 74 74 65 72 0a 20 20 20 20 20 2a 0a 20  bmitter.     *. 
1900: 20 20 20 20 2a 20 41 20 66 65 77 20 65 6e 74 72      * A few entr
1910: 69 65 73 20 61 72 65 20 64 75 70 6c 69 63 61 74  ies are duplicat
1920: 65 73 2e 20 41 6c 73 6f 20 61 70 70 65 6e 64 73  es. Also appends
1930: 20 65 78 74 72 61 6e 65 6f 75 73 20 66 72 65 73   extraneous fres
1940: 68 63 6f 64 65 20 66 69 65 6c 64 73 2e 0a 20 20  hcode fields..  
1950: 20 20 20 2a 0a 20 20 20 20 20 2a 2f 0a 20 20 20     *.     */.   
1960: 20 66 75 6e 63 74 69 6f 6e 20 71 75 65 72 79 28   function query(
1970: 24 70 72 6f 6a 65 63 74 29 20 7b 0a 20 20 20 20  $project) {.    
1980: 0a 20 20 20 20 20 20 20 20 2f 2f 20 45 76 65 72  .        // Ever
1990: 79 6f 6e 65 20 63 61 6e 20 61 63 63 65 73 73 20  yone can access 
19a0: 74 68 69 73 2c 20 62 75 74 20 6f 6e 6c 79 20 74  this, but only t
19b0: 68 65 20 6f 77 6e 65 72 20 77 69 6c 6c 20 73 65  he owner will se
19c0: 65 20 70 72 69 76 61 74 65 20 66 69 65 6c 64 73  e private fields
19d0: 0a 20 20 20 20 20 20 20 20 24 64 61 74 61 20 3d  .        $data =
19e0: 20 24 74 68 69 73 2d 3e 61 75 74 68 5f 66 69 6c   $this->auth_fil
19f0: 74 65 72 28 24 70 72 6f 6a 65 63 74 29 3b 0a 20  ter($project);. 
1a00: 20 20 20 0a 20 20 20 20 20 20 20 20 2f 2f 20 41     .        // A
1a10: 6c 69 61 73 20 73 6f 6d 65 20 66 69 65 6c 64 73  lias some fields
1a20: 20 66 6f 72 20 66 63 2d 73 75 62 6d 69 74 2c 20   for fc-submit, 
1a30: 62 75 74 20 61 70 70 65 6e 64 20 6f 75 72 20 64  but append our d
1a40: 61 74 61 20 73 63 68 65 6d 65 20 69 6e 74 61 63  ata scheme intac
1a50: 74 0a 20 20 20 20 20 20 20 20 24 72 20 3d 20 61  t.        $r = a
1a60: 72 72 61 79 28 0a 20 20 20 20 20 20 20 20 20 20  rray(.          
1a70: 20 20 22 70 72 6f 6a 65 63 74 22 20 3d 3e 20 61    "project" => a
1a80: 72 72 61 79 28 0a 20 20 20 20 20 20 20 20 20 20  rray(.          
1a90: 20 20 20 20 20 20 20 23 22 69 64 22 20 20 20 20         #"id"    
1aa0: 20 20 20 20 3d 3e 20 22 5c 24 4f 42 53 4f 4c 45      => "\$OBSOLE
1ab0: 54 45 20 e2 86 92 20 6e 61 6d 65 22 2c 0a 20 20  TE ... name",.  
1ac0: 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 23                 #
1ad0: 22 70 65 72 6d 61 6c 69 6e 6b 22 20 3d 3e 20 22  "permalink" => "
1ae0: 5c 24 4f 42 53 4f 4c 45 54 45 20 e2 86 92 20 6e  \$OBSOLETE ... n
1af0: 61 6d 65 22 2c 0a 20 20 20 20 20 20 20 20 20 20  ame",.          
1b00: 20 20 20 20 20 20 20 23 22 6f 6e 65 6c 69 6e 65         #"oneline
1b10: 72 22 20 20 3d 3e 20 22 5c 24 4f 42 53 4f 4c 45  r"  => "\$OBSOLE
1b20: 54 45 20 e2 86 92 20 73 75 6d 6d 61 72 79 22 2c  TE ... summary",
1b30: 0a 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20  .               
1b40: 20 20 23 22 74 61 67 5f 6c 69 73 74 22 20 20 3d    #"tag_list"  =
1b50: 3e 20 22 5c 24 4f 42 53 4f 4c 45 54 45 20 e2 86  > "\$OBSOLETE ..
1b60: 92 20 70 72 6f 6a 65 63 74 5f 74 61 67 73 22 2c  . project_tags",
1b70: 0a 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20  .               
1b80: 20 20 23 22 61 70 70 72 6f 76 65 64 5f 75 72 6c    #"approved_url
1b90: 73 22 20 3d 3e 20 5b 5d 2c 0a 20 20 20 20 20 20  s" => [],.      
1ba0: 20 20 20 20 20 20 20 20 20 20 20 22 6e 61 6d 65             "name
1bb0: 22 20 3d 3e 20 24 64 61 74 61 5b 22 6e 61 6d 65  " => $data["name
1bc0: 22 5d 2c 0a 20 20 20 20 20 20 20 20 20 20 20 20  "],.            
1bd0: 20 20 20 20 20 22 73 75 6d 6d 61 72 79 22 20 3d       "summary" =
1be0: 3e 20 24 64 61 74 61 5b 22 73 75 6d 6d 61 72 79  > $data["summary
1bf0: 22 5d 2c 0a 20 20 20 20 20 20 20 20 20 20 20 20  "],.            
1c00: 20 20 20 20 20 22 6c 69 63 65 6e 73 65 5f 6c 69       "license_li
1c10: 73 74 22 20 3d 3e 20 24 64 61 74 61 5b 22 6c 69  st" => $data["li
1c20: 63 65 6e 73 65 22 5d 2c 0a 20 20 20 20 20 20 20  cense"],.       
1c30: 20 20 20 20 20 20 20 20 20 20 22 70 72 6f 6a 65            "proje
1c40: 63 74 5f 74 61 67 73 22 20 3d 3e 20 24 64 61 74  ct_tags" => $dat
1c50: 61 5b 22 74 61 67 73 22 5d 2c 0a 20 20 20 20 20  a["tags"],.     
1c60: 20 20 20 20 20 20 20 20 20 20 20 20 22 75 72 6c              "url
1c70: 73 22 20 3d 3e 20 24 74 68 69 73 2d 3e 75 72 6c  s" => $this->url
1c80: 73 5f 65 78 70 61 6e 64 28 24 64 61 74 61 2c 20  s_expand($data, 
1c90: 24 64 61 74 61 5b 22 75 72 6c 73 22 5d 29 2c 0a  $data["urls"]),.
1ca0: 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20                  
1cb0: 20 22 72 65 6c 65 61 73 65 5f 74 61 67 73 22 20   "release_tags" 
1cc0: 3d 3e 20 22 24 64 61 74 61 5b 73 74 61 74 65 5d  => "$data[state]
1cd0: 2c 24 64 61 74 61 5b 73 63 6f 70 65 5d 22 2c 0a  ,$data[scope]",.
1ce0: 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20                  
1cf0: 20 22 61 75 74 68 6f 72 22 20 3d 3e 20 24 64 61   "author" => $da
1d00: 74 61 5b 22 73 75 62 6d 69 74 74 65 72 22 5d 2c  ta["submitter"],
1d10: 0a 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20  .               
1d20: 20 20 22 73 75 62 6d 69 74 74 65 72 22 20 3d 3e    "submitter" =>
1d30: 20 4e 55 4c 4c 2c 0a 20 20 20 20 20 20 20 20 20   NULL,.         
1d40: 20 20 20 29 0a 20 20 20 20 20 20 20 20 20 20 20     ).           
1d50: 20 2b 20 24 64 61 74 61 2d 3e 67 65 74 41 72 72   + $data->getArr
1d60: 61 79 43 6f 70 79 28 29 20 20 2f 2f 20 6c 69 74  ayCopy()  // lit
1d70: 65 72 61 6c 20 44 42 20 66 69 65 6c 64 73 0a 20  eral DB fields. 
1d80: 20 20 20 20 20 20 20 29 3b 0a 20 20 20 20 20 20         );.      
1d90: 20 20 72 65 74 75 72 6e 20 24 72 3b 0a 20 20 20    return $r;.   
1da0: 20 7d 0a 20 20 20 20 0a 0a 0a 20 20 20 20 2f 2a   }.    ...    /*
1db0: 2a 0a 20 20 20 20 20 2a 20 50 55 54 20 70 72 6f  *.     * PUT pro
1dc0: 6a 65 63 74 20 62 61 73 65 20 66 69 65 6c 64 73  ject base fields
1dd0: 0a 20 20 20 20 20 2a 20 2d 2d 2d 2d 2d 2d 2d 2d  .     * --------
1de0: 2d 2d 2d 2d 2d 2d 2d 2d 2d 2d 2d 2d 2d 2d 2d 0a  ---------------.
1df0: 20 20 20 20 20 2a 0a 20 20 20 20 20 2a 20 40 61       *.     * @a
1e00: 75 74 68 2d 72 65 71 75 69 72 65 64 0a 20 20 20  uth-required.   
1e10: 20 20 2a 0a 20 20 20 20 20 2a 20 57 68 65 72 65    *.     * Where
1e20: 61 73 20 74 68 65 20 22 70 72 6f 6a 65 63 74 22  as the "project"
1e30: 20 70 61 79 6c 6f 61 64 20 73 65 63 74 69 6f 6e   payload section
1e40: 20 63 61 6e 20 63 6f 6e 74 61 69 6e 3a 0a 20 20   can contain:.  
1e50: 20 20 20 2a 20 20 20 e2 86 92 20 74 69 74 6c 65     *   ... title
1e60: 0a 20 20 20 20 20 2a 20 20 20 e2 86 92 20 73 75  .     *   ... su
1e70: 6d 6d 61 72 79 0a 20 20 20 20 20 2a 20 20 20 e2  mmary.     *   .
1e80: 86 92 20 64 65 73 63 72 69 70 74 69 6f 6e 0a 20  .. description. 
1e90: 20 20 20 20 2a 20 20 20 e2 86 92 20 68 6f 6d 65      *   ... home
1ea0: 70 61 67 65 0a 20 20 20 20 20 2a 20 20 20 e2 86  page.     *   ..
1eb0: 92 20 6c 69 63 65 6e 73 65 5f 6c 69 73 74 0a 20  . license_list. 
1ec0: 20 20 20 20 2a 20 20 20 e2 86 92 20 70 72 6f 6a      *   ... proj
1ed0: 65 63 74 5f 74 61 67 73 0a 20 20 20 20 20 2a 20  ect_tags.     * 
1ee0: 20 20 e2 86 92 20 64 6f 77 6e 6c 6f 61 64 0a 20    ... download. 
1ef0: 20 20 20 20 2a 20 41 6e 64 20 61 6e 20 55 52 4c      * And an URL
1f00: 20 64 69 63 74 69 6f 6e 61 72 79 20 28 77 69 74   dictionary (wit
1f10: 68 69 6e 20 70 72 6f 6a 65 63 74 20 6f 72 20 67  hin project or g
1f20: 72 6f 75 70 65 64 20 6f 75 74 29 3a 0a 20 20 20  rouped out):.   
1f30: 20 20 2a 20 20 20 e2 86 92 20 75 72 6c 73 5b 64    *   ... urls[d
1f40: 6f 77 6e 6c 6f 61 64 5d 0a 20 20 20 20 20 2a 20  ownload].     * 
1f50: 20 20 e2 86 92 20 75 72 6c 73 5b 63 68 61 6e 67    ... urls[chang
1f60: 65 6c 6f 67 5d 0a 20 20 20 20 20 2a 20 20 20 e2  elog].     *   .
1f70: 86 92 20 75 72 6c 73 5b 73 63 72 65 65 6e 73 68  .. urls[screensh
1f80: 6f 74 5d 0a 20 20 20 20 20 2a 20 20 20 e2 86 92  ot].     *   ...
1f90: 20 75 72 6c 73 5b 63 75 73 74 6f 6d 2d 6e 61 6d   urls[custom-nam
1fa0: 65 5d 0a 20 20 20 20 20 2a 20 52 65 6c 65 61 73  e].     * Releas
1fb0: 65 20 69 6e 66 6f 73 20 28 65 6d 62 65 64 64 65  e infos (embedde
1fc0: 64 20 6f 72 20 73 65 70 61 72 61 74 65 20 4a 53  d or separate JS
1fd0: 4f 4e 20 73 74 72 75 63 74 29 3a 0a 20 20 20 20  ON struct):.    
1fe0: 20 2a 20 20 20 e2 86 92 20 76 65 72 73 69 6f 6e   *   ... version
1ff0: 0a 20 20 20 20 20 2a 20 20 20 e2 86 92 20 63 68  .     *   ... ch
2000: 61 6e 67 65 73 0a 20 20 20 20 20 2a 20 20 20 e2  anges.     *   .
2010: 86 92 20 72 65 6c 65 61 73 65 5f 74 61 67 73 0a  .. release_tags.
2020: 20 20 20 20 20 2a 20 20 20 e2 86 92 20 68 69 64       *   ... hid
2030: 65 0a 20 20 20 20 20 2a 20 20 20 e2 86 92 20 73  e.     *   ... s
2040: 74 61 74 65 0a 20 20 20 20 20 2a 20 20 20 e2 86  tate.     *   ..
2050: 92 20 73 63 6f 70 65 0a 20 20 20 20 20 2a 20 41  . scope.     * A
2060: 64 64 69 74 69 6f 6e 61 6c 6c 79 20 77 65 27 64  dditionally we'd
2070: 20 61 63 63 65 70 74 3a 0a 20 20 20 20 20 2a 20   accept:.     * 
2080: 20 20 e2 86 92 20 61 75 74 68 6f 72 0a 20 20 20    ... author.   
2090: 20 20 2a 0a 20 20 20 20 20 2a 2f 0a 20 20 20 20    *.     */.    
20a0: 66 75 6e 63 74 69 6f 6e 20 75 70 64 61 74 65 5f  function update_
20b0: 63 6f 72 65 28 24 70 72 6f 6a 65 63 74 2c 20 24  core($project, $
20c0: 69 73 5f 6e 65 77 3d 30 29 20 7b 0a 20 20 20 20  is_new=0) {.    
20d0: 20 20 20 20 0a 20 20 20 20 20 20 20 20 2f 2f 20      .        // 
20e0: 41 75 74 68 6f 72 69 7a 61 74 69 6f 6e 20 28 72  Authorization (r
20f0: 65 64 75 6e 64 61 6e 74 20 68 65 72 65 2c 20 73  edundant here, s
2100: 69 6e 63 65 20 2d 3e 69 6e 73 65 72 74 20 63 68  ince ->insert ch
2110: 65 63 6b 73 20 61 6c 72 65 61 64 79 29 0a 20 20  ecks already).  
2120: 20 20 20 20 20 20 24 64 61 74 61 20 3d 20 24 74        $data = $t
2130: 68 69 73 2d 3e 61 75 74 68 5f 66 69 6c 74 65 72  his->auth_filter
2140: 28 24 70 72 6f 6a 65 63 74 29 3b 0a 0a 20 20 20  ($project);..   
2150: 20 20 20 20 20 2f 2f 20 4a 6f 69 6e 20 6f 70 74       // Join opt
2160: 69 6f 6e 61 6c 6c 79 20 73 65 63 74 69 6f 6e 65  ionally sectione
2170: 64 20 4a 53 4f 4e 20 64 69 63 74 73 20 22 70 72  d JSON dicts "pr
2180: 6f 6a 65 63 74 22 2c 20 22 72 65 6c 65 61 73 65  oject", "release
2190: 22 20 61 6e 64 20 22 75 72 6c 73 22 0a 20 20 20  " and "urls".   
21a0: 20 20 20 20 20 24 62 6f 64 79 20 3d 20 24 74 68       $body = $th
21b0: 69 73 2d 3e 6d 65 72 67 65 5f 62 6f 64 79 28 29  is->merge_body()
21c0: 3b 0a 20 20 20 20 20 20 20 20 0a 20 20 20 20 20  ;.        .     
21d0: 20 20 20 2f 2f 20 65 78 74 72 61 63 74 20 66 69     // extract fi
21e0: 65 6c 64 73 0a 20 20 20 20 20 20 20 20 24 69 6e  elds.        $in
21f0: 20 3d 20 6e 65 77 20 69 6e 70 75 74 28 24 62 6f   = new input($bo
2200: 64 79 2c 20 22 50 55 54 5f 75 70 64 61 74 65 5f  dy, "PUT_update_
2210: 63 6f 72 65 22 29 3b 0a 20 20 20 20 20 20 20 20  core");.        
2220: 24 6e 65 77 20 3d 20 61 72 72 61 79 28 0a 0a 20  $new = array(.. 
2230: 20 20 20 20 20 20 20 20 20 20 20 2f 2f 20 62 61             // ba
2240: 73 69 63 20 70 72 6f 6a 65 63 74 20 66 69 65 6c  sic project fiel
2250: 64 73 0a 20 20 20 20 20 20 20 20 20 20 20 20 22  ds.            "
2260: 74 69 74 6c 65 22 20 3d 3e 20 24 69 6e 2d 3e 74  title" => $in->t
2270: 65 78 74 5b 22 74 69 74 6c 65 22 5d 2c 0a 20 20  ext["title"],.  
2280: 20 20 20 20 20 20 20 20 20 20 22 73 75 6d 6d 61            "summa
2290: 72 79 22 20 3d 3e 20 24 69 6e 2d 3e 74 65 78 74  ry" => $in->text
22a0: 5b 22 73 75 6d 6d 61 72 79 22 5d 2c 0a 20 20 20  ["summary"],.   
22b0: 20 20 20 20 20 20 20 20 20 22 64 65 73 63 72 69           "descri
22c0: 70 74 69 6f 6e 22 20 3d 3e 20 24 69 6e 2d 3e 74  ption" => $in->t
22d0: 65 78 74 5b 22 64 65 73 63 72 69 70 74 69 6f 6e  ext["description
22e0: 22 5d 2c 0a 20 20 20 20 20 20 20 20 20 20 20 20  "],.            
22f0: 22 74 61 67 73 22 20 3d 3e 20 66 5f 74 61 67 73  "tags" => f_tags
2300: 28 24 69 6e 2d 3e 74 65 78 74 5b 22 70 72 6f 6a  ($in->text["proj
2310: 65 63 74 5f 74 61 67 73 22 5d 29 2c 0a 20 20 20  ect_tags"]),.   
2320: 20 20 20 20 20 20 20 20 20 22 6c 69 63 65 6e 73           "licens
2330: 65 22 20 3d 3e 20 24 74 68 69 73 2d 3e 6d 61 70  e" => $this->map
2340: 5f 6c 69 63 65 6e 73 65 73 28 24 69 6e 2d 3e 77  _licenses($in->w
2350: 6f 72 64 73 5b 22 6c 69 63 65 6e 73 65 5f 6c 69  ords["license_li
2360: 73 74 22 5d 29 2c 0a 20 20 20 20 20 20 20 20 20  st"]),.         
2370: 20 20 20 22 73 75 62 6d 69 74 74 65 72 22 20 3d     "submitter" =
2380: 3e 20 24 69 6e 2d 3e 74 65 78 74 5b 22 61 75 74  > $in->text["aut
2390: 68 6f 72 22 5d 2c 0a 20 20 20 20 20 20 20 20 20  hor"],.         
23a0: 20 20 20 22 68 6f 6d 65 70 61 67 65 22 20 3d 3e     "homepage" =>
23b0: 20 24 69 6e 2d 3e 75 72 6c 2d 3e 68 74 74 70 5b   $in->url->http[
23c0: 22 68 6f 6d 65 70 61 67 65 22 5d 2c 0a 20 20 20  "homepage"],.   
23d0: 20 20 20 20 20 20 20 20 20 22 69 6d 61 67 65 22           "image"
23e0: 20 3d 3e 20 24 69 6e 2d 3e 75 72 6c 2d 3e 68 74   => $in->url->ht
23f0: 74 70 5b 22 69 6d 61 67 65 22 5d 2c 0a 0a 20 20  tp["image"],..  
2400: 20 20 20 20 20 20 20 20 20 20 2f 2f 20 72 65 6c            // rel
2410: 65 61 73 65 20 66 69 65 6c 64 73 0a 20 20 20 20  ease fields.    
2420: 20 20 20 20 20 20 20 20 22 76 65 72 73 69 6f 6e          "version
2430: 22 20 3d 3e 20 24 69 6e 2d 3e 74 65 78 74 5b 22  " => $in->text["
2440: 76 65 72 73 69 6f 6e 22 5d 2c 0a 20 20 20 20 20  version"],.     
2450: 20 20 20 20 20 20 20 22 63 68 61 6e 67 65 73 22         "changes"
2460: 20 3d 3e 20 24 69 6e 2d 3e 74 65 78 74 5b 22 63   => $in->text["c
2470: 68 61 6e 67 65 73 22 5d 2c 0a 20 20 20 20 20 20  hanges"],.      
2480: 20 20 20 20 20 20 22 73 74 61 74 65 22 20 3d 3e        "state" =>
2490: 20 74 61 67 73 3a 3a 73 74 61 74 65 5f 74 61 67   tags::state_tag
24a0: 28 24 69 6e 2d 3e 6d 75 6c 74 69 2d 3e 6a 6f 69  ($in->multi->joi
24b0: 6e 2d 3e 77 6f 72 64 73 2d 3e 64 65 66 61 75 6c  n->words->defaul
24c0: 74 e2 80 a6 70 72 65 72 65 6c 65 61 73 65 5b 22  t...prerelease["
24d0: 73 74 61 74 65 2c 72 65 6c 65 61 73 65 5f 74 61  state,release_ta
24e0: 67 73 2c 72 65 6c 65 61 73 65 5f 74 61 67 5f 6c  gs,release_tag_l
24f0: 69 73 74 22 5d 29 2c 0a 20 20 20 20 20 20 20 20  ist"]),.        
2500: 20 20 20 20 22 73 63 6f 70 65 22 20 3d 3e 20 74      "scope" => t
2510: 61 67 73 3a 3a 73 63 6f 70 65 5f 74 61 67 73 28  ags::scope_tags(
2520: 24 69 6e 2d 3e 6d 75 6c 74 69 2d 3e 6a 6f 69 6e  $in->multi->join
2530: 2d 3e 77 6f 72 64 73 2d 3e 64 65 66 61 75 6c 74  ->words->default
2540: e2 80 a6 69 6e 69 74 69 61 6c 5b 22 73 63 6f 70  ...initial["scop
2550: 65 2c 72 65 6c 65 61 73 65 5f 74 61 67 73 2c 72  e,release_tags,r
2560: 65 6c 65 61 73 65 5f 74 61 67 5f 6c 69 73 74 22  elease_tag_list"
2570: 5d 29 2c 0a 20 20 20 20 20 20 20 20 20 20 20 20  ]),.            
2580: 22 64 6f 77 6e 6c 6f 61 64 22 20 3d 3e 20 24 69  "download" => $i
2590: 6e 2d 3e 75 72 6c 2d 3e 68 74 74 70 5b 22 64 6f  n->url->http["do
25a0: 77 6e 6c 6f 61 64 22 5d 2c 0a 0a 20 20 20 20 20  wnload"],..     
25b0: 20 20 20 20 20 20 20 2f 2f 20 65 78 74 72 61 73         // extras
25c0: 2c 20 6f 72 20 69 6e 74 65 72 6e 61 6c 73 0a 20  , or internals. 
25d0: 20 20 20 20 20 20 20 29 3b 0a 20 20 20 20 20 20         );.      
25e0: 20 20 0a 20 20 20 20 20 20 20 20 2f 2f 20 6d 65    .        // me
25f0: 72 67 65 20 69 6e 20 63 6f 72 65 20 22 75 72 6c  rge in core "url
2600: 73 22 20 69 66 20 70 72 65 73 65 6e 74 2c 20 74  s" if present, t
2610: 75 72 6e 20 75 72 6c 73 7b 7d 20 69 6e 74 6f 20  urn urls{} into 
2620: 6b 65 79 3d 76 61 6c 75 65 20 6c 69 73 74 0a 20  key=value list. 
2630: 20 20 20 20 20 20 20 69 66 20 28 24 69 6e 2d 3e         if ($in->
2640: 68 61 73 28 22 75 72 6c 73 22 29 29 20 7b 0a 20  has("urls")) {. 
2650: 20 20 20 20 20 20 20 20 20 20 20 24 74 68 69 73             $this
2660: 2d 3e 75 72 6c 73 5f 6d 61 70 28 24 6e 65 77 2c  ->urls_map($new,
2670: 20 24 69 6e 2d 3e 72 61 77 5b 22 75 72 6c 73 22   $in->raw["urls"
2680: 5d 29 3b 0a 20 20 20 20 20 20 20 20 7d 0a 20 20  ]);.        }.  
2690: 20 20 20 20 20 20 2f 2f 20 61 75 74 6f 6d 61 74        // automat
26a0: 69 63 61 6c 6c 79 20 75 73 65 20 4e 45 57 53 20  ically use NEWS 
26b0: 66 69 6c 65 20 69 66 20 70 72 65 73 65 6e 74 0a  file if present.
26c0: 20 20 20 20 20 20 20 20 69 66 20 28 70 72 65 67          if (preg
26d0: 5f 6d 61 74 63 68 28 22 2f 4e 45 57 53 2f 22 2c  _match("/NEWS/",
26e0: 20 24 6e 65 77 5b 22 61 75 74 6f 75 70 64 61 74   $new["autoupdat
26f0: 65 5f 75 72 6c 22 5d 29 29 20 7b 0a 20 20 20 20  e_url"])) {.    
2700: 20 20 20 20 20 20 20 20 24 6e 65 77 5b 22 61 75          $new["au
2710: 74 6f 75 70 64 61 74 65 5f 6d 6f 64 75 6c 65 22  toupdate_module"
2720: 5d 20 3d 20 22 63 68 61 6e 67 65 6c 6f 67 22 3b  ] = "changelog";
2730: 0a 20 20 20 20 20 20 20 20 7d 0a 20 20 20 20 20  .        }.     
2740: 20 20 20 0a 20 20 20 20 20 20 20 20 2f 2f 20 55     .        // U
2750: 70 64 61 74 65 20 66 6c 61 67 73 0a 20 20 20 20  pdate flags.    
2760: 20 20 20 20 24 66 6c 61 67 73 20 3d 20 61 72 72      $flags = arr
2770: 61 79 28 0a 20 20 20 20 20 20 20 20 20 20 20 20  ay(.            
2780: 22 68 69 64 64 65 6e 22 20 3d 3e 20 24 69 6e 2d  "hidden" => $in-
2790: 3e 69 6e 74 5b 22 68 69 64 64 65 6e 22 5d 20 7c  >int["hidden"] |
27a0: 7c 20 24 69 6e 2d 3e 69 6e 74 5b 22 68 69 64 65  | $in->int["hide
27b0: 22 5d 20 7c 7c 20 21 65 6d 70 74 79 28 24 6e 65  "] || !empty($ne
27c0: 77 5b 22 68 69 64 64 65 6e 22 5d 29 2c 0a 20 20  w["hidden"]),.  
27d0: 20 20 20 20 20 20 20 20 20 20 22 64 65 6c 65 74            "delet
27e0: 65 64 22 20 3d 3e 20 30 2c 20 20 20 2f 2f 20 65  ed" => 0,   // e
27f0: 6d 70 74 79 20 74 69 74 6c 65 2c 64 65 73 63 72  mpty title,descr
2800: 69 70 74 69 6f 6e 2c 68 6f 6d 65 70 61 67 65 0a  iption,homepage.
2810: 20 20 20 20 20 20 20 20 29 3b 0a 0a 20 20 20 20          );..    
2820: 20 20 20 20 72 65 74 75 72 6e 20 24 74 68 69 73      return $this
2830: 2d 3e 69 6e 73 65 72 74 28 24 70 72 6f 6a 65 63  ->insert($projec
2840: 74 2c 20 24 6e 65 77 2c 20 24 66 6c 61 67 73 29  t, $new, $flags)
2850: 3b 0a 20 20 20 20 7d 0a 0a 0a 20 20 20 20 2f 2a  ;.    }...    /*
2860: 2a 0a 20 20 20 20 20 2a 20 45 78 70 61 6e 64 20  *.     * Expand 
2870: 43 53 56 20 6c 69 73 74 20 6f 66 20 6c 69 63 65  CSV list of lice
2880: 6e 73 65 20 6e 61 6d 65 73 20 69 6e 74 6f 20 6f  nse names into o
2890: 75 72 20 69 6e 74 65 72 6e 61 6c 20 64 65 6e 6f  ur internal deno
28a0: 6d 69 6e 61 74 6f 72 73 3b 0a 20 20 20 20 20 2a  minators;.     *
28b0: 20 61 6e 64 20 6b 65 65 70 20 63 6f 6d 6d 61 2d   and keep comma-
28c0: 73 65 70 61 72 61 74 69 6f 6e 2e 0a 20 20 20 20  separation..    
28d0: 20 2a 0a 20 20 20 20 20 2a 2f 0a 20 20 20 20 66   *.     */.    f
28e0: 75 6e 63 74 69 6f 6e 20 6d 61 70 5f 6c 69 63 65  unction map_lice
28f0: 6e 73 65 73 28 24 63 73 76 5f 6c 69 63 65 6e 73  nses($csv_licens
2900: 65 73 2c 20 24 72 3d 5b 5d 29 20 7b 0a 20 20 20  es, $r=[]) {.   
2910: 20 20 20 20 20 66 6f 72 65 61 63 68 20 28 70 5f       foreach (p_
2920: 63 73 76 28 24 63 73 76 5f 6c 69 63 65 6e 73 65  csv($csv_license
2930: 73 29 20 61 73 20 24 6c 69 63 65 6e 73 65 29 20  s) as $license) 
2940: 7b 0a 20 20 20 20 20 20 20 20 20 20 20 20 24 72  {.            $r
2950: 5b 5d 20 3d 20 74 61 67 73 3a 3a 6d 61 70 5f 6c  [] = tags::map_l
2960: 69 63 65 6e 73 65 28 24 6c 69 63 65 6e 73 65 29  icense($license)
2970: 3b 0a 20 20 20 20 20 20 20 20 7d 0a 20 20 20 20  ;.        }.    
2980: 20 20 20 20 72 65 74 75 72 6e 20 24 72 20 3f 20      return $r ? 
2990: 6a 6f 69 6e 28 22 2c 20 22 2c 20 24 72 29 20 3a  join(", ", $r) :
29a0: 20 4e 55 4c 4c 3b 0a 20 20 20 20 7d 0a 0a 0a 20   NULL;.    }... 
29b0: 20 20 20 2f 2a 2a 0a 20 20 20 20 20 2a 20 43 6f     /**.     * Co
29c0: 6d 62 69 6e 65 20 73 65 63 74 69 6f 6e 65 64 20  mbine sectioned 
29d0: 4a 53 4f 4e 20 70 61 79 6c 6f 61 64 2e 0a 20 20  JSON payload..  
29e0: 20 20 20 2a 20 20 20 7b 0a 20 20 20 20 20 2a 20     *   {.     * 
29f0: 20 20 20 20 22 70 72 6f 6a 65 63 74 22 3a 20 7b      "project": {
2a00: 7d 2c 0a 20 20 20 20 20 2a 20 20 20 20 20 22 75  },.     *     "u
2a10: 72 6c 73 22 3a 20 7b 7d 2c 0a 20 20 20 20 20 2a  rls": {},.     *
2a20: 20 20 20 20 20 22 72 65 6c 65 61 73 65 22 3a 20       "release": 
2a30: 7b 7d 2c 0a 20 20 20 20 20 2a 20 20 20 7d 0a 20  {},.     *   }. 
2a40: 20 20 20 20 2a 20 41 6c 6c 20 67 65 74 20 6d 65      * All get me
2a50: 72 67 65 64 20 69 6e 74 6f 20 73 69 6e 67 6c 65  rged into single
2a60: 20 72 65 71 75 65 73 74 20 73 74 72 75 63 74 75   request structu
2a70: 72 65 2e 0a 20 20 20 20 20 2a 0a 20 20 20 20 20  re..     *.     
2a80: 2a 2f 0a 20 20 20 20 66 75 6e 63 74 69 6f 6e 20  */.    function 
2a90: 6d 65 72 67 65 5f 62 6f 64 79 28 29 20 7b 0a 20  merge_body() {. 
2aa0: 20 20 20 20 20 20 20 24 62 6f 64 79 20 3d 20 5b         $body = [
2ab0: 5d 3b 0a 20 20 20 20 20 20 20 20 69 66 20 28 69  ];.        if (i
2ac0: 73 73 65 74 28 24 74 68 69 73 2d 3e 62 6f 64 79  sset($this->body
2ad0: 5b 22 70 72 6f 6a 65 63 74 22 5d 29 29 20 7b 0a  ["project"])) {.
2ae0: 20 20 20 20 20 20 20 20 20 20 20 20 24 62 6f 64              $bod
2af0: 79 20 3d 20 61 72 72 61 79 5f 6d 65 72 67 65 28  y = array_merge(
2b00: 24 62 6f 64 79 2c 20 24 74 68 69 73 2d 3e 62 6f  $body, $this->bo
2b10: 64 79 5b 22 70 72 6f 6a 65 63 74 22 5d 29 3b 0a  dy["project"]);.
2b20: 20 20 20 20 20 20 20 20 7d 0a 20 20 20 20 20 20          }.      
2b30: 20 20 69 66 20 28 69 73 73 65 74 28 24 74 68 69    if (isset($thi
2b40: 73 2d 3e 62 6f 64 79 5b 22 72 65 6c 65 61 73 65  s->body["release
2b50: 22 5d 29 29 20 7b 0a 20 20 20 20 20 20 20 20 20  "])) {.         
2b60: 20 20 20 24 62 6f 64 79 20 3d 20 61 72 72 61 79     $body = array
2b70: 5f 6d 65 72 67 65 28 24 62 6f 64 79 2c 20 24 74  _merge($body, $t
2b80: 68 69 73 2d 3e 62 6f 64 79 5b 22 72 65 6c 65 61  his->body["relea
2b90: 73 65 22 5d 29 3b 0a 20 20 20 20 20 20 20 20 7d  se"]);.        }
2ba0: 0a 20 20 20 20 20 20 20 20 69 66 20 28 69 73 73  .        if (iss
2bb0: 65 74 28 24 74 68 69 73 2d 3e 62 6f 64 79 5b 22  et($this->body["
2bc0: 75 72 6c 73 22 5d 29 29 20 7b 0a 20 20 20 20 20  urls"])) {.     
2bd0: 20 20 20 20 20 20 20 24 62 6f 64 79 5b 22 75 72         $body["ur
2be0: 6c 73 22 5d 20 3d 20 24 74 68 69 73 2d 3e 62 6f  ls"] = $this->bo
2bf0: 64 79 5b 22 75 72 6c 73 22 5d 3b 0a 20 20 20 20  dy["urls"];.    
2c00: 20 20 20 20 7d 0a 20 20 20 20 20 20 20 20 72 65      }.        re
2c10: 74 75 72 6e 20 24 62 6f 64 79 3b 0a 20 20 20 20  turn $body;.    
2c20: 7d 0a 0a 0a 0a 20 20 20 20 2f 2a 2a 0a 20 20 20  }....    /**.   
2c30: 20 20 2a 20 43 52 45 41 54 45 20 70 72 6f 6a 65    * CREATE proje
2c40: 63 74 20 77 69 74 68 20 62 61 73 65 20 66 69 65  ct with base fie
2c50: 6c 64 73 0a 20 20 20 20 20 2a 20 2d 2d 2d 2d 2d  lds.     * -----
2c60: 2d 2d 2d 2d 2d 2d 2d 2d 2d 2d 2d 2d 2d 2d 2d 2d  ----------------
2c70: 2d 2d 2d 2d 2d 2d 2d 2d 2d 2d 0a 20 20 20 20 20  ----------.     
2c80: 2a 0a 20 20 20 20 20 2a 20 40 61 75 74 68 2d 72  *.     * @auth-r
2c90: 65 71 75 69 72 65 64 0a 20 20 20 20 20 2a 20 40  equired.     * @
2ca0: 63 65 72 74 2d 72 65 71 75 69 72 65 64 0a 20 20  cert-required.  
2cb0: 20 20 20 2a 0a 20 20 20 20 20 2a 20 53 61 6d 65     *.     * Same
2cc0: 20 66 69 65 6c 64 73 20 73 75 70 70 6f 72 74 65   fields supporte
2cd0: 64 20 61 73 20 66 6f 72 20 60 75 70 64 61 74 65  d as for `update
2ce0: 5f 63 6f 72 65 60 20 2f 20 50 55 54 20 72 65 71  _core` / PUT req
2cf0: 75 65 73 74 2c 0a 20 20 20 20 20 2a 20 62 75 74  uest,.     * but
2d00: 20 61 64 64 69 74 69 6f 6e 61 6c 6c 79 2f 6f 70   additionally/op
2d10: 74 69 6f 6e 61 6c 6c 79 20 61 63 63 65 70 74 73  tionally accepts
2d20: 3a 3a 0a 20 20 20 20 20 2a 20 20 20 20 e2 86 92  ::.     *    ...
2d30: 20 74 69 74 6c 65 0a 20 20 20 20 20 2a 20 20 20   title.     *   
2d40: 20 e2 86 92 20 69 6d 61 67 65 20 20 20 20 20 20   ... image      
2d50: 20 20 20 28 55 52 4c 20 74 6f 20 70 72 6f 6a 65     (URL to proje
2d60: 63 74 20 6c 6f 67 6f 2f 73 63 72 65 65 6e 73 68  ct logo/screensh
2d70: 6f 74 29 0a 20 20 20 20 20 2a 20 20 20 20 e2 86  ot).     *    ..
2d80: 92 20 72 65 6c 65 61 73 65 5f 74 61 67 73 20 20  . release_tags  
2d90: 28 22 69 6e 69 74 69 61 6c 2c 62 75 67 66 69 78  ("initial,bugfix
2da0: 22 29 0a 20 20 20 20 20 2a 20 20 20 20 e2 86 92  ").     *    ...
2db0: 20 61 75 74 68 6f 72 20 20 20 20 20 20 20 20 28   author        (
2dc0: 22 6e 69 63 6b 6e 61 6d 65 2c 20 75 73 65 72 40  "nickname, user@
2dd0: 73 6f 75 72 63 65 66 6f 72 67 65 22 29 0a 20 20  sourceforge").  
2de0: 20 20 20 2a 20 20 20 20 e2 86 92 20 76 65 72 73     *    ... vers
2df0: 69 6f 6e 0a 20 20 20 20 20 2a 20 20 20 20 e2 86  ion.     *    ..
2e00: 92 20 63 68 61 6e 67 65 73 0a 20 20 20 20 20 2a  . changes.     *
2e10: 20 20 20 20 e2 86 92 20 63 68 61 6e 67 65 6c 6f      ... changelo
2e20: 67 2d 55 52 4c 20 28 74 6f 20 4e 45 57 53 20 66  g-URL (to NEWS f
2e30: 69 6c 65 29 0a 20 20 20 20 20 2a 0a 20 20 20 20  ile).     *.    
2e40: 20 2a 20 42 75 74 20 63 61 6e 20 63 72 65 61 74   * But can creat
2e50: 65 20 65 6e 74 69 72 65 6c 79 20 6e 65 77 20 70  e entirely new p
2e60: 72 6f 6a 65 63 74 73 2e 20 28 57 4f 52 4b 53 20  rojects. (WORKS 
2e70: 4a 55 53 54 20 4f 4e 43 45 29 2e 0a 20 20 20 20  JUST ONCE)..    
2e80: 20 2a 20 50 6f 70 75 6c 61 74 65 73 20 74 68 65   * Populates the
2e90: 20 60 6c 6f 63 6b 60 20 66 69 65 6c 64 20 77 69   `lock` field wi
2ea0: 74 68 20 74 68 65 20 68 61 73 68 65 64 20 60 61  th the hashed `a
2eb0: 75 74 68 5f 63 6f 64 65 60 2e 0a 20 20 20 20 20  uth_code`..     
2ec0: 2a 0a 20 20 20 20 20 2a 2f 0a 20 20 20 20 66 75  *.     */.    fu
2ed0: 6e 63 74 69 6f 6e 20 6e 65 77 5f 70 72 6f 6a 65  nction new_proje
2ee0: 63 74 28 24 70 72 6f 6a 65 63 74 29 20 7b 0a 20  ct($project) {. 
2ef0: 20 20 20 0a 20 20 20 20 20 20 20 20 2f 2f 20 43     .        // C
2f00: 68 65 63 6b 20 61 6e 74 69 2d 73 70 61 6d 20 63  heck anti-spam c
2f10: 65 72 74 69 66 69 63 61 74 65 0a 20 20 20 20 20  ertificate.     
2f20: 20 20 20 23 20 24 74 68 69 73 2d 3e 72 65 71 75     # $this->requ
2f30: 69 72 65 73 5f 73 73 6c 5f 63 65 72 74 28 29 3b  ires_ssl_cert();
2f40: 0a 20 20 20 20 20 20 20 20 0a 20 20 20 20 20 20  .        .      
2f50: 20 20 2f 2f 20 50 6f 70 75 6c 61 74 65 20 6e 65    // Populate ne
2f60: 77 20 70 72 6f 6a 65 63 74 20 72 65 63 6f 72 64  w project record
2f70: 0a 20 20 20 20 20 20 20 20 24 69 6e 20 3d 20 6e  .        $in = n
2f80: 65 77 20 69 6e 70 75 74 28 24 74 68 69 73 2d 3e  ew input($this->
2f90: 62 6f 64 79 5b 22 70 72 6f 6a 65 63 74 22 5d 2c  body["project"],
2fa0: 20 22 43 52 45 41 54 45 5f 6e 65 77 5f 70 72 6f   "CREATE_new_pro
2fb0: 6a 65 63 74 22 29 3b 0a 20 20 20 20 20 20 20 20  ject");.        
2fc0: 24 70 72 6f 6a 65 63 74 20 3d 20 6e 65 77 20 72  $project = new r
2fd0: 65 6c 65 61 73 65 28 61 72 72 61 79 28 0a 20 20  elease(array(.  
2fe0: 20 20 20 20 20 20 20 20 20 20 22 6e 61 6d 65 22            "name"
2ff0: 20 3d 3e 20 24 74 68 69 73 2d 3e 6e 61 6d 65 2c   => $this->name,
3000: 20 2f 2f 20 61 6c 72 65 61 64 79 20 66 69 6c 74   // already filt
3010: 65 72 65 64 0a 20 20 20 20 20 20 20 20 20 20 20  ered.           
3020: 20 22 74 69 74 6c 65 22 20 3d 3e 20 24 69 6e 2d   "title" => $in-
3030: 3e 74 65 78 74 2d 3e 64 65 66 61 75 6c 74 28 22  >text->default("
3040: 74 69 74 6c 65 22 2c 20 24 74 68 69 73 2d 3e 6e  title", $this->n
3050: 61 6d 65 29 2c 0a 20 20 20 20 20 20 20 20 20 20  ame),.          
3060: 20 20 22 73 75 62 6d 69 74 74 65 72 22 20 3d 3e    "submitter" =>
3070: 20 24 69 6e 2d 3e 74 65 78 74 2d 3e 64 65 66 61   $in->text->defa
3080: 75 6c 74 28 22 61 75 74 68 6f 72 22 2c 20 22 66  ult("author", "f
3090: 72 65 65 63 6f 64 65 2d 73 75 62 6d 69 74 2c 20  reecode-submit, 
30a0: 61 70 69 40 66 72 65 73 68 63 6f 64 65 2e 63 6c  api@freshcode.cl
30b0: 75 62 22 29 2c 0a 20 20 20 20 20 20 20 20 20 20  ub"),.          
30c0: 20 20 22 65 64 69 74 6f 72 5f 6e 6f 74 65 22 20    "editor_note" 
30d0: 3d 3e 20 73 65 6c 66 3a 3a 45 44 49 54 4f 52 5f  => self::EDITOR_
30e0: 4e 4f 54 45 2c 0a 20 20 20 20 20 20 20 20 20 20  NOTE,.          
30f0: 20 20 22 68 69 64 64 65 6e 22 20 3d 3e 20 65 6d    "hidden" => em
3100: 70 74 79 28 24 69 6e 2d 3e 74 65 78 74 5b 22 76  pty($in->text["v
3110: 65 72 73 69 6f 6e 22 5d 29 2c 0a 20 20 20 20 20  ersion"]),.     
3120: 20 20 20 20 20 20 20 22 61 75 74 6f 75 70 64 61         "autoupda
3130: 74 65 5f 6d 6f 64 75 6c 65 22 20 3d 3e 20 22 61  te_module" => "a
3140: 70 69 22 2c 0a 20 20 20 20 20 20 20 20 20 20 20  pi",.           
3150: 20 22 66 6c 61 67 22 20 3d 3e 20 30 2c 0a 20 20   "flag" => 0,.  
3160: 20 20 20 20 20 20 20 20 20 20 22 64 65 6c 65 74            "delet
3170: 65 64 22 20 3d 3e 20 30 2c 0a 20 20 20 20 20 20  ed" => 0,.      
3180: 20 20 20 20 20 20 22 73 6f 63 69 61 6c 5f 6c 69        "social_li
3190: 6e 6b 73 22 20 3d 3e 20 30 2c 0a 20 20 20 20 20  nks" => 0,.     
31a0: 20 20 20 20 20 20 20 22 73 75 62 6d 69 74 74 65         "submitte
31b0: 72 5f 69 6d 61 67 65 22 20 3d 3e 20 22 22 2c 0a  r_image" => "",.
31c0: 20 20 20 20 20 20 20 20 20 20 20 20 22 61 75 74              "aut
31d0: 6f 75 70 64 61 74 65 5f 64 65 6c 61 79 22 20 3d  oupdate_delay" =
31e0: 3e 20 30 2e 32 35 2c 0a 20 20 20 20 20 20 20 20  > 0.25,.        
31f0: 20 20 20 20 22 6c 6f 63 6b 22 20 3d 3e 20 70 61      "lock" => pa
3200: 73 73 77 6f 72 64 5f 68 61 73 68 28 24 74 68 69  ssword_hash($thi
3210: 73 2d 3e 61 75 74 68 5f 63 6f 64 65 2c 20 50 41  s->auth_code, PA
3220: 53 53 57 4f 52 44 5f 44 45 46 41 55 4c 54 29 2c  SSWORD_DEFAULT),
3230: 0a 20 20 20 20 20 20 20 20 29 29 3b 0a 20 20 20  .        ));.   
3240: 20 20 20 20 20 0a 20 20 20 20 20 20 20 20 72 65       .        re
3250: 74 75 72 6e 20 24 74 68 69 73 2d 3e 75 70 64 61  turn $this->upda
3260: 74 65 5f 63 6f 72 65 28 24 70 72 6f 6a 65 63 74  te_core($project
3270: 2c 20 24 69 73 5f 6e 65 77 3d 31 29 3b 0a 20 20  , $is_new=1);.  
3280: 20 20 7d 0a 0a 0a 0a 20 20 20 20 2f 2a 2a 0a 20    }....    /**. 
3290: 20 20 20 20 2a 20 50 4f 53 54 20 72 65 6c 65 61      * POST relea
32a0: 73 65 2f 76 65 72 73 69 6f 6e 0a 20 20 20 20 20  se/version.     
32b0: 2a 20 2d 2d 2d 2d 2d 2d 2d 2d 2d 2d 2d 2d 2d 2d  * --------------
32c0: 2d 2d 2d 2d 2d 2d 0a 20 20 20 20 20 2a 0a 20 20  ------.     *.  
32d0: 20 20 20 2a 20 40 61 75 74 68 2d 72 65 71 75 69     * @auth-requi
32e0: 72 65 64 0a 20 20 20 20 20 2a 0a 20 20 20 20 20  red.     *.     
32f0: 2a 20 54 68 69 73 20 69 73 20 6e 6f 77 20 6a 75  * This is now ju
3300: 73 74 20 61 20 77 72 61 70 70 65 72 20 61 72 6f  st a wrapper aro
3310: 75 6e 64 20 74 68 65 20 72 65 67 75 6c 61 72 20  und the regular 
3320: 50 55 54 20 6d 65 74 68 6f 64 2c 0a 20 20 20 20  PUT method,.    
3330: 20 2a 20 77 68 69 63 68 20 61 6c 72 65 61 64 79   * which already
3340: 20 68 61 6e 64 6c 65 73 20 74 68 65 20 72 65 6c   handles the rel
3350: 65 61 73 65 20 66 69 65 6c 64 73 2e 0a 20 20 20  ease fields..   
3360: 20 20 2a 0a 20 20 20 20 20 2a 2f 0a 20 20 20 20    *.     */.    
3370: 66 75 6e 63 74 69 6f 6e 20 70 75 62 6c 69 73 68  function publish
3380: 28 24 70 72 6f 6a 65 63 74 29 20 7b 0a 20 20 20  ($project) {.   
3390: 20 20 20 20 20 72 65 74 75 72 6e 20 24 74 68 69       return $thi
33a0: 73 2d 3e 75 70 64 61 74 65 5f 63 6f 72 65 28 24  s->update_core($
33b0: 70 72 6f 6a 65 63 74 29 3b 0a 20 20 20 20 7d 0a  project);.    }.
33c0: 20 20 20 20 0a 0a 20 20 20 20 2f 2a 2a 0a 20 20      ..    /**.  
33d0: 20 20 20 2a 20 43 68 65 63 6b 20 66 6f 72 20 22     * Check for "
33e0: 70 65 6e 64 69 6e 67 22 20 72 65 6c 65 61 73 65  pending" release
33f0: 73 0a 20 20 20 20 20 2a 20 2d 2d 2d 2d 2d 2d 2d  s.     * -------
3400: 2d 2d 2d 2d 2d 2d 2d 2d 2d 2d 2d 2d 2d 2d 2d 2d  ----------------
3410: 2d 2d 2d 2d 2d 0a 20 20 20 20 20 2a 0a 20 20 20  -----.     *.   
3420: 20 20 2a 20 40 6f 62 73 6f 6c 65 74 65 0a 20 20    * @obsolete.  
3430: 20 20 20 2a 0a 20 20 20 20 20 2a 2f 0a 20 20 20     *.     */.   
3440: 20 66 75 6e 63 74 69 6f 6e 20 76 65 72 73 69 6f   function versio
3450: 6e 5f 47 45 54 28 24 70 72 6f 6a 65 63 74 29 20  n_GET($project) 
3460: 7b 0a 20 20 20 20 20 20 20 20 72 65 74 75 72 6e  {.        return
3470: 20 24 74 68 69 73 2d 3e 65 72 72 6f 72 5f 65 78   $this->error_ex
3480: 69 74 28 4e 55 4c 4c 2c 20 27 34 31 30 20 4f 62  it(NULL, '410 Ob
3490: 73 6f 6c 65 74 65 27 2c 20 22 54 68 65 72 65 20  solete', "There 
34a0: 61 72 65 20 6e 6f 20 70 65 6e 64 69 6e 67 20 72  are no pending r
34b0: 65 6c 65 61 73 65 73 2e 20 4a 75 73 74 20 75 73  eleases. Just us
34c0: 65 20 44 45 4c 45 54 45 20 6f 6e 20 2f 70 72 6f  e DELETE on /pro
34d0: 6a 65 63 74 73 2f 5c 24 6e 61 6d 65 2f 5c 24 76  jects/\$name/\$v
34e0: 65 72 73 69 6f 6e 73 74 72 2e 6a 73 6f 6e 20 69  ersionstr.json i
34f0: 6e 73 74 65 61 64 2e 22 29 3b 0a 20 20 20 20 7d  nstead.");.    }
3500: 0a 0a 0a 0a 20 20 20 20 2f 2a 2a 0a 20 20 20 20  ....    /**.    
3510: 20 2a 20 22 57 69 74 68 64 72 61 77 22 20 61 20   * "Withdraw" a 
3520: 22 70 65 6e 64 69 6e 67 22 20 72 65 6c 65 61 73  "pending" releas
3530: 65 0a 20 20 20 20 20 2a 20 2d 2d 2d 2d 2d 2d 2d  e.     * -------
3540: 2d 2d 2d 2d 2d 2d 2d 2d 2d 2d 2d 2d 2d 2d 2d 2d  ----------------
3550: 2d 2d 2d 2d 2d 2d 2d 0a 20 20 20 20 20 2a 0a 20  -------.     *. 
3560: 20 20 20 20 2a 20 40 61 75 74 68 2d 72 65 71 75      * @auth-requ
3570: 69 72 65 64 0a 20 20 20 20 20 2a 0a 20 20 20 20  ired.     *.    
3580: 20 2a 20 57 65 27 72 65 20 66 61 6b 69 6e 67 20   * We're faking 
3590: 74 77 6f 20 74 68 69 6e 67 73 20 68 65 72 65 2e  two things here.
35a0: 20 46 69 72 73 74 6c 79 20 74 68 61 74 20 74 68   Firstly that th
35b0: 65 20 72 65 76 69 65 77 20 70 72 6f 63 65 73 73  e review process
35c0: 0a 20 20 20 20 20 2a 20 77 61 73 20 65 6e 61 62  .     * was enab
35d0: 6c 65 64 20 62 79 20 64 65 66 61 75 6c 74 2e 20  led by default. 
35e0: 53 65 63 6f 6e 64 6c 79 20 74 68 61 74 20 79 6f  Secondly that yo
35f0: 75 20 63 6f 75 6c 64 20 64 65 6c 65 74 65 20 74  u could delete t
3600: 68 69 6e 67 73 2e 0a 20 20 20 20 20 2a 20 28 54  hings..     * (T
3610: 68 65 20 64 61 74 61 62 61 73 65 20 69 73 20 64  he database is d
3620: 65 73 69 67 6e 65 64 20 74 6f 20 62 65 20 73 6f  esigned to be so
3630: 6d 65 77 68 61 74 20 22 69 6d 6d 75 74 61 62 6c  mewhat "immutabl
3640: 65 22 2c 20 77 65 20 6a 75 73 74 0a 20 20 20 20  e", we just.    
3650: 20 2a 20 70 69 6c 65 20 75 70 20 72 65 76 69 73   * pile up revis
3660: 69 6f 6e 73 20 6e 6f 72 6d 61 6c 6c 79 2e 29 0a  ions normally.).
3670: 20 20 20 20 20 2a 0a 20 20 20 20 20 2a 20 53 6f       *.     * So
3680: 20 77 69 74 68 64 72 61 77 69 6e 67 20 61 20 72   withdrawing a r
3690: 65 6c 65 61 73 65 20 6a 75 73 74 20 6d 65 61 6e  elease just mean
36a0: 73 20 69 74 20 67 65 74 73 20 6d 61 72 6b 65 64  s it gets marked
36b0: 20 22 64 65 6c 65 74 65 64 22 0a 20 20 20 20 20   "deleted".     
36c0: 2a 20 28 66 6f 72 6d 65 72 6c 79 20 6a 75 73 74  * (formerly just
36d0: 20 22 68 69 64 64 65 6e 22 20 61 6e 64 2f 6f 72   "hidden" and/or
36e0: 20 66 6c 61 67 67 65 64 20 66 6f 72 20 6d 6f 64   flagged for mod
36f0: 65 72 61 74 6f 72 20 61 74 74 65 6e 74 69 6f 6e  erator attention
3700: 2e 29 0a 20 20 20 20 20 2a 20 54 68 69 73 20 73  .).     * This s
3710: 6f 6d 65 77 68 61 74 20 73 74 69 6c 6c 20 6d 61  omewhat still ma
3720: 79 20 74 65 72 6d 69 6e 61 74 65 20 61 20 70 72  y terminate a pr
3730: 6f 6a 65 63 74 20 6c 69 66 65 6c 69 6e 65 20 28  oject lifeline (
3740: 64 75 65 20 74 6f 20 56 49 45 57 0a 20 20 20 20  due to VIEW.    
3750: 20 2a 20 72 65 76 69 73 69 6f 6e 20 67 72 6f 75   * revision grou
3760: 70 69 6e 67 29 2c 20 62 75 74 20 63 61 6e 20 62  ping), but can b
3770: 65 20 75 6e 64 6f 6e 65 20 62 79 20 73 75 62 6d  e undone by subm
3780: 69 74 74 69 6e 67 20 74 68 65 20 72 65 6c 65 61  itting the relea
3790: 73 65 0a 20 20 20 20 20 2a 20 61 6e 65 77 2e 0a  se.     * anew..
37a0: 20 20 20 20 20 2a 0a 20 20 20 20 20 2a 20 54 68       *.     * Th
37b0: 65 20 72 65 61 73 6f 6e 69 6e 67 20 62 65 69 6e  e reasoning bein
37c0: 67 20 74 68 61 74 20 77 69 74 68 64 72 61 77 6e  g that withdrawn
37d0: 20 72 65 6c 65 61 73 65 73 20 61 72 65 20 72 65   releases are re
37e0: 61 6c 6c 79 20 6a 75 73 74 0a 20 20 20 20 20 2a  ally just.     *
37f0: 20 61 75 74 68 6f 72 73 20 6d 61 6b 69 6e 67 20   authors making 
3800: 6c 61 73 74 20 6d 69 6e 75 74 65 20 66 69 78 65  last minute fixe
3810: 73 3b 20 63 6f 6d 6d 6f 6e 6c 79 20 72 65 74 72  s; commonly retr
3820: 61 63 74 65 64 20 72 65 6c 65 61 73 65 73 0a 20  acted releases. 
3830: 20 20 20 20 2a 20 61 72 65 20 6a 75 73 74 20 72      * are just r
3840: 65 73 65 6e 74 20 6c 61 74 65 72 2c 20 6f 72 20  esent later, or 
3850: 77 69 74 68 20 61 20 64 69 66 66 65 72 65 6e 74  with a different
3860: 20 63 68 61 6e 67 65 6c 6f 67 2e 0a 20 20 20 20   changelog..    
3870: 20 2a 0a 20 20 20 20 20 2a 2f 0a 20 20 20 20 66   *.     */.    f
3880: 75 6e 63 74 69 6f 6e 20 76 65 72 73 69 6f 6e 5f  unction version_
3890: 44 45 4c 45 54 45 28 24 70 72 6f 6a 65 63 74 29  DELETE($project)
38a0: 20 7b 0a 0a 20 20 20 20 20 20 20 20 2f 2f 20 4f   {..        // O
38b0: 62 76 69 6f 75 73 6c 79 20 72 65 71 75 69 72 65  bviously require
38c0: 73 20 61 20 76 61 6c 69 64 20 60 6c 6f 63 6b 60  s a valid `lock`
38d0: 20 68 61 73 68 0a 20 20 20 20 20 20 20 20 24 74   hash.        $t
38e0: 68 69 73 2d 3e 72 65 71 75 69 72 65 73 5f 70 65  his->requires_pe
38f0: 72 6d 69 73 73 69 6f 6e 28 24 70 72 6f 6a 65 63  rmission($projec
3900: 74 29 3b 0a 20 20 20 20 20 20 20 20 61 73 73 65  t);.        asse
3910: 72 74 28 27 69 73 5f 6e 75 6d 65 72 69 63 28 24  rt('is_numeric($
3920: 74 68 69 73 2d 3e 72 65 76 29 27 29 3b 0a 0a 20  this->rev)');.. 
3930: 20 20 20 20 20 20 20 2f 2f 20 48 69 64 65 20 61         // Hide a
3940: 6c 6c 20 65 6e 74 72 69 65 73 20 66 6f 72 20 72  ll entries for r
3950: 65 76 69 73 69 6f 6e 0a 20 20 20 20 20 20 20 20  evision.        
3960: 24 72 20 3d 20 64 62 28 5b 0a 20 20 20 20 20 20  $r = db([.      
3970: 20 20 20 22 20 55 50 44 41 54 45 20 72 65 6c 65     " UPDATE rele
3980: 61 73 65 20 22 2c 0a 20 20 20 20 20 20 20 20 20  ase ",.         
3990: 22 20 20 20 20 53 45 54 20 3a 2c 20 20 22 20 3d  "    SET :,  " =
39a0: 3e 20 5b 22 68 69 64 64 65 6e 22 20 3d 3e 20 31  > ["hidden" => 1
39b0: 2c 20 22 64 65 6c 65 74 65 64 22 20 3d 3e 20 31  , "deleted" => 1
39c0: 2c 20 22 66 6c 61 67 22 20 3d 3e 20 30 5d 2c 0a  , "flag" => 0],.
39d0: 20 20 20 20 20 20 20 20 20 22 20 20 57 48 45 52           "  WHER
39e0: 45 20 3a 26 20 20 22 20 3d 3e 20 5b 22 6e 61 6d  E :&  " => ["nam
39f0: 65 22 20 3d 3e 20 24 74 68 69 73 2d 3e 6e 61 6d  e" => $this->nam
3a00: 65 2c 20 22 76 65 72 73 69 6f 6e 22 20 3d 3e 20  e, "version" => 
3a10: 24 74 68 69 73 2d 3e 72 65 76 5d 0a 20 20 20 20  $this->rev].    
3a20: 20 20 20 20 5d 29 3b 0a 20 20 20 20 20 20 20 20      ]);.        
3a30: 0a 20 20 20 20 20 20 20 20 72 65 74 75 72 6e 20  .        return 
3a40: 24 72 20 3f 20 61 72 72 61 79 28 22 73 75 63 63  $r ? array("succ
3a50: 65 73 73 22 20 3d 3e 20 54 52 55 45 29 20 3a 20  ess" => TRUE) : 
3a60: 24 74 68 69 73 2d 3e 65 72 72 6f 72 5f 65 78 69  $this->error_exi
3a70: 74 28 4e 55 4c 4c 29 3b 0a 20 20 20 20 7d 0a 0a  t(NULL);.    }..
3a80: 0a 20 20 20 20 2f 2a 2a 0a 20 20 20 20 20 2a 20  .    /**.     * 
3a90: 55 52 4c 20 65 64 69 74 69 6e 67 0a 20 20 20 20  URL editing.    
3aa0: 20 2a 20 2d 2d 2d 2d 2d 2d 2d 2d 2d 2d 2d 0a 20   * -----------. 
3ab0: 20 20 20 20 2a 0a 20 20 20 20 20 2a 20 40 61 75      *.     * @au
3ac0: 74 68 2d 72 65 71 75 69 72 65 64 0a 20 20 20 20  th-required.    
3ad0: 20 2a 0a 20 20 20 20 20 2a 20 54 68 65 72 65 20   *.     * There 
3ae0: 69 73 20 6f 6e 65 20 61 73 73 6f 63 69 61 74 69  is one associati
3af0: 76 65 20 55 52 4c 20 62 6c 6f 62 20 66 6f 72 20  ve URL blob for 
3b00: 72 65 61 64 69 6e 67 20 61 6e 64 20 75 70 64 61  reading and upda
3b10: 74 69 6e 67 20 61 6c 6c 20 55 52 4c 73 0a 20 20  ting all URLs.  
3b20: 20 20 20 2a 20 61 74 20 6f 6e 63 65 2e 20 54 68     * at once. Th
3b30: 65 20 75 72 6c 73 7b 7d 20 64 69 63 74 20 63 61  e urls{} dict ca
3b40: 6e 20 62 65 20 70 72 65 73 65 6e 74 20 62 79 20  n be present by 
3b50: 69 74 73 65 6c 66 2c 20 69 6e 20 61 6c 6c 20 50  itself, in all P
3b60: 55 54 20 6f 72 20 50 4f 53 54 0a 20 20 20 20 20  UT or POST.     
3b70: 2a 20 72 65 71 75 65 73 74 73 2c 20 6f 72 20 62  * requests, or b
3b80: 65 20 61 20 73 75 62 61 72 72 61 79 20 6f 66 20  e a subarray of 
3b90: 74 68 65 20 6f 75 74 65 72 20 70 72 6f 6a 65 63  the outer projec
3ba0: 74 7b 7d 20 73 74 72 75 63 74 75 72 65 2e 0a 20  t{} structure.. 
3bb0: 20 20 20 20 2a 0a 20 20 20 20 20 2a 20 20 20 47      *.     *   G
3bc0: 45 54 20 2f 70 72 6f 6a 65 63 74 73 2f 6e 61 6d  ET /projects/nam
3bd0: 65 2f 75 72 6c 73 2e 6a 73 6f 6e 20 20 20 7b 20  e/urls.json   { 
3be0: 22 75 72 6c 73 22 20 3a 20 7b 20 22 73 72 63 22  "urls" : { "src"
3bf0: 3a 20 22 68 74 74 70 3a 2f 2f 2e 2e 22 2c 0a 20  : "http://..",. 
3c00: 20 20 20 20 2a 20 20 20 20 20 20 20 20 20 20 20      *           
3c10: 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20                  
3c20: 20 20 20 20 20 20 20 20 20 20 20 20 22 67 69 74              "git
3c30: 68 75 62 22 3a 20 22 68 74 74 70 3a 2f 2f 2e 2e  hub": "http://..
3c40: 22 20 7d 20 20 20 20 7d 0a 20 20 20 20 20 2a 20  " }    }.     * 
3c50: 20 20 50 55 54 20 2f 70 72 6f 6a 65 63 74 73 2f    PUT /projects/
3c60: 6e 61 6d 65 2f 75 72 6c 73 2e 6a 73 6f 6e 20 20  name/urls.json  
3c70: 20 7b 20 22 75 72 6c 73 22 3a 20 7b 20 22 74 78   { "urls": { "tx
3c80: 7a 22 3a 2c 20 22 64 6f 63 22 3a 2e 2e 20 7d 20  z":, "doc":.. } 
3c90: 20 7d 0a 20 20 20 20 20 2a 0a 20 20 20 20 20 2a   }.     *.     *
3ca0: 20 4f 75 72 20 6c 61 62 65 6c 73 20 75 73 65 20   Our labels use 
3cb0: 74 68 65 20 74 61 67 2d 66 6f 72 6d 2c 20 73 6f  the tag-form, so
3cc0: 20 69 6e 63 6f 6d 69 6e 67 20 6c 61 62 65 6c 73   incoming labels
3cd0: 20 77 69 6c 6c 20 62 65 20 61 64 61 70 74 65 64   will be adapted
3ce0: 2e 0a 20 20 20 20 20 2a 20 22 54 61 72 2f 42 5a  ..     * "Tar/BZ
3cf0: 32 22 20 62 65 63 6f 6d 65 73 20 22 54 61 72 2d  2" becomes "Tar-
3d00: 42 5a 32 22 20 77 69 74 68 20 63 61 73 65 20 70  BZ2" with case p
3d10: 72 65 73 65 72 76 65 64 2c 20 62 75 74 20 64 61  reserved, but da
3d20: 73 68 65 64 2d 6e 61 6d 65 73 2e 0a 20 20 20 20  shed-names..    
3d30: 20 2a 0a 20 20 20 20 20 2a 20 49 6e 74 65 72 6e   *.     * Intern
3d40: 61 6c 6c 79 20 74 68 65 20 75 72 6c 73 20 61 72  ally the urls ar
3d50: 65 20 73 74 6f 72 65 64 20 69 6e 20 61 6e 20 49  e stored in an I
3d60: 4e 49 2d 73 74 79 6c 65 20 6b 65 79 3d 76 61 6c  NI-style key=val
3d70: 75 65 20 74 65 78 74 20 62 6c 6f 62 2e 0a 20 20  ue text blob..  
3d80: 20 20 20 2a 20 28 42 75 74 20 74 68 65 20 41 50     * (But the AP
3d90: 49 20 73 74 61 79 73 20 73 6f 6d 65 77 68 61 74  I stays somewhat
3da0: 20 6d 6f 72 65 20 52 45 53 54 79 20 77 69 74 68   more RESTy with
3db0: 20 61 6e 20 61 73 73 6f 63 69 61 74 69 76 65 20   an associative 
3dc0: 64 69 63 74 2e 29 0a 20 20 20 20 20 2a 0a 20 20  dict.).     *.  
3dd0: 20 20 20 2a 2f 0a 20 20 20 20 66 75 6e 63 74 69     */.    functi
3de0: 6f 6e 20 75 72 6c 73 28 24 70 72 6f 6a 65 63 74  on urls($project
3df0: 29 20 7b 0a 20 20 20 20 0a 20 20 20 20 20 20 20  ) {.    .       
3e00: 20 2f 2a 2a 0a 20 20 20 20 20 20 20 20 20 2a 20   /**.         * 
3e10: 46 6f 72 20 61 20 47 45 54 20 71 75 65 72 79 20  For a GET query 
3e20: 6a 75 73 74 20 6d 69 72 72 6f 72 20 22 4f 74 68  just mirror "Oth
3e30: 65 72 20 55 52 4c 73 22 20 61 73 20 64 69 63 74  er URLs" as dict
3e40: 0a 20 20 20 20 20 20 20 20 20 2a 0a 20 20 20 20  .         *.    
3e50: 20 20 20 20 20 2a 20 40 75 6e 61 75 74 68 6f 72       * @unauthor
3e60: 69 7a 65 64 0a 20 20 20 20 20 20 20 20 20 2a 0a  ized.         *.
3e70: 20 20 20 20 20 20 20 20 20 2a 2f 0a 20 20 20 20           */.    
3e80: 20 20 20 20 69 66 20 28 24 74 68 69 73 2d 3e 6d      if ($this->m
3e90: 65 74 68 6f 64 20 3d 3d 20 22 47 45 54 22 29 20  ethod == "GET") 
3ea0: 7b 0a 20 20 20 20 20 20 20 20 20 20 20 20 72 65  {.            re
3eb0: 74 75 72 6e 20 61 72 72 61 79 28 22 75 72 6c 73  turn array("urls
3ec0: 22 20 3d 3e 20 24 74 68 69 73 2d 3e 75 72 6c 73  " => $this->urls
3ed0: 5f 65 78 70 61 6e 64 28 24 70 72 6f 6a 65 63 74  _expand($project
3ee0: 2c 20 24 70 72 6f 6a 65 63 74 5b 22 75 72 6c 73  , $project["urls
3ef0: 22 5d 29 29 3b 0a 20 20 20 20 20 20 20 20 7d 0a  "]));.        }.
3f00: 20 20 20 20 20 20 20 20 0a 20 20 20 20 20 20 20          .       
3f10: 20 2f 2a 2a 0a 20 20 20 20 20 20 20 20 20 2a 20   /**.         * 
3f20: 55 70 64 61 74 65 73 20 6d 61 79 20 63 6f 6d 65  Updates may come
3f30: 20 61 73 20 50 55 54 2c 20 50 4f 53 54 2c 20 50   as PUT, POST, P
3f40: 55 53 48 20 72 65 71 75 65 73 74 0a 20 20 20 20  USH request.    
3f50: 20 20 20 20 20 2a 0a 20 20 20 20 20 20 20 20 20       *.         
3f60: 2a 20 40 61 75 74 68 2d 72 65 71 75 69 72 65 64  * @auth-required
3f70: 0a 20 20 20 20 20 20 20 20 20 2a 0a 20 20 20 20  .         *.    
3f80: 20 20 20 20 20 2a 2f 0a 20 20 20 20 20 20 20 20       */.        
3f90: 65 6c 73 65 20 7b 0a 20 20 20 20 20 20 20 20 20  else {.         
3fa0: 20 20 20 24 74 68 69 73 2d 3e 75 72 6c 73 5f 6d     $this->urls_m
3fb0: 61 70 28 24 70 72 6f 6a 65 63 74 2c 20 24 74 68  ap($project, $th
3fc0: 69 73 2d 3e 62 6f 64 79 5b 22 75 72 6c 73 22 5d  is->body["urls"]
3fd0: 29 3b 0a 20 20 20 20 20 20 20 20 20 20 20 20 2f  );.            /
3fe0: 2f 20 55 70 64 61 74 65 20 44 42 0a 20 20 20 20  / Update DB.    
3ff0: 20 20 20 20 20 20 20 20 72 65 74 75 72 6e 20 24          return $
4000: 74 68 69 73 2d 3e 69 6e 73 65 72 74 28 24 70 72  this->insert($pr
4010: 6f 6a 65 63 74 2c 20 24 70 72 6f 6a 65 63 74 2d  oject, $project-
4020: 3e 67 65 74 41 72 72 61 79 43 6f 70 79 28 29 29  >getArrayCopy())
4030: 3b 0a 20 20 20 20 20 20 20 20 7d 0a 20 20 20 20  ;.        }.    
4040: 7d 0a 0a 0a 20 20 20 20 2f 2a 2a 0a 20 20 20 20  }...    /**.    
4050: 20 2a 20 40 6f 75 74 67 6f 69 6e 67 20 3e 3e 3e   * @outgoing >>>
4060: 0a 20 20 20 20 20 2a 0a 20 20 20 20 20 2a 20 55  .     *.     * U
4070: 6e 70 61 63 6b 73 20 22 75 72 6c 73 22 20 66 72  npacks "urls" fr
4080: 6f 6d 20 6b 65 79 3d 76 61 6c 75 65 20 66 6f 72  om key=value for
4090: 6d 61 74 20 69 6e 74 6f 20 61 72 72 61 79 2c 0a  mat into array,.
40a0: 20 20 20 20 20 2a 20 61 6e 64 20 6a 6f 69 6e 73       * and joins
40b0: 20 63 6f 72 65 20 55 52 4c 73 20 28 68 6f 6d 65   core URLs (home
40c0: 70 61 67 65 2c 20 64 6f 77 6e 6c 6f 61 64 2c 20  page, download, 
40d0: 69 6d 61 67 65 29 20 69 6e 0a 20 20 20 20 20 2a  image) in.     *
40e0: 0a 20 20 20 20 20 2a 20 40 70 61 72 61 6d 20 20  .     * @param  
40f0: 52 65 6c 65 61 73 65 20 20 20 20 20 20 24 70 72  Release      $pr
4100: 6f 6a 65 63 74 20 6f 62 6a 65 63 74 2f 61 72 72  oject object/arr
4110: 61 79 0a 20 20 20 20 20 2a 20 40 70 61 72 61 6d  ay.     * @param
4120: 20 20 73 74 72 69 6e 67 20 20 20 20 20 20 20 22    string       "
4130: 74 69 74 6c 65 3d 75 72 6c 22 20 6c 69 73 74 2c  title=url" list,
4140: 20 69 6e 69 2f 79 61 6d 6c 2d 73 74 79 6c 65 0a   ini/yaml-style.
4150: 20 20 20 20 20 2a 2f 0a 20 20 20 20 66 75 6e 63       */.    func
4160: 74 69 6f 6e 20 75 72 6c 73 5f 65 78 70 61 6e 64  tion urls_expand
4170: 28 24 70 72 6f 6a 65 63 74 2c 20 24 75 72 6c 73  ($project, $urls
4180: 29 20 7b 0a 20 20 20 20 20 20 20 20 24 75 72 6c  ) {.        $url
4190: 73 20 3d 20 70 5f 6b 65 79 5f 76 61 6c 75 65 28  s = p_key_value(
41a0: 24 75 72 6c 73 2c 20 4e 55 4c 4c 29 3b 0a 20 20  $urls, NULL);.  
41b0: 20 20 20 20 20 20 24 75 72 6c 73 5b 22 48 6f 6d        $urls["Hom
41c0: 65 70 61 67 65 22 5d 20 3d 20 24 70 72 6f 6a 65  epage"] = $proje
41d0: 63 74 5b 22 68 6f 6d 65 70 61 67 65 22 5d 3b 0a  ct["homepage"];.
41e0: 20 20 20 20 20 20 20 20 24 75 72 6c 73 5b 22 44          $urls["D
41f0: 6f 77 6e 6c 6f 61 64 22 5d 20 3d 20 24 70 72 6f  ownload"] = $pro
4200: 6a 65 63 74 5b 22 64 6f 77 6e 6c 6f 61 64 22 5d  ject["download"]
4210: 3b 0a 20 20 20 20 20 20 20 20 24 75 72 6c 73 5b  ;.        $urls[
4220: 22 53 63 72 65 65 6e 73 68 6f 74 22 5d 20 3d 20  "Screenshot"] = 
4230: 24 70 72 6f 6a 65 63 74 5b 22 69 6d 61 67 65 22  $project["image"
4240: 5d 3b 0a 20 20 20 20 20 20 20 20 24 75 72 6c 73  ];.        $urls
4250: 5b 22 43 68 61 6e 67 65 6c 6f 67 22 5d 20 3d 20  ["Changelog"] = 
4260: 24 70 72 6f 6a 65 63 74 5b 22 61 75 74 6f 75 70  $project["autoup
4270: 64 61 74 65 5f 75 72 6c 22 5d 3b 0a 20 20 20 20  date_url"];.    
4280: 20 20 20 20 72 65 74 75 72 6e 20 61 72 72 61 79      return array
4290: 5f 66 69 6c 74 65 72 28 24 75 72 6c 73 2c 20 22  _filter($urls, "
42a0: 73 74 72 6c 65 6e 22 29 3b 0a 20 20 20 20 7d 0a  strlen");.    }.
42b0: 0a 0a 20 20 20 20 2f 2a 2a 0a 20 20 20 20 20 2a  ..    /**.     *
42c0: 20 40 69 6e 63 6f 6d 69 6e 67 20 3c 3c 3c 0a 20   @incoming <<<. 
42d0: 20 20 20 20 2a 0a 20 20 20 20 20 2a 20 43 6f 6d      *.     * Com
42e0: 70 61 63 74 73 20 7b 74 69 74 6c 65 3a 75 72 6c  pacts {title:url
42f0: 7d 20 64 69 63 74 69 6f 6e 61 72 79 20 69 6e 74  } dictionary int
4300: 6f 20 6b 65 79 3d 76 61 6c 75 65 20 66 69 65 6c  o key=value fiel
4310: 64 20 66 6f 72 20 63 75 73 74 6f 6d 20 65 6e 74  d for custom ent
4320: 72 69 65 73 2c 0a 20 20 20 20 20 2a 20 61 6e 64  ries,.     * and
4330: 20 73 65 70 61 72 61 74 65 73 20 6f 75 74 20 63   separates out c
4340: 6f 72 65 20 55 52 4c 20 66 69 65 6c 64 73 20 69  ore URL fields i
4350: 6e 74 6f 20 72 65 6c 65 61 73 65 2d 3e 20 73 74  nto release-> st
4360: 6f 72 61 67 65 2e 0a 20 20 20 20 20 2a 0a 20 20  orage..     *.  
4370: 20 20 20 2a 20 40 70 61 72 61 6d 20 20 26 72 65     * @param  &re
4380: 66 65 72 65 6e 63 65 20 20 20 24 70 72 6f 6a 65  ference   $proje
4390: 63 74 20 6f 62 6a 65 63 74 2f 61 72 72 61 79 0a  ct object/array.
43a0: 20 20 20 20 20 2a 20 40 70 61 72 61 6d 20 20 61       * @param  a
43b0: 72 72 61 79 20 20 20 20 20 20 20 20 74 69 74 6c  rray        titl
43c0: 65 20 3d 3e 20 75 72 6c 20 64 69 63 74 69 6f 6e  e => url diction
43d0: 61 72 79 0a 20 20 20 20 20 2a 0a 20 20 20 20 20  ary.     *.     
43e0: 2a 40 59 69 6b 65 73 3a 20 72 61 74 68 65 72 20  *@Yikes: rather 
43f0: 72 65 74 75 72 6e 20 5b 24 6e 65 77 2c 20 24 75  return [$new, $u
4400: 72 6c 73 5d 20 6c 69 73 74 3f 0a 20 20 20 20 20  rls] list?.     
4410: 2a 0a 20 20 20 20 20 2a 2f 0a 20 20 20 20 66 75  *.     */.    fu
4420: 6e 63 74 69 6f 6e 20 75 72 6c 73 5f 6d 61 70 28  nction urls_map(
4430: 26 24 70 72 6f 6a 65 63 74 2c 20 24 64 69 63 74  &$project, $dict
4440: 29 20 7b 0a 20 20 20 20 0a 20 20 20 20 20 20 20  ) {.    .       
4450: 20 69 66 20 28 65 6d 70 74 79 28 24 64 69 63 74   if (empty($dict
4460: 29 29 20 7b 0a 20 20 20 20 20 20 20 20 20 20 20  )) {.           
4470: 20 72 65 74 75 72 6e 3b 0a 20 20 20 20 20 20 20   return;.       
4480: 20 7d 0a 20 20 20 20 0a 20 20 20 20 20 20 20 20   }.    .        
4490: 2f 2f 20 46 69 6c 74 65 72 20 69 6e 63 6f 6d 69  // Filter incomi
44a0: 6e 67 20 55 52 4c 73 0a 20 20 20 20 20 20 20 20  ng URLs.        
44b0: 24 75 72 6c 73 20 3d 20 6e 65 77 20 69 6e 70 75  $urls = new inpu
44c0: 74 28 24 64 69 63 74 2c 20 22 75 72 6c 73 5f 64  t($dict, "urls_d
44d0: 69 63 74 22 29 3b 0a 20 20 20 20 20 20 20 20 24  ict");.        $
44e0: 75 72 6c 73 20 3d 20 24 75 72 6c 73 2d 3e 6c 69  urls = $urls->li
44f0: 73 74 2d 3e 75 72 6c 2d 3e 68 74 74 70 5b 24 75  st->url->http[$u
4500: 72 6c 73 2d 3e 6b 65 79 73 28 29 5d 3b 0a 0a 20  rls->keys()];.. 
4510: 20 20 20 20 20 20 20 2f 2f 20 55 70 64 61 74 65         // Update
4520: 20 73 74 72 75 63 74 0a 20 20 20 20 20 20 20 20   struct.        
4530: 24 6e 65 77 5f 74 65 78 74 20 3d 20 22 23 20 45  $new_text = "# E
4540: 78 70 61 6e 64 65 64 20 66 72 6f 6d 20 41 50 49  xpanded from API
4550: 20 72 65 71 75 65 73 74 5c 72 5c 6e 22 3b 0a 20   request\r\n";. 
4560: 20 20 20 20 20 20 20 24 6d 61 70 5f 63 6f 72 65         $map_core
4570: 20 3d 20 61 72 72 61 79 28 0a 20 20 20 20 20 20   = array(.      
4580: 20 20 20 20 20 20 22 68 6f 6d 65 70 61 67 65 22        "homepage"
4590: 20 3d 3e 20 22 68 6f 6d 65 70 61 67 65 22 2c 0a   => "homepage",.
45a0: 20 20 20 20 20 20 20 20 20 20 20 20 22 68 6f 6d              "hom
45b0: 65 2d 70 61 67 65 22 20 3d 3e 20 22 68 6f 6d 65  e-page" => "home
45c0: 70 61 67 65 22 2c 0a 20 20 20 20 20 20 20 20 20  page",.         
45d0: 20 20 20 22 77 65 62 73 69 74 65 22 20 3d 3e 20     "website" => 
45e0: 22 68 6f 6d 65 70 61 67 65 22 2c 0a 20 20 20 20  "homepage",.    
45f0: 20 20 20 20 20 20 20 20 22 64 6f 77 6e 6c 6f 61          "downloa
4600: 64 22 20 3d 3e 20 22 64 6f 77 6e 6c 6f 61 64 22  d" => "download"
4610: 2c 0a 20 20 20 20 20 20 20 20 20 20 20 20 22 73  ,.            "s
4620: 63 72 65 65 6e 73 68 6f 74 22 20 3d 3e 20 22 69  creenshot" => "i
4630: 6d 61 67 65 22 2c 0a 20 20 20 20 20 20 20 20 20  mage",.         
4640: 20 20 20 22 63 68 61 6e 67 65 6c 6f 67 22 20 3d     "changelog" =
4650: 3e 20 22 61 75 74 6f 75 70 64 61 74 65 5f 75 72  > "autoupdate_ur
4660: 6c 22 2c 0a 20 20 20 20 20 20 20 20 29 3b 0a 20  l",.        );. 
4670: 20 20 20 20 20 20 20 66 6f 72 65 61 63 68 20 28         foreach (
4680: 24 75 72 6c 73 20 61 73 20 24 6c 61 62 65 6c 20  $urls as $label 
4690: 3d 3e 20 24 75 72 6c 29 20 7b 0a 0a 20 20 20 20  => $url) {..    
46a0: 20 20 20 20 20 20 20 20 2f 2f 20 52 65 6d 6f 76          // Remov
46b0: 65 20 6e 6f 6e 2d 61 6c 70 68 61 6e 75 6d 65 72  e non-alphanumer
46c0: 69 63 20 63 68 61 72 61 63 74 65 72 73 0a 20 20  ic characters.  
46d0: 20 20 20 20 20 20 20 20 20 20 24 6c 61 62 65 6c            $label
46e0: 20 3d 20 74 72 69 6d 28 70 72 65 67 5f 72 65 70   = trim(preg_rep
46f0: 6c 61 63 65 28 22 2f 5c 57 2b 2f 22 2c 20 22 2d  lace("/\W+/", "-
4700: 22 2c 20 24 6c 61 62 65 6c 29 2c 20 22 2d 22 29  ", $label), "-")
4710: 3b 0a 20 20 20 20 20 20 20 20 20 20 20 20 24 6c  ;.            $l
4720: 6f 77 65 72 20 3d 20 73 74 72 74 6f 6c 6f 77 65  ower = strtolowe
4730: 72 28 24 6c 61 62 65 6c 29 3b 0a 0a 20 20 20 20  r($label);..    
4740: 20 20 20 20 20 20 20 20 2f 2f 20 53 70 6c 69 74          // Split
4750: 20 68 6f 6d 65 70 61 67 65 2c 20 64 6f 77 6e 6c   homepage, downl
4760: 6f 61 64 20 55 52 4c 20 69 6e 74 6f 20 73 65 70  oad URL into sep
4770: 61 72 61 74 65 20 66 69 65 6c 64 73 2c 0a 20 20  arate fields,.  
4780: 20 20 20 20 20 20 20 20 20 20 69 66 20 28 69 73            if (is
4790: 73 65 74 28 24 6d 61 70 5f 63 6f 72 65 5b 24 6c  set($map_core[$l
47a0: 6f 77 65 72 5d 29 29 20 7b 0a 20 20 20 20 20 20  ower])) {.      
47b0: 20 20 20 20 20 20 20 20 20 20 69 66 20 28 24 6c            if ($l
47c0: 6f 77 65 72 20 3d 3d 20 22 69 6d 61 67 65 22 20  ower == "image" 
47d0: 61 6e 64 20 21 70 72 65 67 5f 6d 61 74 63 68 28  and !preg_match(
47e0: 22 2f 28 6a 70 65 3f 67 7c 67 69 66 7c 70 6e 67  "/(jpe?g|gif|png
47f0: 7c 77 65 62 70 29 28 24 7c 5b 3f 5d 29 2f 69 22  |webp)($|[?])/i"
4800: 2c 20 24 75 72 6c 29 29 20 7b 0a 20 20 20 20 20  , $url)) {.     
4810: 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 63                 c
4820: 6f 6e 74 69 6e 75 65 3b 0a 20 20 20 20 20 20 20  ontinue;.       
4830: 20 20 20 20 20 20 20 20 20 7d 0a 20 20 20 20 20           }.     
4840: 20 20 20 20 20 20 20 20 20 20 20 24 70 72 6f 6a             $proj
4850: 65 63 74 5b 24 6c 6f 77 65 72 5d 20 3d 20 24 75  ect[$lower] = $u
4860: 72 6c 3b 0a 20 20 20 20 20 20 20 20 20 20 20 20  rl;.            
4870: 7d 0a 20 20 20 20 20 20 20 20 20 20 20 20 2f 2f  }.            //
4880: 20 57 68 69 6c 65 20 72 65 6d 61 69 6e 69 6e 67   While remaining
4890: 20 67 6f 20 69 6e 74 6f 20 60 75 72 6c 73 60 20   go into `urls` 
48a0: 6b 65 79 3d 76 61 6c 75 65 20 62 6c 6f 63 6b 2c  key=value block,
48b0: 20 72 65 74 61 69 6e 20 63 61 73 65 2d 73 65 6e   retain case-sen
48c0: 73 69 74 69 76 69 74 79 20 68 65 72 65 0a 20 20  sitivity here.  
48d0: 20 20 20 20 20 20 20 20 20 20 65 6c 73 65 20 7b            else {
48e0: 0a 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20  .               
48f0: 20 24 6e 65 77 5f 74 65 78 74 20 2e 3d 20 22 24   $new_text .= "$
4900: 6c 61 62 65 6c 20 3d 20 24 75 72 6c 5c 72 5c 6e  label = $url\r\n
4910: 22 3b 0a 20 20 20 20 20 20 20 20 20 20 20 20 7d  ";.            }
4920: 0a 20 20 20 20 20 20 20 20 7d 0a 0a 20 20 20 20  .        }..    
4930: 20 20 20 20 2f 2f 20 6f 76 65 72 77 72 69 74 65      // overwrite
4940: 20 69 6e 63 6f 6d 69 6e 67 20 64 69 63 74 0a 20   incoming dict. 
4950: 20 20 20 20 20 20 20 24 70 72 6f 6a 65 63 74 5b         $project[
4960: 22 75 72 6c 73 22 5d 20 3d 20 24 6e 65 77 5f 74  "urls"] = $new_t
4970: 65 78 74 3b 0a 20 20 20 20 7d 0a 20 20 20 20 0a  ext;.    }.    .
4980: 20 20 20 20 0a 20 20 20 20 2f 2a 2a 0a 20 20 20      .    /**.   
4990: 20 20 2a 20 50 65 72 66 6f 72 6d 20 70 61 72 74    * Perform part
49a0: 69 61 6c 20 75 70 64 61 74 65 0a 20 20 20 20 20  ial update.     
49b0: 2a 0a 20 20 20 20 20 2a 20 40 61 75 74 68 2d 72  *.     * @auth-r
49c0: 65 71 75 69 72 65 64 0a 20 20 20 20 20 2a 0a 20  equired.     *. 
49d0: 20 20 20 20 2a 2f 0a 20 20 20 20 66 75 6e 63 74      */.    funct
49e0: 69 6f 6e 20 69 6e 73 65 72 74 28 24 70 72 6f 6a  ion insert($proj
49f0: 65 63 74 2c 20 24 6e 65 77 2c 20 24 66 6c 61 67  ect, $new, $flag
4a00: 73 3d 5b 5d 29 20 7b 0a 0a 20 20 20 20 20 20 20  s=[]) {..       
4a10: 20 2f 2f 20 57 72 69 74 65 20 70 65 72 6d 69 73   // Write permis
4a20: 73 69 6f 6e 73 20 72 65 71 75 69 72 65 64 20 6f  sions required o
4a30: 62 76 69 6f 75 73 6c 79 2e 0a 20 20 20 20 20 20  bviously..      
4a40: 20 20 24 74 68 69 73 2d 3e 72 65 71 75 69 72 65    $this->require
4a50: 73 5f 70 65 72 6d 69 73 73 69 6f 6e 28 24 70 72  s_permission($pr
4a60: 6f 6a 65 63 74 29 3b 0a 20 0a 20 20 20 20 20 20  oject);. .      
4a70: 20 20 2f 2f 20 4c 6f 67 20 64 61 74 61 0a 20 20    // Log data.  
4a80: 20 20 20 20 20 20 24 74 68 69 73 2d 3e 6c 6f 67        $this->log
4a90: 28 24 6e 65 77 2c 20 22 2f 2a 20 2b 2b 20 53 54  ($new, "/* ++ ST
4aa0: 4f 52 45 20 44 41 54 41 20 2a 2f 22 29 3b 0a 0a  ORE DATA */");..
4ab0: 20 20 20 20 20 20 20 20 2f 2f 20 41 64 64 20 6e          // Add n
4ac0: 65 77 20 66 69 65 6c 64 73 20 74 6f 20 24 70 72  ew fields to $pr
4ad0: 6f 6a 65 63 74 0a 20 20 20 20 20 20 20 20 24 66  oject.        $f
4ae0: 6c 61 67 65 5b 22 73 75 62 6d 69 74 74 65 72 5f  lage["submitter_
4af0: 6f 70 65 6e 69 64 22 5d 20 3d 20 24 5f 53 45 52  openid"] = $_SER
4b00: 56 45 52 2d 3e 74 65 78 74 5b 22 48 54 54 50 5f  VER->text["HTTP_
4b10: 55 53 45 52 5f 41 47 45 4e 54 22 5d 3b 0a 20 20  USER_AGENT"];.  
4b20: 20 20 20 20 20 20 24 66 6c 61 67 73 5b 22 76 69        $flags["vi
4b30: 61 22 5d 20 3d 20 22 61 70 69 22 3b 0a 20 20 20  a"] = "api";.   
4b40: 20 20 20 20 20 24 70 72 6f 6a 65 63 74 2d 3e 75       $project->u
4b50: 70 64 61 74 65 28 61 72 72 61 79 5f 66 69 6c 74  pdate(array_filt
4b60: 65 72 28 24 6e 65 77 2c 20 22 73 74 72 6c 65 6e  er($new, "strlen
4b70: 22 29 2c 20 24 66 6c 61 67 73 2c 20 5b 5d 2c 20  "), $flags, [], 
4b80: 54 52 55 45 29 3b 0a 0a 20 20 20 20 20 20 20 20  TRUE);..        
4b90: 2f 2f 20 53 74 6f 72 65 20 6f 72 20 72 65 74 75  // Store or retu
4ba0: 72 6e 20 4a 53 4f 4e 20 41 50 49 20 65 72 72 6f  rn JSON API erro
4bb0: 72 2e 0a 20 20 20 20 20 20 20 20 72 65 74 75 72  r..        retur
4bc0: 6e 20 28 24 70 72 6f 6a 65 63 74 2d 3e 73 74 6f  n ($project->sto
4bd0: 72 65 28 29 20 61 6e 64 20 28 68 65 61 64 65 72  re() and (header
4be0: 28 22 53 74 61 74 75 73 3a 20 32 30 31 20 43 72  ("Status: 201 Cr
4bf0: 65 61 74 65 64 22 29 20 2b 20 31 29 29 0a 20 20  eated") + 1)).  
4c00: 20 20 20 20 20 20 20 20 20 20 20 3f 20 61 72 72             ? arr
4c10: 61 79 28 22 73 75 63 63 65 73 73 22 20 3d 3e 20  ay("success" => 
4c20: 54 52 55 45 29 0a 20 20 20 20 20 20 20 20 20 20  TRUE).          
4c30: 20 20 20 3a 20 24 74 68 69 73 2d 3e 65 72 72 6f     : $this->erro
4c40: 72 5f 65 78 69 74 28 4e 55 4c 4c 2c 20 27 35 30  r_exit(NULL, '50
4c50: 30 20 49 6e 74 65 72 6e 61 6c 20 49 73 73 75 65  0 Internal Issue
4c60: 73 27 2c 20 22 44 61 74 61 62 61 73 65 20 6d 69  s', "Database mi
4c70: 73 74 61 6b 65 22 29 3b 0a 20 20 20 20 7d 0a 20  stake");.    }. 
4c80: 20 20 20 0a 20 20 20 20 0a 20 20 20 20 2f 2a 2a     .    .    /**
4c90: 0a 20 20 20 20 20 2a 20 53 74 72 69 70 20 64 6f  .     * Strip do
4ca0: 77 6e 20 72 61 77 20 70 72 6f 6a 65 63 74 20 64  wn raw project d
4cb0: 61 74 61 20 66 6f 72 20 61 62 73 65 6e 74 20 61  ata for absent a
4cc0: 75 74 68 5f 63 6f 64 65 0a 20 20 20 20 20 2a 20  uth_code.     * 
4cd0: 69 6e 20 72 65 61 64 2f 47 45 54 20 72 65 71 75  in read/GET requ
4ce0: 65 73 74 73 2e 0a 20 20 20 20 20 2a 0a 20 20 20  ests..     *.   
4cf0: 20 20 2a 2f 0a 20 20 20 20 66 75 6e 63 74 69 6f    */.    functio
4d00: 6e 20 61 75 74 68 5f 66 69 6c 74 65 72 28 24 64  n auth_filter($d
4d10: 61 74 61 29 20 7b 0a 20 20 20 20 20 20 20 20 69  ata) {.        i
4d20: 66 20 28 21 24 74 68 69 73 2d 3e 69 73 5f 61 75  f (!$this->is_au
4d30: 74 68 6f 72 69 7a 65 64 28 24 64 61 74 61 29 29  thorized($data))
4d40: 20 7b 0a 20 20 20 20 20 20 20 20 20 20 20 20 75   {.            u
4d50: 6e 73 65 74 28 0a 20 20 20 20 20 20 20 20 20 20  nset(.          
4d60: 20 20 20 20 20 20 24 64 61 74 61 5b 22 6c 6f 63        $data["loc
4d70: 6b 22 5d 2c 0a 20 20 20 20 20 20 20 20 20 20 20  k"],.           
4d80: 20 20 20 20 20 24 64 61 74 61 5b 22 73 75 62 6d       $data["subm
4d90: 69 74 74 65 72 5f 6f 70 65 6e 69 64 22 5d 2c 0a  itter_openid"],.
4da0: 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20                  
4db0: 23 24 64 61 74 61 5b 22 73 75 62 6d 69 74 74 65  #$data["submitte
4dc0: 72 22 5d 2c 0a 20 20 20 20 20 20 20 20 20 20 20  r"],.           
4dd0: 20 20 20 20 20 24 64 61 74 61 5b 22 73 75 62 6d       $data["subm
4de0: 69 74 74 65 72 5f 69 6d 61 67 65 22 5d 2c 0a 20  itter_image"],. 
4df0: 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 24                 $
4e00: 64 61 74 61 5b 22 68 69 64 64 65 6e 22 5d 2c 20  data["hidden"], 
4e10: 24 64 61 74 61 5b 22 64 65 6c 65 74 65 64 22 5d  $data["deleted"]
4e20: 2c 20 24 64 61 74 61 5b 22 66 6c 61 67 22 5d 2c  , $data["flag"],
4e30: 0a 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20  .               
4e40: 20 24 64 61 74 61 5b 22 73 6f 63 69 61 6c 5f 6c   $data["social_l
4e50: 69 6e 6b 73 22 5d 2c 0a 20 20 20 20 20 20 20 20  inks"],.        
4e60: 20 20 20 20 20 20 20 20 24 64 61 74 61 5b 22 61          $data["a
4e70: 75 74 6f 75 70 64 61 74 65 5f 6d 6f 64 75 6c 65  utoupdate_module
4e80: 22 5d 2c 20 24 64 61 74 61 5b 22 61 75 74 6f 75  "], $data["autou
4e90: 70 64 61 74 65 5f 64 65 6c 61 79 22 5d 2c 0a 20  pdate_delay"],. 
4ea0: 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 24                 $
4eb0: 64 61 74 61 5b 22 61 75 74 6f 75 70 64 61 74 65  data["autoupdate
4ec0: 5f 72 65 67 65 78 22 5d 2c 0a 20 20 20 20 20 20  _regex"],.      
4ed0: 20 20 20 20 20 20 20 20 20 20 24 64 61 74 61 5b            $data[
4ee0: 22 65 64 69 74 6f 72 5f 6e 6f 74 65 22 5d 2c 0a  "editor_note"],.
4ef0: 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20                  
4f00: 24 64 61 74 61 5b 22 74 5f 63 68 61 6e 67 65 64  $data["t_changed
4f10: 22 5d 0a 20 20 20 20 20 20 20 20 20 20 20 20 29  "].            )
4f20: 3b 0a 20 20 20 20 20 20 20 20 7d 0a 20 20 20 20  ;.        }.    
4f30: 20 20 20 20 72 65 74 75 72 6e 20 24 64 61 74 61      return $data
4f40: 3b 0a 20 20 20 20 7d 0a 0a 20 20 20 20 0a 20 20  ;.    }..    .  
4f50: 20 20 2f 2a 2a 0a 20 20 20 20 20 2a 20 50 72 65    /**.     * Pre
4f60: 76 65 6e 74 20 66 75 72 74 68 65 72 20 6f 70 65  vent further ope
4f70: 72 61 74 69 6f 6e 73 20 66 6f 72 20 28 77 72 69  rations for (wri
4f80: 74 65 29 20 72 65 71 75 65 73 74 73 20 74 68 61  te) requests tha
4f90: 74 0a 20 20 20 20 20 2a 20 61 63 74 75 61 6c 6c  t.     * actuall
4fa0: 79 20 52 45 51 55 49 52 45 20 61 20 76 61 6c 69  y REQUIRE a vali
4fb0: 64 20 61 75 74 68 6f 72 69 7a 61 74 69 6f 6e 20  d authorization 
4fc0: 74 6f 6b 65 6e 2e 0a 20 20 20 20 20 2a 0a 20 20  token..     *.  
4fd0: 20 20 20 2a 20 40 65 78 69 74 20 69 66 20 75 6e     * @exit if un
4fe0: 61 75 74 68 6f 72 69 7a 65 64 0a 20 20 20 20 20  authorized.     
4ff0: 2a 0a 20 20 20 20 20 2a 2f 0a 20 20 20 20 66 75  *.     */.    fu
5000: 6e 63 74 69 6f 6e 20 72 65 71 75 69 72 65 73 5f  nction requires_
5010: 70 65 72 6d 69 73 73 69 6f 6e 28 24 64 61 74 61  permission($data
5020: 29 20 7b 0a 20 20 20 20 20 20 20 20 69 66 20 28  ) {.        if (
5030: 24 74 68 69 73 2d 3e 69 73 5f 61 75 74 68 6f 72  $this->is_author
5040: 69 7a 65 64 28 24 64 61 74 61 29 29 20 7b 0a 20  ized($data)) {. 
5050: 20 20 20 20 20 20 20 20 20 20 20 72 65 74 75 72             retur
5060: 6e 20 24 64 61 74 61 3b 0a 20 20 20 20 20 20 20  n $data;.       
5070: 20 7d 0a 20 20 20 20 20 20 20 20 24 74 68 69 73   }.        $this
5080: 2d 3e 65 72 72 6f 72 5f 65 78 69 74 28 4e 55 4c  ->error_exit(NUL
5090: 4c 2c 20 22 34 30 31 20 55 6e 61 75 74 68 6f 72  L, "401 Unauthor
50a0: 69 7a 65 64 22 2c 20 22 4e 6f 20 6d 61 74 63 68  ized", "No match
50b0: 69 6e 67 20 41 50 49 20 61 75 74 68 5f 74 6f 6b  ing API auth_tok
50c0: 65 6e 20 68 61 73 68 2e 20 41 64 64 20 61 20 63  en hash. Add a c
50d0: 72 79 70 74 28 33 29 20 70 61 73 73 77 6f 72 64  rypt(3) password
50e0: 20 69 6e 20 79 6f 75 72 20 66 72 65 73 68 63 6f   in your freshco
50f0: 64 65 2e 63 6c 75 62 20 70 72 6f 6a 65 63 74 20  de.club project 
5100: 65 6e 74 72 69 65 73 20 60 6c 6f 63 6b 60 20 66  entries `lock` f
5110: 69 65 6c 64 2c 20 63 6f 6d 6d 61 2d 64 65 6c 69  ield, comma-deli
5120: 6d 69 74 65 64 20 74 6f 20 79 6f 75 72 20 4f 70  mited to your Op
5130: 65 6e 49 44 20 68 61 6e 64 6c 65 2e 20 53 65 65  enID handle. See
5140: 20 68 74 74 70 3a 2f 2f 66 6f 73 73 69 6c 2e 69   http://fossil.i
5150: 6e 63 6c 75 64 65 2d 6f 6e 63 65 2e 6f 72 67 2f  nclude-once.org/
5160: 66 72 65 73 68 63 6f 64 65 2f 77 69 6b 69 2f 41  freshcode/wiki/A
5170: 50 49 32 22 29 3b 0a 20 20 20 20 7d 0a 20 20 20  PI2");.    }.   
5180: 20 0a 20 20 20 20 0a 20 20 20 20 2f 2a 2a 0a 20   .    .    /**. 
5190: 20 20 20 20 2a 20 52 65 71 75 69 72 65 73 20 61      * Requires a
51a0: 20 76 61 6c 69 64 20 63 6c 69 65 6e 74 20 53 53   valid client SS
51b0: 4c 20 63 65 72 74 69 66 69 63 61 74 65 20 66 6f  L certificate fo
51c0: 72 20 43 52 45 41 54 45 20 72 65 71 75 65 73 74  r CREATE request
51d0: 73 2e 0a 20 20 20 20 20 2a 20 43 75 72 72 65 6e  s..     * Curren
51e0: 74 6c 79 20 6a 75 73 74 20 63 68 65 63 6b 73 20  tly just checks 
51f0: 74 68 65 20 73 65 72 69 61 6c 20 49 44 20 61 67  the serial ID ag
5200: 61 69 6e 73 74 20 61 20 6c 69 73 74 20 6f 66 20  ainst a list of 
5210: 76 61 6c 69 64 20 73 74 75 62 73 2e 0a 20 20 20  valid stubs..   
5220: 20 20 2a 0a 20 20 20 20 20 2a 20 40 65 78 69 74    *.     * @exit
5230: 20 69 66 20 75 6e 61 75 74 68 6f 72 69 7a 65 64   if unauthorized
5240: 0a 20 20 20 20 20 2a 0a 20 20 20 20 20 2a 2f 0a  .     *.     */.
5250: 20 20 20 20 66 75 6e 63 74 69 6f 6e 20 72 65 71      function req
5260: 75 69 72 65 73 5f 73 73 6c 5f 63 65 72 74 28 29  uires_ssl_cert()
5270: 20 7b 0a 20 20 20 20 20 20 20 20 24 73 65 72 69   {.        $seri
5280: 61 6c 20 3d 20 24 5f 53 45 52 56 45 52 2d 3e 6e  al = $_SERVER->n
5290: 61 6d 65 2d 3e 61 73 63 69 69 2d 3e 62 61 73 65  ame->ascii->base
52a0: 6e 61 6d 65 2d 3e 73 74 72 74 6f 75 70 70 65 72  name->strtoupper
52b0: 5b 27 53 53 4c 5f 43 4c 49 45 4e 54 5f 4d 5f 53  ['SSL_CLIENT_M_S
52c0: 45 52 49 41 4c 27 5d 3b 0a 20 20 20 20 20 20 20  ERIAL'];.       
52d0: 20 24 72 65 6d 61 69 6e 20 3d 20 24 5f 53 45 52   $remain = $_SER
52e0: 56 45 52 2d 3e 69 6e 74 5b 27 53 53 4c 5f 43 4c  VER->int['SSL_CL
52f0: 49 45 4e 54 5f 56 5f 52 45 4d 41 49 4e 27 5d 3b  IENT_V_REMAIN'];
5300: 0a 20 20 20 20 20 20 20 20 69 66 20 28 73 74 72  .        if (str
5310: 6c 65 6e 28 24 73 65 72 69 61 6c 29 20 61 6e 64  len($serial) and
5320: 20 28 24 72 65 6d 61 69 6e 20 3e 3d 20 30 29 20   ($remain >= 0) 
5330: 61 6e 64 20 66 69 6c 65 5f 65 78 69 73 74 73 28  and file_exists(
5340: 22 63 6f 6e 66 69 67 2f 63 65 72 74 2f 24 73 65  "config/cert/$se
5350: 72 69 61 6c 22 29 29 20 7b 0a 20 20 20 20 20 20  rial")) {.      
5360: 20 20 20 20 20 20 72 65 74 75 72 6e 20 54 52 55        return TRU
5370: 45 3b 0a 20 20 20 20 20 20 20 20 7d 0a 20 20 20  E;.        }.   
5380: 20 20 20 20 20 24 74 68 69 73 2d 3e 65 72 72 6f       $this->erro
5390: 72 5f 65 78 69 74 28 24 73 65 72 69 61 6c 2c 20  r_exit($serial, 
53a0: 22 34 39 35 20 43 65 72 74 20 45 72 72 6f 72 22  "495 Cert Error"
53b0: 2c 20 22 55 6e 72 65 67 69 73 74 65 72 65 64 20  , "Unregistered 
53c0: 6f 72 20 65 78 70 69 72 65 64 20 53 53 4c 20 63  or expired SSL c
53d0: 65 72 74 69 66 69 63 61 74 65 2e 20 50 6c 65 61  ertificate. Plea
53e0: 73 65 20 75 73 65 20 74 68 65 20 64 65 66 61 75  se use the defau
53f0: 6c 74 20 60 68 74 74 70 3a 2f 2f 66 6f 73 73 69  lt `http://fossi
5400: 6c 2e 69 6e 63 6c 75 64 65 2d 6f 6e 63 65 2e 6f  l.include-once.o
5410: 72 67 2f 66 72 65 73 68 63 6f 64 65 2f 64 6f 63  rg/freshcode/doc
5420: 2f 74 72 75 6e 6b 2f 64 6f 63 2f 73 75 62 6d 69  /trunk/doc/submi
5430: 74 2e 70 65 6d 60 20 66 72 6f 6d 20 74 68 65 20  t.pem` from the 
5440: 57 69 6b 69 2e 22 29 3b 0a 20 20 20 20 7d 0a 0a  Wiki.");.    }..
5450: 0a 20 20 20 20 2f 2a 2a 0a 20 20 20 20 20 2a 20  .    /**.     * 
5460: 54 68 65 20 60 6c 6f 63 6b 60 20 66 69 65 6c 64  The `lock` field
5470: 20 75 73 75 61 6c 6c 79 20 63 6f 6e 74 61 69 6e   usually contain
5480: 73 20 6f 6e 65 20 6f 72 20 6d 6f 72 65 20 4f 70  s one or more Op
5490: 65 6e 49 44 20 75 72 6c 73 2e 20 49 74 27 73 0a  enID urls. It's.
54a0: 20 20 20 20 20 2a 20 61 20 63 6f 6d 6d 61 2d 64       * a comma-d
54b0: 65 6c 69 6d 69 74 65 64 20 66 69 65 6c 64 2e 0a  elimited field..
54c0: 20 20 20 20 20 2a 0a 20 20 20 20 20 2a 20 55 73       *.     * Us
54d0: 69 6e 67 20 74 68 65 20 41 50 49 20 61 64 64 69  ing the API addi
54e0: 74 69 6f 6e 61 6c 6c 79 20 72 65 71 75 69 72 65  tionally require
54f0: 73 20 61 20 70 61 73 73 77 6f 72 64 20 68 61 73  s a password has
5500: 68 2c 20 61 73 20 69 6e 20 63 72 79 70 74 28 33  h, as in crypt(3
5510: 29 0a 20 20 20 20 20 2a 20 6f 72 20 60 6f 70 65  ).     * or `ope
5520: 6e 73 73 6c 20 70 61 73 73 77 64 20 2d 31 60 20  nssl passwd -1` 
5530: 6f 72 20 50 48 50 73 20 70 61 73 73 77 6f 72 64  or PHPs password
5540: 5f 68 61 73 68 28 29 2c 20 74 6f 20 62 65 20 70  _hash(), to be p
5550: 72 65 73 65 6e 74 2e 0a 20 20 20 20 20 2a 0a 20  resent..     *. 
5560: 20 20 20 20 2a 20 49 74 20 77 69 6c 6c 20 73 69      * It will si
5570: 6d 70 6c 79 20 62 65 20 63 6f 6d 70 61 72 65 64  mply be compared
5580: 20 61 67 61 69 6e 73 74 20 74 68 65 20 3f 61 75   against the ?au
5590: 74 68 5f 63 6f 64 65 3d 20 70 61 72 61 6d 65 74  th_code= paramet
55a0: 65 72 2e 0a 20 20 20 20 20 2a 0a 20 20 20 20 20  er..     *.     
55b0: 2a 2f 0a 20 20 20 20 66 75 6e 63 74 69 6f 6e 20  */.    function 
55c0: 69 73 5f 61 75 74 68 6f 72 69 7a 65 64 28 24 64  is_authorized($d
55d0: 61 74 61 29 20 7b 0a 20 20 20 20 20 20 20 20 66  ata) {.        f
55e0: 6f 72 65 61 63 68 20 28 70 72 65 67 5f 67 72 65  oreach (preg_gre
55f0: 70 28 22 2f 5e 5b 5e 3a 5d 2b 24 2f 22 2c 20 70  p("/^[^:]+$/", p
5600: 5f 63 73 76 28 24 64 61 74 61 5b 22 6c 6f 63 6b  _csv($data["lock
5610: 22 5d 29 29 20 61 73 20 24 68 61 73 68 29 20 7b  "])) as $hash) {
5620: 0a 20 20 20 20 20 20 20 20 20 20 20 20 69 66 20  .            if 
5630: 28 70 61 73 73 77 6f 72 64 5f 76 65 72 69 66 79  (password_verify
5640: 28 24 74 68 69 73 2d 3e 61 75 74 68 5f 63 6f 64  ($this->auth_cod
5650: 65 2c 20 24 68 61 73 68 29 29 20 7b 0a 20 20 20  e, $hash)) {.   
5660: 20 20 20 20 20 20 20 20 20 20 20 20 20 72 65 74               ret
5670: 75 72 6e 20 54 52 55 45 3b 0a 20 20 20 20 20 20  urn TRUE;.      
5680: 20 20 20 20 20 20 7d 0a 20 20 20 20 20 20 20 20        }.        
5690: 7d 0a 20 20 20 20 20 20 20 20 72 65 74 75 72 6e  }.        return
56a0: 20 46 41 4c 53 45 3b 0a 20 20 20 20 7d 0a 0a 0a   FALSE;.    }...
56b0: 20 20 20 20 2f 2a 2a 0a 20 20 20 20 20 2a 20 4a      /**.     * J
56c0: 53 4f 4e 20 65 6e 63 6f 64 65 20 61 6e 64 20 66  SON encode and f
56d0: 69 6e 69 73 68 2e 0a 20 20 20 20 20 2a 0a 20 20  inish..     *.  
56e0: 20 20 20 2a 2f 0a 20 20 20 20 66 75 6e 63 74 69     */.    functi
56f0: 6f 6e 20 6a 73 6f 6e 5f 65 78 69 74 28 24 64 61  on json_exit($da
5700: 74 61 29 20 7b 0a 20 20 20 20 20 20 20 20 68 65  ta) {.        he
5710: 61 64 65 72 28 22 43 6f 6e 74 65 6e 74 2d 54 79  ader("Content-Ty
5720: 70 65 32 3a 20 6a 73 6f 6e 2f 76 6e 64 2e 66 72  pe2: json/vnd.fr
5730: 65 65 63 6f 64 65 2e 63 6f 6d 3b 20 76 65 72 73  eecode.com; vers
5740: 69 6f 6e 3d 33 3b 20 63 68 61 72 73 65 74 3d 55  ion=3; charset=U
5750: 54 46 2d 38 22 29 3b 0a 20 20 20 20 20 20 20 20  TF-8");.        
5760: 68 65 61 64 65 72 28 22 43 6f 6e 74 65 6e 74 2d  header("Content-
5770: 54 79 70 65 3a 20 61 70 70 6c 69 63 61 74 69 6f  Type: applicatio
5780: 6e 2f 6a 73 6f 6e 22 29 3b 0a 20 20 20 20 20 20  n/json");.      
5790: 20 20 24 74 68 69 73 2d 3e 6c 6f 67 28 24 64 61    $this->log($da
57a0: 74 61 2c 20 22 2f 2a 20 3e 3e 20 52 45 53 50 4f  ta, "/* >> RESPO
57b0: 4e 53 45 20 2a 2f 22 29 3b 0a 20 20 20 20 20 20  NSE */");.      
57c0: 20 20 24 64 61 74 61 5b 22 5c 24 66 65 65 64 2d    $data["\$feed-
57d0: 6c 69 63 65 6e 73 65 22 5d 20 3d 20 22 43 43 2d  license"] = "CC-
57e0: 42 59 2d 53 41 20 33 2e 30 22 3b 0a 20 20 20 20  BY-SA 3.0";.    
57f0: 20 20 20 20 24 64 61 74 61 5b 22 5c 24 66 65 65      $data["\$fee
5800: 64 2d 6f 72 69 67 69 6e 22 5d 20 3d 20 22 68 74  d-origin"] = "ht
5810: 74 70 3a 2f 2f 66 72 65 73 68 63 6f 64 65 2e 63  tp://freshcode.c
5820: 6c 75 62 2f 22 3b 0a 20 20 20 20 20 20 20 20 65  lub/";.        e
5830: 78 69 74 28 0a 20 20 20 20 20 20 20 20 20 20 20  xit(.           
5840: 20 6a 73 6f 6e 5f 65 6e 63 6f 64 65 28 24 64 61   json_encode($da
5850: 74 61 2c 20 4a 53 4f 4e 5f 50 52 45 54 54 59 5f  ta, JSON_PRETTY_
5860: 50 52 49 4e 54 20 7c 20 4a 53 4f 4e 5f 55 4e 45  PRINT | JSON_UNE
5870: 53 43 41 50 45 44 5f 53 4c 41 53 48 45 53 29 0a  SCAPED_SLASHES).
5880: 20 20 20 20 20 20 20 20 29 3b 0a 20 20 20 20 7d          );.    }
5890: 0a 0a 0a 20 20 20 20 2f 2a 2a 0a 20 20 20 20 20  ...    /**.     
58a0: 2a 20 42 61 69 6c 20 77 69 74 68 20 65 72 72 6f  * Bail with erro
58b0: 72 20 72 65 73 70 6f 6e 73 65 2e 0a 20 20 20 20  r response..    
58c0: 20 2a 0a 20 20 20 20 20 2a 2f 0a 20 20 20 20 66   *.     */.    f
58d0: 75 6e 63 74 69 6f 6e 20 65 72 72 6f 72 5f 65 78  unction error_ex
58e0: 69 74 28 24 64 61 74 61 2c 20 24 68 74 74 70 20  it($data, $http 
58f0: 3d 20 22 35 30 33 20 55 6e 61 76 61 69 6c 61 62  = "503 Unavailab
5900: 6c 65 22 2c 20 24 6a 73 6f 6e 20 3d 20 22 75 6e  le", $json = "un
5910: 6b 6e 6f 77 6e 20 6d 65 74 68 6f 64 22 29 20 7b  known method") {
5920: 0a 20 20 20 20 20 20 20 20 68 65 61 64 65 72 28  .        header(
5930: 22 53 74 61 74 75 73 3a 20 24 68 74 74 70 22 29  "Status: $http")
5940: 3b 0a 20 20 20 20 20 20 20 20 24 74 68 69 73 2d  ;.        $this-
5950: 3e 6a 73 6f 6e 5f 65 78 69 74 28 5b 22 65 72 72  >json_exit(["err
5960: 6f 72 22 20 3d 3e 20 22 24 6a 73 6f 6e 22 2c 20  or" => "$json", 
5970: 22 70 72 6f 6a 65 63 74 22 20 3d 3e 20 5b 22 6e  "project" => ["n
5980: 61 6d 65 22 20 3d 3e 20 4e 55 4c 4c 5d 2c 20 22  ame" => NULL], "
5990: 5c 24 64 61 74 61 22 20 3d 3e 20 24 64 61 74 61  \$data" => $data
59a0: 5d 29 3b 0a 20 20 20 20 7d 0a 0a 7d 0a 0a 0a 0a  ]);.    }..}....
59b0: 3f 3e                                            ?>