SiteApi.hx 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280
  1. /*
  2. * Copyright (C)2005-2012 Haxe Foundation
  3. *
  4. * Permission is hereby granted, free of charge, to any person obtaining a
  5. * copy of this software and associated documentation files (the "Software"),
  6. * to deal in the Software without restriction, including without limitation
  7. * the rights to use, copy, modify, merge, publish, distribute, sublicense,
  8. * and/or sell copies of the Software, and to permit persons to whom the
  9. * Software is furnished to do so, subject to the following conditions:
  10. *
  11. * The above copyright notice and this permission notice shall be included in
  12. * all copies or substantial portions of the Software.
  13. *
  14. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  17. * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  18. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  19. * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
  20. * DEALINGS IN THE SOFTWARE.
  21. */
  22. package tools.haxelib;
  23. import tools.haxelib.Data;
  24. #if haxelib_site
  25. import tools.haxelib.SiteDb;
  26. #end
  27. class SiteApi {
  28. var db : sys.db.Connection;
  29. public function new( db ) {
  30. this.db = db;
  31. }
  32. public function search( word : String ) : List<{ id : Int, name : String }> {
  33. return Project.manager.containing(word);
  34. }
  35. public function infos( project : String ) : ProjectInfos {
  36. var p = Project.manager.search({ name : project }).first();
  37. if( p == null )
  38. throw "No such Project : "+project;
  39. var vl = Version.manager.search({ project : p.id });
  40. var versions = new Array();
  41. for( v in vl )
  42. versions.push({ name : v.name, comments : v.comments, date : v.date });
  43. return {
  44. name : p.name,
  45. curversion : if( p.version == null ) null else p.version.name,
  46. desc : p.description,
  47. versions : versions,
  48. owner : p.owner.name,
  49. website : p.website,
  50. license : p.license,
  51. tags : Tag.manager.search({ project : p.id }).map(function(t) return t.tag),
  52. };
  53. }
  54. public function user( name : String ) : UserInfos {
  55. var u = User.manager.search({ name : name }).first();
  56. if( u == null )
  57. throw "No such user : "+name;
  58. var pl = Project.manager.search({ owner : u.id });
  59. var projects = new Array();
  60. for( p in pl )
  61. projects.push(p.name);
  62. return {
  63. name : u.name,
  64. fullname : u.fullname,
  65. email : u.email,
  66. projects : projects,
  67. };
  68. }
  69. public function register( name : String, pass : String, mail : String, fullname : String ) : Bool {
  70. if( !Data.alphanum.match(name) )
  71. throw "Invalid user name, please use alphanumeric characters";
  72. if( name.length < 3 )
  73. throw "User name must be at least 3 characters";
  74. var u = new User();
  75. u.name = name;
  76. u.pass = pass;
  77. u.email = mail;
  78. u.fullname = fullname;
  79. u.insert();
  80. return null;
  81. }
  82. public function isNewUser( name : String ) : Bool {
  83. return User.manager.search({ name : name }).first() == null;
  84. }
  85. public function checkDeveloper( prj : String, user : String ) : Void {
  86. var p = Project.manager.search({ name : prj }).first();
  87. if( p == null )
  88. return;
  89. for( d in Developer.manager.search({ project : p.id }) )
  90. if( d.user.name == user )
  91. return;
  92. throw "User '"+user+"' is not a developer of project '"+prj+"'";
  93. }
  94. public function checkPassword( user : String, pass : String ) : Bool {
  95. var u = User.manager.search({ name : user }).first();
  96. return u != null && u.pass == pass;
  97. }
  98. public function getSubmitId() : String {
  99. return Std.string(Std.random(100000000));
  100. }
  101. public function processSubmit( id : String, user : String, pass : String ) : String {
  102. var path = Site.TMP_DIR+"/"+Std.parseInt(id)+".tmp";
  103. var file = try sys.io.File.read(path,true) catch( e : Dynamic ) throw "Invalid file id #"+id;
  104. var zip = try haxe.zip.Reader.readZip(file) catch( e : Dynamic ) { file.close(); neko.Lib.rethrow(e); };
  105. file.close();
  106. var infos = Data.readInfos(zip,true);
  107. var u = User.manager.search({ name : user }).first();
  108. if( u == null || u.pass != pass )
  109. throw "Invalid username or password";
  110. var devs = infos.developers.map(function(user) {
  111. var u = User.manager.search({ name : user }).first();
  112. if( u == null )
  113. throw "Unknown user '"+user+"'";
  114. return u;
  115. });
  116. var tags = Lambda.array(infos.tags);
  117. tags.sort(Reflect.compare);
  118. var p = Project.manager.search({ name : infos.project }).first();
  119. // create project if needed
  120. if( p == null ) {
  121. p = new Project();
  122. p.name = infos.project;
  123. p.description = infos.desc;
  124. p.website = infos.website;
  125. p.license = infos.license;
  126. p.owner = u;
  127. p.insert();
  128. for( u in devs ) {
  129. var d = new Developer();
  130. d.user = u;
  131. d.project = p;
  132. d.insert();
  133. }
  134. for( tag in tags ) {
  135. var t = new Tag();
  136. t.tag = tag;
  137. t.project = p;
  138. t.insert();
  139. }
  140. }
  141. // check submit rights
  142. var pdevs = Developer.manager.search({ project : p.id });
  143. var isdev = false;
  144. for( d in pdevs )
  145. if( d.user.id == u.id ) {
  146. isdev = true;
  147. break;
  148. }
  149. if( !isdev )
  150. throw "You are not a developer of this project";
  151. var otags = Tag.manager.search({ project : p.id });
  152. var curtags = otags.map(function(t) return t.tag).join(":");
  153. // update public infos
  154. if( infos.desc != p.description || p.website != infos.website || p.license != infos.license || pdevs.length != devs.length || tags.join(":") != curtags ) {
  155. if( u.id != p.owner.id )
  156. throw "Only project owner can modify project infos";
  157. p.description = infos.desc;
  158. p.website = infos.website;
  159. p.license = infos.license;
  160. p.update();
  161. if( pdevs.length != devs.length ) {
  162. for( d in pdevs )
  163. d.delete();
  164. for( u in devs ) {
  165. var d = new Developer();
  166. d.user = u;
  167. d.project = p;
  168. d.insert();
  169. }
  170. }
  171. if( tags.join(":") != curtags ) {
  172. for( t in otags )
  173. t.delete();
  174. for( tag in tags ) {
  175. var t = new Tag();
  176. t.tag = tag;
  177. t.project = p;
  178. t.insert();
  179. }
  180. }
  181. }
  182. // look for current version
  183. var current = null;
  184. var vstr = infos.version.toString();
  185. for( v in Version.manager.search({ project : p.id }) )
  186. if( v.name == vstr ) {
  187. current = v;
  188. break;
  189. }
  190. // update documentation
  191. var doc = null;
  192. var docXML = Data.readDoc(zip);
  193. if( docXML != null ) {
  194. var p = new haxe.rtti.XmlParser();
  195. p.process(Xml.parse(docXML).firstElement(),null);
  196. p.sort();
  197. var roots = new Array();
  198. for( x in p.root )
  199. switch( x ) {
  200. case TPackage(name,_,_):
  201. switch( name ) {
  202. case "flash","flash8","sys","cs","java","flash9","haxe","js","neko","cpp","php","tools": // don't include haXe core types
  203. default: roots.push(x);
  204. }
  205. default:
  206. // don't include haXe root types
  207. }
  208. var s = new haxe.Serializer();
  209. s.useEnumIndex = true;
  210. s.useCache = true;
  211. s.serialize(roots);
  212. doc = s.toString();
  213. }
  214. // update file
  215. var target = Site.REP_DIR+"/"+Data.fileName(p.name,infos.version);
  216. if( current != null ) sys.FileSystem.deleteFile(target);
  217. sys.FileSystem.rename(path,target);
  218. // update existing version
  219. if( current != null ) {
  220. current.documentation = doc;
  221. current.comments = infos.versionComments;
  222. current.update();
  223. return "Version "+current.name+" (id#"+current.id+") updated";
  224. }
  225. // add new version
  226. var v = new Version();
  227. v.project = p;
  228. v.name = infos.version;
  229. v.comments = infos.versionComments;
  230. v.downloads = 0;
  231. v.date = Date.now().toString();
  232. v.documentation = doc;
  233. v.insert();
  234. p.version = v;
  235. p.update();
  236. return "Version "+v.name+" (id#"+v.id+") added";
  237. }
  238. public function postInstall( project : String, version : String ) {
  239. var p = Project.manager.search({ name : project }).first();
  240. if( p == null )
  241. throw "No such Project : "+project;
  242. var v = Version.manager.search({ project : p.id, name : version }).first();
  243. if( v == null )
  244. throw "No such Version : "+version;
  245. v.downloads++;
  246. v.update();
  247. p.downloads++;
  248. p.update();
  249. }
  250. }