476e68f00d628112b0a8467a7d0aa0c0b4c791b2
[nit.git] / src / web / web_base.nit
1 # This file is part of NIT ( http://www.nitlanguage.org ).
2 #
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
6 #
7 # http://www.apache.org/licenses/LICENSE-2.0
8 #
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.
14
15 # Base classes used by `nitweb`.
16 module web_base
17
18 import model::model_views
19 import model::model_json
20 import doc_down
21 import popcorn
22
23 # Specific nitcorn Action that uses a Model
24 class ModelHandler
25 super Handler
26
27 # Model to use.
28 var model: Model
29
30 # MModule used to flatten model.
31 var mainmodule: MModule
32
33 # Find the MEntity ` with `full_name`.
34 fun find_mentity(model: ModelView, full_name: nullable String): nullable MEntity do
35 if full_name == null then return null
36 return model.mentity_by_full_name(full_name.from_percent_encoding)
37 end
38
39 # Init the model view from the `req` uri parameters.
40 fun init_model_view(req: HttpRequest): ModelView do
41 var view = new ModelView(model)
42 var show_private = req.bool_arg("private") or else false
43 if not show_private then view.min_visibility = protected_visibility
44
45 view.include_fictive = req.bool_arg("fictive") or else false
46 view.include_empty_doc = req.bool_arg("empty-doc") or else true
47 view.include_test_suite = req.bool_arg("test-suite") or else false
48 view.include_attribute = req.bool_arg("attributes") or else true
49
50 return view
51 end
52 end
53
54 # Specific handler for nitweb API.
55 abstract class APIHandler
56 super ModelHandler
57
58 # The JSON API does not filter anything by default.
59 #
60 # So we can cache the model view.
61 var view: ModelView is lazy do
62 var view = new ModelView(model)
63 view.min_visibility = private_visibility
64 view.include_fictive = true
65 view.include_empty_doc = true
66 view.include_attribute = true
67 view.include_test_suite = true
68 return view
69 end
70
71 # Try to load the mentity from uri with `/:id`.
72 #
73 # Send 400 if `:id` is null.
74 # Send 404 if no entity is found.
75 # Return null in both cases.
76 fun mentity_from_uri(req: HttpRequest, res: HttpResponse): nullable MEntity do
77 var id = req.param("id")
78 if id == null then
79 res.error 400
80 return null
81 end
82 var mentity = find_mentity(view, id)
83 if mentity == null then
84 res.error 404
85 end
86 return mentity
87 end
88 end
89
90 # A NitView is rendered by an action.
91 interface NitView
92 # Renders this view and returns something that can be written to a HTTP response.
93 fun render: Writable is abstract
94 end
95
96 redef class HttpResponse
97 # Render a NitView as response.
98 fun send_view(view: NitView, status: nullable Int) do send(view.render, status)
99 end
100
101 redef class MEntity
102
103 # URL to `self` within the web interface.
104 fun web_url: String is abstract
105
106 # URL to `self` within the JSON api.
107 fun api_url: String do return "/api/entity/" / full_name
108
109 redef fun json do
110 var obj = super
111 obj["web_url"] = web_url
112 obj["api_url"] = api_url
113 return obj
114 end
115
116 # Get the full json repesentation of `self` with MEntityRefs resolved.
117 fun api_json(handler: ModelHandler): JsonObject do return json
118 end
119
120 redef class MEntityRef
121 redef fun json do
122 var obj = super
123 obj["web_url"] = mentity.web_url
124 obj["api_url"] = mentity.api_url
125 obj["name"] = mentity.name
126 obj["mdoc"] = mentity.mdoc_or_fallback
127 obj["visibility"] = mentity.visibility
128 obj["location"] = mentity.location
129 var modifiers = new JsonArray
130 for modifier in mentity.collect_modifiers do
131 modifiers.add modifier
132 end
133 obj["modifiers"] = modifiers
134 var mentity = self.mentity
135 if mentity isa MMethod then
136 obj["msignature"] = mentity.intro.msignature
137 else if mentity isa MMethodDef then
138 obj["msignature"] = mentity.msignature
139 else if mentity isa MVirtualTypeProp then
140 obj["bound"] = to_mentity_ref(mentity.intro.bound)
141 else if mentity isa MVirtualTypeDef then
142 obj["bound"] = to_mentity_ref(mentity.bound)
143 end
144 return obj
145 end
146 end
147
148 redef class MDoc
149
150 # Add doc down processing
151 redef fun json do
152 var obj = super
153 obj["synopsis"] = synopsis
154 obj["documentation"] = documentation
155 obj["comment"] = comment
156 obj["html_synopsis"] = html_synopsis.write_to_string
157 obj["html_documentation"] = html_documentation.write_to_string
158 obj["html_comment"] = html_comment.write_to_string
159 return obj
160 end
161 end
162
163 redef class MPackage
164 redef var web_url = "/package/{full_name}" is lazy
165 end
166
167 redef class MGroup
168 redef var web_url = "/group/{full_name}" is lazy
169 end
170
171 redef class MModule
172 redef var web_url = "/module/{full_name}" is lazy
173
174 redef fun api_json(handler) do
175 var obj = super
176 obj["intro_mclassdefs"] = to_mentity_refs(collect_intro_mclassdefs(private_view))
177 obj["redef_mclassdefs"] = to_mentity_refs(collect_redef_mclassdefs(private_view))
178 obj["imports"] = to_mentity_refs(in_importation.direct_greaters)
179 return obj
180 end
181 end
182
183 redef class MClass
184 redef var web_url = "/class/{full_name}" is lazy
185
186 redef fun api_json(handler) do
187 var obj = super
188 obj["all_mproperties"] = to_mentity_refs(collect_accessible_mproperties(private_view))
189 obj["intro_mproperties"] = to_mentity_refs(collect_intro_mproperties(private_view))
190 obj["redef_mproperties"] = to_mentity_refs(collect_redef_mproperties(private_view))
191 obj["parents"] = to_mentity_refs(collect_parents(private_view))
192 return obj
193 end
194 end
195
196 redef class MClassDef
197 redef var web_url = "/classdef/{full_name}" is lazy
198
199 redef fun json do
200 var obj = super
201 obj["intro"] = to_mentity_ref(mclass.intro)
202 obj["mpackage"] = to_mentity_ref(mmodule.mpackage)
203 return obj
204 end
205
206 redef fun api_json(handler) do
207 var obj = super
208 obj["intro_mpropdefs"] = to_mentity_refs(collect_intro_mpropdefs(private_view))
209 obj["redef_mpropdefs"] = to_mentity_refs(collect_redef_mpropdefs(private_view))
210 return obj
211 end
212 end
213
214 redef class MProperty
215 redef var web_url = "/property/{full_name}" is lazy
216
217 redef fun json do
218 var obj = super
219 obj["intro_mclass"] = to_mentity_ref(intro_mclassdef.mclass)
220 obj["mpackage"] = to_mentity_ref(intro_mclassdef.mmodule.mpackage)
221 return obj
222 end
223 end
224
225 redef class MPropDef
226 redef var web_url = "/propdef/{full_name}" is lazy
227
228 redef fun json do
229 var obj = super
230 obj["intro"] = to_mentity_ref(mproperty.intro)
231 obj["intro_mclassdef"] = to_mentity_ref(mproperty.intro.mclassdef)
232 obj["mmodule"] = to_mentity_ref(mclassdef.mmodule)
233 obj["mgroup"] = to_mentity_ref(mclassdef.mmodule.mgroup)
234 obj["mpackage"] = to_mentity_ref(mclassdef.mmodule.mpackage)
235 return obj
236 end
237 end
238
239 redef class MClassType
240 redef var web_url = mclass.web_url is lazy
241 end
242
243 redef class MNullableType
244 redef var web_url = mtype.web_url is lazy
245 end
246
247 redef class MParameterType
248 redef var web_url = mclass.web_url is lazy
249 end
250
251 redef class MVirtualType
252 redef var web_url = mproperty.web_url is lazy
253 end
254
255 redef class POSetElement[E]
256 super Jsonable
257
258 # Return JSON representation of `self`.
259 fun json: JsonObject do
260 assert self isa POSetElement[MEntity]
261 var obj = new JsonObject
262 obj["greaters"] = to_mentity_refs(greaters)
263 obj["direct_greaters"] = to_mentity_refs(direct_greaters)
264 obj["direct_smallers"] = to_mentity_refs(direct_smallers)
265 obj["smallers"] = to_mentity_refs(smallers)
266 return obj
267 end
268
269 redef fun to_json do return json.to_json
270 end