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
))
50 abstract class APICatalogHandler
53 # Sorter used to sort packages
55 # Sorting is based on mpackage score.
56 var mpackages_sorter
= new CatalogScoreSorter(config
.catalog
) is lazy
58 # List the 10 best packages from `cpt`
59 fun list_best
(cpt
: Counter[MPackage]): JsonArray do
60 var res
= new JsonArray
63 if i
> best
.length
then break
64 res
.add best
[best
.length-i
]
69 # List packages by group.
70 fun list_by
(map
: MultiHashMap[Object, MPackage]): JsonObject do
71 var res
= new JsonObject
72 var keys
= map
.keys
.to_a
73 alpha_comparator
.sort
(keys
)
75 var projs
= map
[k
].to_a
76 alpha_comparator
.sort
(projs
)
77 res
[k
.to_s
.html_escape
] = new JsonArray.from
(projs
)
83 # Get all the packages from the catalog using pagination
85 # `GET /packages?p=1&n=10`: get the list of catalog by page
86 class APICatalogPackages
87 super APICatalogHandler
89 redef fun get
(req
, res
) do
90 var page
= req
.int_arg
("p")
91 var limit
= req
.int_arg
("n")
92 var mpackages
= config
.catalog
.mpackages
.values
.to_a
93 mpackages_sorter
.sort
(mpackages
)
94 var response
= new JsonArray.from
(mpackages
)
95 res
.json paginate
(response
, response
.length
, page
, limit
)
99 class APICatalogHighLighted
100 super APICatalogHandler
102 redef fun get
(req
, res
) do res
.json list_best
(config
.catalog
.score
)
105 class APICatalogMostRequired
106 super APICatalogHandler
108 redef fun get
(req
, res
) do
109 if config
.catalog
.deps
.not_empty
then
110 var reqs
= new Counter[MPackage]
111 for p
in config
.model
.mpackages
do
112 reqs
[p
] = config
.catalog
.deps
[p
].smallers
.length
- 1
114 res
.json list_best
(reqs
)
117 res
.json
new JsonArray
121 class APICatalogByTags
122 super APICatalogHandler
124 redef fun get
(req
, res
) do res
.json list_by
(config
.catalog
.tag2proj
)
127 class APICatalogContributors
128 super APICatalogHandler
130 redef fun get
(req
, res
) do
131 var obj
= new JsonObject
132 obj
["maintainers"] = new JsonArray.from
(config
.catalog
.maint2proj
.keys
)
133 obj
["contributors"] = new JsonArray.from
(config
.catalog
.contrib2proj
.keys
)
138 # Get the catalog statistics
140 # `GET /stats`: return the catalog statistics
141 class APICatalogStats
142 super APICatalogHandler
144 redef fun get
(req
, res
) do
145 res
.json config
.catalog
.catalog_stats
149 # Get all the tags from the catalog
151 # `GET /tags`: the list of tags associated with their number of packages
153 super APICatalogHandler
155 # Sorter to sort tags alphabetically
156 var tags_sorter
= new CatalogTagsSorter
158 redef fun get
(req
, res
) do
159 var obj
= new JsonObject
161 var tags
= config
.catalog
.tag2proj
.keys
.to_a
162 tags_sorter
.sort
(tags
)
165 if not config
.catalog
.tag2proj
.has_key
(tag
) then continue
166 obj
[tag
] = config
.catalog
.tag2proj
[tag
].length
172 # Get the packages related to a tag
174 # `GET /tag/:tid?p=1&n=10`: return a paginated list of packages
176 super APICatalogHandler
178 redef fun get
(req
, res
) do
179 var page
= req
.int_arg
("p")
180 var limit
= req
.int_arg
("n")
181 var id
= req
.param
("tid")
183 res
.api_error
(400, "Missing tag")
186 id
= id
.from_percent_encoding
187 if not config
.catalog
.tag2proj
.has_key
(id
) then
188 res
.api_error
(404, "Tag not found")
191 var obj
= new JsonObject
193 var mpackages
= config
.catalog
.tag2proj
[id
]
194 mpackages_sorter
.sort
(mpackages
)
195 var response
= new JsonArray.from
(mpackages
)
196 obj
["packages"] = paginate
(response
, response
.length
, page
, limit
)
202 # Build the catalog from `mpackages`
203 fun build_catalog
(mpackages
: Array[MPackage]) do
205 for p
in mpackages
do
208 modelbuilder
.scan_group
(g
)
211 for gg
in p
.mgroups
do for m
in gg
.mmodules
do
212 for im
in m
.in_importation
.direct_greaters
do
214 if ip
== null or ip
== p
then continue
220 for mpackage
in mpackages
do
221 package_page
(mpackage
)
223 mpackage_stats
(mpackage
)
228 redef class MPackageMetadata
231 redef fun core_serialize_to
(v
) do
233 v
.serialize_attribute
("license", license
)
234 v
.serialize_attribute
("maintainers", maintainers
)
235 v
.serialize_attribute
("contributors", contributors
)
236 v
.serialize_attribute
("tags", tags
)
237 v
.serialize_attribute
("tryit", tryit
)
238 v
.serialize_attribute
("apk", apk
)
239 v
.serialize_attribute
("homepage", homepage
)
240 v
.serialize_attribute
("browse", browse
)
241 v
.serialize_attribute
("git", git
)
242 v
.serialize_attribute
("issues", issues
)
243 v
.serialize_attribute
("first_date", first_date
)
244 v
.serialize_attribute
("last_date", last_date
)
249 redef class CatalogStats
252 redef fun core_serialize_to
(v
) do
254 v
.serialize_attribute
("packages", packages
)
255 v
.serialize_attribute
("maintainers", maintainers
)
256 v
.serialize_attribute
("contributors", contributors
)
257 v
.serialize_attribute
("tags", tags
)
258 v
.serialize_attribute
("modules", modules
)
259 v
.serialize_attribute
("classes", classes
)
260 v
.serialize_attribute
("methods", methods
)
261 v
.serialize_attribute
("loc", loc
)
265 # MPackage statistics for the catalog
266 redef class MPackageStats
269 redef fun core_serialize_to
(v
) do
271 v
.serialize_attribute
("mmodules", mmodules
)
272 v
.serialize_attribute
("mclasses", mclasses
)
273 v
.serialize_attribute
("mmethods", mmethods
)
274 v
.serialize_attribute
("loc", loc
)
275 v
.serialize_attribute
("errors", errors
)
276 v
.serialize_attribute
("warnings", warnings
)
277 v
.serialize_attribute
("warnings_per_kloc", warnings_per_kloc
)
278 v
.serialize_attribute
("documentation_score", documentation_score
)
279 v
.serialize_attribute
("commits", commits
)
280 v
.serialize_attribute
("score", score
)
287 redef fun core_serialize_to
(v
) do
289 v
.serialize_attribute
("name", name
)
290 v
.serialize_attribute
("email", email
)
291 v
.serialize_attribute
("gravatar", gravatar
)
296 # Serialize the full catalog version of `self` to JSON
298 # See: `FullCatalogSerializer`
299 fun to_full_catalog_json
(catalog
: Catalog, plain
, pretty
: nullable Bool): String do
300 var stream
= new StringWriter
301 var serializer
= new FullCatalogSerializer(stream
, catalog
)
302 serializer
.plain_json
= plain
or else false
303 serializer
.pretty_json
= pretty
or else false
304 serializer
.serialize
self
309 redef fun core_serialize_to
(v
) do
311 v
.serialize_attribute
("metadata", metadata
)
312 if v
isa FullCatalogSerializer then
313 v
.serialize_attribute
("stats", v
.catalog
.mpackages_stats
[self])
315 var parents
= v
.catalog
.deps
[self].direct_greaters
.to_a
316 v
.serialize_attribute
("dependencies", v
.deps_to_json
(parents
))
317 var children
= v
.catalog
.deps
[self].direct_smallers
.to_a
318 v
.serialize_attribute
("clients", v
.deps_to_json
(children
))
323 # CatalogSerializer decorate the Package JSON with full catalog metadata
325 # See MEntity::to_full_catalog_json.
326 class FullCatalogSerializer
327 super FullJsonSerializer
329 # Catalog used to decorate the MPackages
332 private fun deps_to_json
(mpackages
: Array[MPackage]): JsonArray do
333 var res
= new JsonArray
334 for mpackage
in mpackages
do
335 res
.add dep_to_json
(mpackage
)
340 private fun dep_to_json
(mpackage
: MPackage): JsonObject do
341 var obj
= new JsonObject
342 obj
["name"] = mpackage
.name
343 var mdoc
= mpackage
.mdoc_or_fallback
345 obj
["synopsis"] = mdoc
.synopsis
.write_to_string