Revision 27140946
Grosse simplification de la gestion des plugins
Ces modifications permettent d'isoler un peu plus les plugins
du code principal de VigiBoard (de sorte qu'il serait possible
de fournir les plugins dans des paquets RPM séparés).
Ajout d'un validateur type !FormEncode pour la conversion d'une date
selon un format (obtenu dans les traductions).
Ajout d'un mécanisme permettant aux plugins d'ajouter dynamiquement
des lignes dans le formulaire de recherche.
Ajout de nouveaux plugins pour coller au mécanisme décrit ci-dessus.
Transformation des plugins existants pour profiter de ce modèle
dynamique pour la recherche. En conséquence, le code nécessaire
pour gérer la recherche dans le contrôleur Root a été grandement
simplifié.
Ajout de la possibilité de filtrer en fonction de la priorité des
événements affichés (cf. #572).
Légère correction dans les tests (pour ne pas dépendre de l'i18n).
git-svn-id: https://vigilo-dev.si.c-s.fr/svn@6559 b22e2e97-25c9-44ff-b637-2e5ceca36478
vigiboard/controllers/root.py | ||
---|---|---|
22 | 22 |
|
23 | 23 |
from datetime import datetime |
24 | 24 |
from time import mktime |
25 |
import math |
|
26 | 25 |
|
27 |
from tg.exceptions import HTTPNotFound, HTTPInternalServerError
|
|
26 |
from tg.exceptions import HTTPNotFound |
|
28 | 27 |
from tg import expose, validate, require, flash, url, \ |
29 | 28 |
tmpl_context, request, config, session, redirect |
30 | 29 |
from webhelpers import paginate |
... | ... | |
33 | 32 |
from sqlalchemy import asc |
34 | 33 |
from sqlalchemy.sql import func |
35 | 34 |
from sqlalchemy.orm import aliased |
36 |
from sqlalchemy.orm import contains_eager |
|
37 | 35 |
from sqlalchemy.sql.expression import or_ |
38 | 36 |
from repoze.what.predicates import Any, All, in_group, \ |
39 | 37 |
has_permission, not_anonymous, \ |
40 | 38 |
NotAuthorizedError |
41 | 39 |
from formencode import schema |
42 |
from pkg_resources import working_set |
|
43 | 40 |
|
44 | 41 |
from vigilo.models.session import DBSession |
45 | 42 |
from vigilo.models.tables import Event, EventHistory, CorrEvent, Host, \ |
46 | 43 |
SupItem, SupItemGroup, LowLevelService, \ |
47 | 44 |
StateName, State, DataPermission |
48 | 45 |
from vigilo.models.tables.grouphierarchy import GroupHierarchy |
49 |
from vigilo.models.functions import sql_escape_like |
|
50 | 46 |
from vigilo.models.tables.secondary_tables import EVENTSAGGREGATE_TABLE, \ |
51 | 47 |
USER_GROUP_TABLE, SUPITEM_GROUP_TABLE |
52 | 48 |
|
... | ... | |
60 | 56 |
|
61 | 57 |
from vigiboard.widgets.edit_event import edit_event_status_options, \ |
62 | 58 |
EditEventForm |
63 |
from vigiboard.widgets.search_form import create_search_form, get_calendar_lang
|
|
59 |
from vigiboard.widgets.search_form import create_search_form |
|
64 | 60 |
|
65 | 61 |
__all__ = ('RootController', 'get_last_modification_timestamp', |
66 | 62 |
'date_to_timestamp') |
... | ... | |
88 | 84 |
|
89 | 85 |
def process_form_errors(self, *argv, **kwargv): |
90 | 86 |
""" |
91 |
Gestion des erreurs de validation : On affiche les erreurs
|
|
87 |
Gestion des erreurs de validation : on affiche les erreurs
|
|
92 | 88 |
puis on redirige vers la dernière page accédée. |
93 | 89 |
""" |
94 | 90 |
for k in tmpl_context.form_errors: |
... | ... | |
103 | 99 |
class DefaultSchema(schema.Schema): |
104 | 100 |
"""Schéma de validation de la méthode default.""" |
105 | 101 |
page = validators.Int(min=1, if_missing=1, if_invalid=1) |
106 |
supitemgroup = validators.Int(if_missing=None, if_invalid=None) |
|
107 |
host = validators.String(if_missing=None)
|
|
108 |
service = validators.String(if_missing=None)
|
|
109 |
output = validators.String(if_missing=None) |
|
110 |
trouble_ticket = validators.String(if_missing=None)
|
|
111 |
from_date = validators.String(if_missing=None)
|
|
112 |
to_date = validators.String(if_missing=None)
|
|
102 |
|
|
103 |
# Nécessaire pour que les critères de recherche soient conservés.
|
|
104 |
allow_extra_fields = True
|
|
105 |
|
|
106 |
# 2ème validation, cette fois avec les champs
|
|
107 |
# du formulaire de recherche.
|
|
108 |
chained_validators = [create_search_form.validator]
|
|
113 | 109 |
|
114 | 110 |
@validate( |
115 | 111 |
validators=DefaultSchema(), |
116 | 112 |
error_handler = process_form_errors) |
117 | 113 |
@expose('events_table.html') |
118 | 114 |
@require(access_restriction) |
119 |
def default(self, page, supitemgroup, host, service, |
|
120 |
output, trouble_ticket, from_date, to_date): |
|
115 |
def default(self, page, **search): |
|
121 | 116 |
""" |
122 | 117 |
Page d'accueil de Vigiboard. Elle affiche, suivant la page demandée |
123 | 118 |
(page 1 par defaut), la liste des événements, rangés par ordre de prise |
... | ... | |
125 | 120 |
Pour accéder à cette page, l'utilisateur doit être authentifié. |
126 | 121 |
|
127 | 122 |
@param page: Numéro de la page souhaitée, commence à 1 |
128 |
@param host: Si l'utilisateur souhaite sélectionner seulement certains |
|
129 |
événements suivant leur hôte, il peut placer une expression |
|
130 |
ici en suivant la structure du LIKE en SQL |
|
131 |
@param service: Idem que host mais sur les services |
|
132 |
@param output: Idem que host mais sur le text explicatif |
|
133 |
@param trouble_ticket: Idem que host mais sur les tickets attribués |
|
123 |
@type page: C{int} |
|
124 |
@param search: Dictionnaire contenant les critères de recherche. |
|
125 |
@type search: C{dict} |
|
134 | 126 |
|
135 | 127 |
Cette méthode permet de satisfaire les exigences suivantes : |
136 | 128 |
- VIGILO_EXIG_VIGILO_BAC_0040, |
... | ... | |
152 | 144 |
Event.idsupitem == aggregates.items.c.idsupitem)) |
153 | 145 |
aggregates.add_order_by(asc(aggregates.items.c.hostname)) |
154 | 146 |
|
155 |
search = {} |
|
156 |
|
|
157 |
# Application des filtres si nécessaire |
|
158 |
if supitemgroup: |
|
159 |
search['supitemgroup'] = supitemgroup |
|
160 |
aggregates.add_join((GroupHierarchy, GroupHierarchy.idchild == |
|
161 |
aggregates.items.c.idsupitemgroup)) |
|
162 |
aggregates.add_filter(GroupHierarchy.idparent == supitemgroup) |
|
163 |
|
|
164 |
if host: |
|
165 |
search['host_'] = host |
|
166 |
host = sql_escape_like(host) |
|
167 |
aggregates.add_filter(aggregates.items.c.hostname.ilike( |
|
168 |
'%s' % host)) |
|
169 |
|
|
170 |
if service: |
|
171 |
search['service'] = service |
|
172 |
service = sql_escape_like(service) |
|
173 |
aggregates.add_filter(aggregates.items.c.servicename.ilike( |
|
174 |
'%s' % service)) |
|
175 |
|
|
176 |
if output: |
|
177 |
search['output'] = output |
|
178 |
output = sql_escape_like(output) |
|
179 |
aggregates.add_filter(Event.message.ilike('%s' % output)) |
|
180 |
|
|
181 |
if trouble_ticket: |
|
182 |
search['tt'] = trouble_ticket |
|
183 |
trouble_ticket = sql_escape_like(trouble_ticket) |
|
184 |
aggregates.add_filter(CorrEvent.trouble_ticket.ilike( |
|
185 |
'%s' % trouble_ticket)) |
|
186 |
|
|
187 |
if from_date: |
|
188 |
search['from_date'] = from_date.lower() |
|
189 |
try: |
|
190 |
# TRANSLATORS: Format de date et heure Python/JavaScript. |
|
191 |
# TRANSLATORS: http://www.dynarch.com/static/jscalendar-1.0/doc/html/reference.html#node_sec_5.3.5 |
|
192 |
# TRANSLATORS: http://docs.python.org/release/2.5/lib/module-time.html |
|
193 |
from_date = datetime.strptime( |
|
194 |
from_date.encode('utf8'), |
|
195 |
_('%Y-%m-%d %I:%M:%S %p').encode('utf8')) |
|
196 |
except ValueError: |
|
197 |
# On ignore silencieusement la date invalide reçue. |
|
198 |
pass |
|
199 |
else: |
|
200 |
aggregates.add_filter(CorrEvent.timestamp_active >= from_date) |
|
201 |
|
|
202 |
if to_date: |
|
203 |
search['to_date'] = to_date.lower() |
|
204 |
try: |
|
205 |
# TRANSLATORS: Format de date et heure Python/JavaScript. |
|
206 |
# TRANSLATORS: http://www.dynarch.com/static/jscalendar-1.0/doc/html/reference.html#node_sec_5.3.5 |
|
207 |
# TRANSLATORS: http://docs.python.org/release/2.5/lib/module-time.html |
|
208 |
to_date = datetime.strptime( |
|
209 |
to_date.encode('utf8'), |
|
210 |
_('%Y-%m-%d %I:%M:%S %p').encode('utf8')) |
|
211 |
except ValueError: |
|
212 |
# On ignore silencieusement la date invalide reçue. |
|
213 |
pass |
|
214 |
else: |
|
215 |
aggregates.add_filter(CorrEvent.timestamp_active <= to_date) |
|
147 |
# Application des filtres des plugins si nécessaire. |
|
148 |
for plugin, instance in config.get('columns_plugins', []): |
|
149 |
instance.handle_search_fields(aggregates, search) |
|
150 |
|
|
151 |
# Certains arguments sont réservés dans url_for(). |
|
152 |
# On effectue les substitutions adéquates. |
|
153 |
# Par exemple: "host" devient "host_". |
|
154 |
reserved = ('host', ) |
|
155 |
copy = search.copy() |
|
156 |
for column in copy: |
|
157 |
if column in reserved: |
|
158 |
search[column + '_'] = search[column] |
|
159 |
del search[column] |
|
216 | 160 |
|
217 | 161 |
# Pagination des résultats |
218 | 162 |
aggregates.generate_request() |
219 | 163 |
items_per_page = int(config['vigiboard_items_per_page']) |
220 |
page = paginate.Page(aggregates.req, page=page, items_per_page=items_per_page) |
|
164 |
page = paginate.Page(aggregates.req, page=page, |
|
165 |
items_per_page=items_per_page) |
|
221 | 166 |
|
222 | 167 |
# Récupération des données des plugins |
223 | 168 |
plugins_data = {} |
... | ... | |
246 | 191 |
event_edit_status_options = edit_event_status_options, |
247 | 192 |
search_form = create_search_form, |
248 | 193 |
search = search, |
249 |
get_calendar_lang = get_calendar_lang, |
|
250 | 194 |
) |
251 | 195 |
|
252 | 196 |
|
... | ... | |
310 | 254 |
# Pagination des résultats |
311 | 255 |
events.generate_request() |
312 | 256 |
items_per_page = int(config['vigiboard_items_per_page']) |
313 |
page = paginate.Page(events.req, page=page, items_per_page=items_per_page) |
|
257 |
page = paginate.Page(events.req, page=page, |
|
258 |
items_per_page=items_per_page) |
|
314 | 259 |
|
315 | 260 |
# Vérification que l'événement existe |
316 | 261 |
if not page.item_count: |
... | ... | |
325 | 270 |
page = page, |
326 | 271 |
search_form = create_search_form, |
327 | 272 |
search = {}, |
328 |
get_calendar_lang = get_calendar_lang, |
|
329 | 273 |
) |
330 | 274 |
|
331 | 275 |
|
... | ... | |
388 | 332 |
page = page, |
389 | 333 |
search_form = create_search_form, |
390 | 334 |
search = {}, |
391 |
get_calendar_lang = get_calendar_lang, |
|
392 | 335 |
) |
393 | 336 |
|
394 | 337 |
|
... | ... | |
436 | 379 |
# Pagination des résultats |
437 | 380 |
aggregates.generate_request() |
438 | 381 |
items_per_page = int(config['vigiboard_items_per_page']) |
439 |
page = paginate.Page(aggregates.req, page=page, items_per_page=items_per_page) |
|
382 |
page = paginate.Page(aggregates.req, page=page, |
|
383 |
items_per_page=items_per_page) |
|
440 | 384 |
|
441 | 385 |
# Vérification qu'il y a au moins 1 événement qui correspond |
442 | 386 |
if not page.item_count: |
... | ... | |
460 | 404 |
event_edit_status_options = edit_event_status_options, |
461 | 405 |
search_form = create_search_form, |
462 | 406 |
search = {}, |
463 |
get_calendar_lang = get_calendar_lang, |
|
464 | 407 |
) |
465 | 408 |
|
466 | 409 |
|
... | ... | |
554 | 497 |
for event in events.req: |
555 | 498 |
if trouble_ticket and trouble_ticket != event.trouble_ticket: |
556 | 499 |
history = EventHistory( |
557 |
type_action="Ticket change", |
|
500 |
type_action=u"Ticket change",
|
|
558 | 501 |
idevent=event.idcause, |
559 | 502 |
value=unicode(trouble_ticket), |
560 | 503 |
text="Changed trouble ticket from '%(from)s' " |
Also available in: Unified diff