9bca8bef9a2d2ea027061e98a70ac097e7a6813f
1 # This file is part of NIT ( http://www.nitlanguage.org ).
3 # Licensed under the Apache License, Version 2.0 (the "License");
4 # you may not use this file except in compliance with the License.
5 # You may obtain a copy of the License at
7 # http://www.apache.org/licenses/LICENSE-2.0
9 # Unless required by applicable law or agreed to in writing, software
10 # distributed under the License is distributed on an "AS IS" BASIS,
11 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 # See the License for the specific language governing permissions and
13 # limitations under the License.
20 redef class NitwebConfig
22 # Catalog to pass to handlers.
23 var catalog
: Catalog is noinit
27 # This method should be called at nitweb startup.
29 self.catalog
= new Catalog(modelbuilder
)
30 self.catalog
.build_catalog
(model
.mpackages
)
37 use
("/catalog/packages/", new APICatalogPackages(config
))
39 use
("/catalog/highlighted", new APICatalogHighLighted(config
))
40 use
("/catalog/required", new APICatalogMostRequired(config
))
41 use
("/catalog/bytags", new APICatalogByTags(config
))
42 use
("/catalog/contributors", new APICatalogContributors(config
))
43 use
("/catalog/stats", new APICatalogStats(config
))
45 use
("/catalog/tags", new APICatalogTags(config
))
46 use
("/catalog/tag/:tid", new APICatalogTag(config
))
48 use
("/catalog/person/:pid", new APICatalogPerson(config
))
49 use
("/catalog/person/:pid/maintaining", new APICatalogMaintaining(config
))
50 use
("/catalog/person/:pid/contributing", new APICatalogContributing(config
))
54 abstract class APICatalogHandler
57 # Sorter used to sort packages
59 # Sorting is based on mpackage score.
60 var mpackages_sorter
= new CatalogScoreSorter(config
.catalog
) is lazy
62 # List the 10 best packages from `cpt`
63 fun list_best
(cpt
: Counter[MPackage]): JsonArray do
64 var res
= new JsonArray
67 if i
> best
.length
then break
68 res
.add best
[best
.length-i
]
73 # List packages by group.
74 fun list_by
(map
: MultiHashMap[Object, MPackage]): JsonObject do
75 var res
= new JsonObject
76 var keys
= map
.keys
.to_a
77 alpha_comparator
.sort
(keys
)
79 var projs
= map
[k
].to_a
80 alpha_comparator
.sort
(projs
)
81 res
[k
.to_s
.html_escape
] = new JsonArray.from
(projs
)
87 # Get all the packages from the catalog using pagination
89 # `GET /packages?p=1&n=10`: get the list of catalog by page
90 class APICatalogPackages
91 super APICatalogHandler
93 redef fun get
(req
, res
) do
94 var page
= req
.int_arg
("p")
95 var limit
= req
.int_arg
("n")
96 var mpackages
= config
.catalog
.mpackages
.values
.to_a
97 mpackages_sorter
.sort
(mpackages
)
98 var response
= new JsonArray.from
(mpackages
)
99 res
.json paginate
(response
, response
.length
, page
, limit
)
103 class APICatalogHighLighted
104 super APICatalogHandler
106 redef fun get
(req
, res
) do res
.json list_best
(config
.catalog
.score
)
109 class APICatalogMostRequired
110 super APICatalogHandler
112 redef fun get
(req
, res
) do
113 if config
.catalog
.deps
.not_empty
then
114 var reqs
= new Counter[MPackage]
115 for p
in config
.model
.mpackages
do
116 reqs
[p
] = config
.catalog
.deps
[p
].smallers
.length
- 1
118 res
.json list_best
(reqs
)
121 res
.json
new JsonArray
125 class APICatalogByTags
126 super APICatalogHandler
128 redef fun get
(req
, res
) do res
.json list_by
(config
.catalog
.tag2proj
)
131 class APICatalogContributors
132 super APICatalogHandler
134 redef fun get
(req
, res
) do
135 var obj
= new JsonObject
136 obj
["maintainers"] = new JsonArray.from
(config
.catalog
.maint2proj
.keys
)
137 obj
["contributors"] = new JsonArray.from
(config
.catalog
.contrib2proj
.keys
)
142 # Get the catalog statistics
144 # `GET /stats`: return the catalog statistics
145 class APICatalogStats
146 super APICatalogHandler
148 redef fun get
(req
, res
) do
149 res
.json config
.catalog
.catalog_stats
153 # Get all the tags from the catalog
155 # `GET /tags`: the list of tags associated with their number of packages
157 super APICatalogHandler
159 # Sorter to sort tags alphabetically
160 var tags_sorter
= new CatalogTagsSorter
162 redef fun get
(req
, res
) do
163 var obj
= new JsonObject
165 var tags
= config
.catalog
.tag2proj
.keys
.to_a
166 tags_sorter
.sort
(tags
)
169 if not config
.catalog
.tag2proj
.has_key
(tag
) then continue
170 obj
[tag
] = config
.catalog
.tag2proj
[tag
].length
176 # Get the packages related to a tag
178 # `GET /tag/:tid?p=1&n=10`: return a paginated list of packages
180 super APICatalogHandler
182 redef fun get
(req
, res
) do
183 var page
= req
.int_arg
("p")
184 var limit
= req
.int_arg
("n")
185 var id
= req
.param
("tid")
187 res
.api_error
(400, "Missing tag")
190 id
= id
.from_percent_encoding
191 if not config
.catalog
.tag2proj
.has_key
(id
) then
192 res
.api_error
(404, "Tag not found")
195 var obj
= new JsonObject
197 var mpackages
= config
.catalog
.tag2proj
[id
]
198 mpackages_sorter
.sort
(mpackages
)
199 var response
= new JsonArray.from
(mpackages
)
200 obj
["packages"] = paginate
(response
, response
.length
, page
, limit
)
205 # Get a person existing in the catalog
207 # `GET /person/:pid`: get the person with `pid`
208 class APICatalogPerson
209 super APICatalogHandler
211 # Get the person with `:pid` or throw a 404 error
212 fun get_person
(req
: HttpRequest, res
: HttpResponse): nullable Person do
213 var id
= req
.param
("pid")
215 res
.api_error
(400, "Missing package full_name")
218 id
= id
.from_percent_encoding
219 if not config
.catalog
.name2person
.has_key
(id
) then
220 res
.api_error
(404, "Person not found")
223 return config
.catalog
.name2person
[id
]
226 redef fun get
(req
, res
) do
227 var person
= get_person
(req
, res
)
228 if person
== null then return
233 # Get the list of mpackages maintained by a person
235 # `GET /person/:pid/maintaining?p=1&n=10`: return a paginated list of packages
236 class APICatalogMaintaining
237 super APICatalogPerson
239 redef fun get
(req
, res
) do
240 var person
= get_person
(req
, res
)
241 if person
== null then return
243 var page
= req
.int_arg
("p")
244 var limit
= req
.int_arg
("n")
245 var array
= new Array[MPackage]
246 if config
.catalog
.maint2proj
.has_key
(person
) then
247 array
= config
.catalog
.maint2proj
[person
].to_a
249 mpackages_sorter
.sort
(array
)
250 var response
= new JsonArray.from
(array
)
251 res
.json paginate
(response
, response
.length
, page
, limit
)
255 # Get the list of mpackages contributed by a person
257 # `GET /person/:pid/contributing?p=1&n=10`: return a paginated list of packages
258 class APICatalogContributing
259 super APICatalogPerson
261 redef fun get
(req
, res
) do
262 var person
= get_person
(req
, res
)
263 if person
== null then return
265 var page
= req
.int_arg
("p")
266 var limit
= req
.int_arg
("n")
267 var array
= new Array[MPackage]
268 if config
.catalog
.contrib2proj
.has_key
(person
) then
269 array
= config
.catalog
.contrib2proj
[person
].to_a
271 mpackages_sorter
.sort
(array
)
272 var response
= new JsonArray.from
(array
)
273 res
.json paginate
(response
, response
.length
, page
, limit
)
279 # Build the catalog from `mpackages`
280 fun build_catalog
(mpackages
: Array[MPackage]) do
282 for p
in mpackages
do
285 modelbuilder
.scan_group
(g
)
288 for gg
in p
.mgroups
do for m
in gg
.mmodules
do
289 for im
in m
.in_importation
.direct_greaters
do
291 if ip
== null or ip
== p
then continue
297 for mpackage
in mpackages
do
298 package_page
(mpackage
)
300 mpackage_stats
(mpackage
)
305 redef class MPackageMetadata
308 redef fun core_serialize_to
(v
) do
310 v
.serialize_attribute
("license", license
)
311 v
.serialize_attribute
("maintainers", maintainers
)
312 v
.serialize_attribute
("contributors", contributors
)
313 v
.serialize_attribute
("tags", tags
)
314 v
.serialize_attribute
("tryit", tryit
)
315 v
.serialize_attribute
("apk", apk
)
316 v
.serialize_attribute
("homepage", homepage
)
317 v
.serialize_attribute
("browse", browse
)
318 v
.serialize_attribute
("git", git
)
319 v
.serialize_attribute
("issues", issues
)
320 v
.serialize_attribute
("first_date", first_date
)
321 v
.serialize_attribute
("last_date", last_date
)
326 redef class CatalogStats
329 redef fun core_serialize_to
(v
) do
331 v
.serialize_attribute
("packages", packages
)
332 v
.serialize_attribute
("maintainers", maintainers
)
333 v
.serialize_attribute
("contributors", contributors
)
334 v
.serialize_attribute
("tags", tags
)
335 v
.serialize_attribute
("modules", modules
)
336 v
.serialize_attribute
("classes", classes
)
337 v
.serialize_attribute
("methods", methods
)
338 v
.serialize_attribute
("loc", loc
)
342 # MPackage statistics for the catalog
343 redef class MPackageStats
346 redef fun core_serialize_to
(v
) do
348 v
.serialize_attribute
("mmodules", mmodules
)
349 v
.serialize_attribute
("mclasses", mclasses
)
350 v
.serialize_attribute
("mmethods", mmethods
)
351 v
.serialize_attribute
("loc", loc
)
352 v
.serialize_attribute
("errors", errors
)
353 v
.serialize_attribute
("warnings", warnings
)
354 v
.serialize_attribute
("warnings_per_kloc", warnings_per_kloc
)
355 v
.serialize_attribute
("documentation_score", documentation_score
)
356 v
.serialize_attribute
("commits", commits
)
357 v
.serialize_attribute
("score", score
)
364 redef fun core_serialize_to
(v
) do
366 v
.serialize_attribute
("name", name
)
367 v
.serialize_attribute
("email", email
)
368 v
.serialize_attribute
("gravatar", gravatar
)
373 # Serialize the full catalog version of `self` to JSON
375 # See: `FullCatalogSerializer`
376 fun to_full_catalog_json
(catalog
: Catalog, plain
, pretty
: nullable Bool): String do
377 var stream
= new StringWriter
378 var serializer
= new FullCatalogSerializer(stream
, catalog
)
379 serializer
.plain_json
= plain
or else false
380 serializer
.pretty_json
= pretty
or else false
381 serializer
.serialize
self
386 redef fun core_serialize_to
(v
) do
388 v
.serialize_attribute
("metadata", metadata
)
389 if v
isa FullCatalogSerializer then
390 v
.serialize_attribute
("stats", v
.catalog
.mpackages_stats
[self])
392 var parents
= v
.catalog
.deps
[self].direct_greaters
.to_a
393 v
.serialize_attribute
("dependencies", v
.deps_to_json
(parents
))
394 var children
= v
.catalog
.deps
[self].direct_smallers
.to_a
395 v
.serialize_attribute
("clients", v
.deps_to_json
(children
))
400 # CatalogSerializer decorate the Package JSON with full catalog metadata
402 # See MEntity::to_full_catalog_json.
403 class FullCatalogSerializer
404 super FullJsonSerializer
406 # Catalog used to decorate the MPackages
409 private fun deps_to_json
(mpackages
: Array[MPackage]): JsonArray do
410 var res
= new JsonArray
411 for mpackage
in mpackages
do
412 res
.add dep_to_json
(mpackage
)
417 private fun dep_to_json
(mpackage
: MPackage): JsonObject do
418 var obj
= new JsonObject
419 obj
["name"] = mpackage
.name
420 var mdoc
= mpackage
.mdoc_or_fallback
422 obj
["synopsis"] = mdoc
.synopsis
.write_to_string