def update_timeperiod(params): """Update a time period""" body = params['body'] name = params['name'] if name == "24X7": raise ProblemException(405, http.client.responses[405], "You cannot change the built-in time period") time_period = load_timeperiod(name) if time_period is None: raise ProblemException(404, http.client.responses[404], f"Time period {name} not found") if "exceptions" in body: time_period = dict( (key, time_period[key]) for key in [*defines.weekday_ids(), "alias", "exclude"] if key in time_period) time_period["exceptions"] = _format_exceptions(body["exceptions"]) if "alias" in body: time_period['alias'] = body['alias'] if "active_time_ranges" in body: time_period.update(_daily_time_ranges(body['active_time_ranges'])) if "exclude" in body: time_period["exclude"] = body["exclude"] save_timeperiod(name, time_period) return Response(status=204)
def _to_valuespec(self, tp_spec): if not tp_spec: return {} exceptions = [] for exception_name, time_ranges in tp_spec.items(): if exception_name not in defines.weekday_ids() + [ "alias", "exclude" ]: exceptions.append( (exception_name, self._time_ranges_to_valuespec(time_ranges))) vs_spec = { "name": unique_default_name_suggestion(self._name or "time_period", list(self._timeperiods.keys())), "alias": timeperiod_spec_alias(tp_spec), "weekdays": self._weekdays_to_valuespec(tp_spec), "exclude": tp_spec.get("exclude", []), "exceptions": sorted(exceptions), } return vs_spec
def _from_vars(self): self._timeperiods = watolib.timeperiods.load_timeperiods() self._name = request.var("edit") # missing -> new group # TODO: Nuke the field below? It effectively hides facts about _name for mypy. self._new = self._name is None if self._name in watolib.timeperiods.builtin_timeperiods(): raise MKUserError("edit", _("Builtin timeperiods can not be modified")) if self._new: clone_name = request.var("clone") if request.var("mode") == "import_ical": self._timeperiod = {} elif clone_name: self._name = clone_name self._timeperiod = self._get_timeperiod(self._name) else: # initialize with 24x7 config self._timeperiod = { day: [("00:00", "24:00")] for day in defines.weekday_ids() } else: self._timeperiod = self._get_timeperiod(self._name)
def _daily_time_ranges(active_time_ranges: List[Dict[str, Any]]) -> Dict[str, List[TIME_RANGE]]: """Convert the user provided time ranges to the Checkmk format Args: active_time_ranges: The list of specific time ranges Returns: A dict which contains the week days as keys and their associating time ranges as values Examples: >>> _daily_time_ranges( ... [{"day": "monday", "time_ranges": [{"start": dt.time(12), "end": dt.time(14)}]}]) {'monday': [('12:00', '14:00')], 'tuesday': [], 'wednesday': [], 'thursday': [], \ 'friday': [], 'saturday': [], 'sunday': []} """ result: Dict[str, List[TIME_RANGE]] = {day: [] for day in defines.weekday_ids()} for active_time_range in active_time_ranges: period = active_time_range["day"] # weekday or week time_ranges = [ _format_time_range(time_range) for time_range in active_time_range["time_ranges"] ] if period == "all": for day_time_ranges in result.values(): day_time_ranges.extend(time_ranges) else: # specific day result[period].extend(time_ranges) return result
def _weekdays_to_valuespec(self, tp_spec): if self._has_same_time_specs_during_whole_week(tp_spec): return ("whole_week", self._time_ranges_to_valuespec(tp_spec.get("monday", []))) return ("day_specific", { day: self._time_ranges_to_valuespec(tp_spec.get(day, [])) for day in defines.weekday_ids() })
def action(self): if not html.check_transaction(): return vs_ical = self._vs_ical() ical = vs_ical.from_html_vars("ical") vs_ical.validate_value(ical, "ical") filename, _ty, content = ical['file'] try: data = self._parse_ical(content, ical['horizon']) except Exception as e: if config.debug: raise raise MKUserError('ical_file', _('Failed to parse file: %s') % e) # TODO: This is kind of a hack that we "fake" a HTTP request structure here. # Find a better way to hand over the whole data structure directly to the # edit_timeperiod code html.request.set_var('timeperiod_p_alias', data.get('descr', data.get('name', filename))) for day in defines.weekday_ids(): html.request.set_var('%s_0_from' % day, '') html.request.set_var('%s_0_until' % day, '') # Default to whole day if not ical["times"]: ical["times"] = [((0, 0), (24, 0))] html.request.set_var('timeperiod_p_exceptions_count', "%d" % len(data['events'])) for index, event in enumerate(data['events']): index += 1 html.request.set_var('timeperiod_p_exceptions_%d_0' % index, event['date']) html.request.set_var('timeperiod_p_exceptions_indexof_%d' % index, "%d" % index) html.request.set_var('timeperiod_p_exceptions_%d_1_count' % index, "%d" % len(ical["times"])) for n, time_spec in enumerate(ical["times"]): n += 1 start_time = ":".join("%02d" % x for x in time_spec[0]) end_time = ":".join("%02d" % x for x in time_spec[1]) html.request.set_var( 'timeperiod_p_exceptions_%d_1_%d_from' % (index, n), start_time) html.request.set_var( 'timeperiod_p_exceptions_%d_1_%d_until' % (index, n), end_time) html.request.set_var( 'timeperiod_p_exceptions_%d_1_indexof_%d' % (index, n), "%d" % index) return "edit_timeperiod"
def show_time_period(params): """Show a time period""" name = params['name'] time_periods = load_timeperiods() if name not in time_periods: raise ProblemException(404, http.client.responses[404], f"Time period {name} not found") time_period = time_periods[name] time_period_readable: Dict[str, Any] = {key: time_period[key] for key in ("alias", "exclude")} active_time_ranges = _active_time_ranges_readable( {key: time_period[key] for key in defines.weekday_ids()}) time_period_readable["active_time_ranges"] = active_time_ranges time_period_readable["exceptions"] = _exceptions_readable({ key: time_period[key] for key in time_period if key not in ['alias', 'exclude', *defines.weekday_ids()] }) return _serve_time_period(time_period_readable)
def _show_add_timeperiod_page(self) -> None: # If an ICalendar file is uploaded, we process the htmlvars here, to avoid # "Request URI too long exceptions" vs_ical = self._vs_ical() ical = vs_ical.from_html_vars("ical") vs_ical.validate_value(ical, "ical") filename, _ty, content = ical["file"] try: # TODO(ml): If we could open the file in text mode, we would not # need to `decode()` here. data = self._parse_ical(content.decode("utf-8"), ical["horizon"]) except Exception as e: if active_config.debug: raise raise MKUserError("ical_file", _("Failed to parse file: %s") % e) get_vars = { "timeperiod_p_alias": data.get("descr", data.get("name", filename)), } for day in defines.weekday_ids(): get_vars["%s_0_from" % day] = "" get_vars["%s_0_until" % day] = "" # Default to whole day if not ical["times"]: ical["times"] = [((0, 0), (24, 0))] get_vars["timeperiod_p_exceptions_count"] = "%d" % len(data["events"]) for index, event in enumerate(data["events"]): index += 1 get_vars["timeperiod_p_exceptions_%d_0" % index] = event["date"] get_vars["timeperiod_p_exceptions_indexof_%d" % index] = "%d" % index get_vars["timeperiod_p_exceptions_%d_1_count" % index] = "%d" % len(ical["times"]) for n, time_spec in enumerate(ical["times"]): n += 1 start_time = ":".join("%02d" % x for x in time_spec[0]) end_time = ":".join("%02d" % x for x in time_spec[1]) get_vars["timeperiod_p_exceptions_%d_1_%d_from" % (index, n)] = start_time get_vars["timeperiod_p_exceptions_%d_1_%d_until" % (index, n)] = end_time get_vars["timeperiod_p_exceptions_%d_1_indexof_%d" % (index, n)] = "%d" % index for var, val in get_vars.items(): html.request.set_var(var, val) html.request.set_var("mode", "edit_timeperiod") ModeEditTimeperiod().page()
def _to_api_format( time_period: TimeperiodSpec, builtin_period: bool = False, internal_format: bool = False ): """Convert time_period to API format as specified in request schema Args: time_period: time period which has the internal checkmk format builtin_period: bool specifying if the time period is a built-in time period internal_format: bool which determines if the time ranges should be compatible for internal processing Examples: >>> _to_api_format({'alias': 'Test All days 8x5', '2021-04-01': [('14:00', '15:00')], ... 'monday': [('08:00', '12:30'), ('13:30', '17:00')], 'tuesday': [], 'wednesday': [], ... 'thursday': [], 'friday': [], 'saturday': [], 'sunday': [], 'exclude': []}) {'alias': 'Test All days 8x5', 'exclude': [], 'active_time_ranges': \ [{'day': 'monday', 'time_ranges': [{'start': '08:00', 'end': '12:30'}, {'start': '13:30', \ 'end': '17:00'}]}], 'exceptions': [{'date': '2021-04-01', 'time_ranges': [{'start': '14:00', 'end': '15:00'}]}]} """ time_period_readable: Dict[str, Any] = {"alias": time_period["alias"]} if not builtin_period: time_period_readable["exclude"] = time_period.get("exclude", []) active_time_ranges = _active_time_ranges_readable( {key: time_period[key] for key in defines.weekday_ids()} ) exceptions = _exceptions_readable( { key: time_period[key] for key in time_period if key not in ["alias", "exclude", *defines.weekday_ids()] } ) if internal_format: active_time_ranges = _convert_to_dt(active_time_ranges) exceptions = _convert_to_dt(exceptions) time_period_readable["active_time_ranges"] = active_time_ranges time_period_readable["exceptions"] = exceptions return time_period_readable
def action(self) -> ActionResult: if not transactions.check_transaction(): return None vs_ical = self._vs_ical() ical = vs_ical.from_html_vars("ical") vs_ical.validate_value(ical, "ical") filename, _ty, content = ical['file'] try: # TODO(ml): If we could open the file in text mode, we would not # need to `decode()` here. data = self._parse_ical(content.decode("utf-8"), ical['horizon']) except Exception as e: if config.debug: raise raise MKUserError('ical_file', _('Failed to parse file: %s') % e) get_vars = { 'timeperiod_p_alias': data.get('descr', data.get('name', filename)), } for day in defines.weekday_ids(): get_vars['%s_0_from' % day] = '' get_vars['%s_0_until' % day] = '' # Default to whole day if not ical["times"]: ical["times"] = [((0, 0), (24, 0))] get_vars['timeperiod_p_exceptions_count'] = "%d" % len(data['events']) for index, event in enumerate(data['events']): index += 1 get_vars['timeperiod_p_exceptions_%d_0' % index] = event['date'] get_vars['timeperiod_p_exceptions_indexof_%d' % index] = "%d" % index get_vars['timeperiod_p_exceptions_%d_1_count' % index] = "%d" % len(ical["times"]) for n, time_spec in enumerate(ical["times"]): n += 1 start_time = ":".join("%02d" % x for x in time_spec[0]) end_time = ":".join("%02d" % x for x in time_spec[1]) get_vars['timeperiod_p_exceptions_%d_1_%d_from' % (index, n)] = start_time get_vars['timeperiod_p_exceptions_%d_1_%d_until' % (index, n)] = end_time get_vars['timeperiod_p_exceptions_%d_1_indexof_%d' % (index, n)] = "%d" % index return redirect(mode_url("edit_timeperiod", **get_vars))
def _weekdays_from_valuespec(self, vs_spec): weekday_ty, weekday_values = vs_spec["weekdays"] if weekday_ty not in ["whole_week", "day_specific"]: raise NotImplementedError() # produce a data structure equal to the "day_specific" structure if weekday_ty == "whole_week": weekday_values = {day: weekday_values for day in defines.weekday_ids()} return { day: self._time_ranges_from_valuespec(weekday_values[day]) for day, time_ranges in weekday_values.items() if time_ranges }
def _validate_timeperiod_exception(self, value, varprefix): if value in defines.weekday_ids(): raise MKUserError(varprefix, _("You cannot use weekday names (%s) in exceptions") % value) if value in ["name", "alias", "timeperiod_name", "register", "use", "exclude"]: raise MKUserError(varprefix, _("<tt>%s</tt> is a reserved keyword.")) cfg = watolib.ConfigDomainOMD().default_globals() if cfg["site_core"] == "cmc": try: time.strptime(value, "%Y-%m-%d") except ValueError: raise MKUserError( varprefix, _("You need to provide timeperiod exceptions in YYYY-MM-DD format"))
def _time_exceptions_from_valuespec(self, vs_spec): # TODO: time exceptions is either a list of tuples or a dictionary for period_type, exceptions_details = vs_spec["weekdays"] if period_type not in ["whole_week", "day_specific"]: raise NotImplementedError() # produce a data structure equal to the "day_specific" structure if period_type == "whole_week": time_exceptions = {day: exceptions_details for day in defines.weekday_ids()} else: # specific days time_exceptions = exceptions_details return { day: self._time_ranges_from_valuespec(time_exceptions[day]) for day, time_ranges in time_exceptions.items() if time_ranges }
def _to_valuespec(self, tp_spec): if not tp_spec: return {} exceptions = [] for exception_name, time_ranges in tp_spec.items(): if exception_name not in defines.weekday_ids() + ["alias", "exclude"]: exceptions.append((exception_name, self._time_ranges_to_valuespec(time_ranges))) vs_spec = { "name": self._name, "alias": tp_spec.get("alias", ""), "weekdays": self._weekdays_to_valuespec(tp_spec), "exclude": tp_spec.get("exclude", []), "exceptions": sorted(exceptions), } return vs_spec
def _from_vars(self): self._timeperiods = watolib.timeperiods.load_timeperiods() self._name = html.request.var("edit") # missing -> new group self._new = self._name is None if self._name in watolib.timeperiods.builtin_timeperiods(): raise MKUserError("edit", _("Builtin timeperiods can not be modified")) if self._new: clone_name = html.request.var("clone") if clone_name: self._name = clone_name self._timeperiod = self._get_timeperiod(self._name) else: # initialize with 24x7 config self._timeperiod = {day: [("00:00", "24:00")] for day in defines.weekday_ids()} else: self._timeperiod = self._get_timeperiod(self._name)
def action(self): if not html.check_transaction(): return vs_ical = self._vs_ical() ical = vs_ical.from_html_vars("ical") vs_ical.validate_value(ical, "ical") filename, _ty, content = ical['file'] try: data = self._parse_ical(content, ical['horizon']) except Exception as e: if config.debug: raise raise MKUserError('ical_file', _('Failed to parse file: %s') % e) html.request.set_var('alias', data.get('descr', data.get('name', filename))) for day in defines.weekday_ids(): html.request.set_var('%s_0_from' % day, '') html.request.set_var('%s_0_until' % day, '') html.request.set_var('except_count', "%d" % len(data['events'])) for index, event in enumerate(data['events']): index += 1 html.request.set_var('except_%d_0' % index, event['date']) html.request.set_var('except_indexof_%d' % index, "%d" % index) if ical["times"]: for n, time_spec in enumerate(ical["times"]): start_time = ":".join("%02d" % x for x in time_spec[0]) end_time = ":".join("%02d" % x for x in time_spec[1]) html.request.set_var('except_%d_1_%d_from' % (index, n), start_time) html.request.set_var('except_%d_1_%d_until' % (index, n), end_time) return "edit_timeperiod"
def _has_same_time_specs_during_whole_week(self, tp_spec): """Put the time ranges of all weekdays into a set to reduce the duplicates to see whether or not all days have the same time spec and return True if they have the same.""" unified_time_ranges = set( tuple(tp_spec.get(day, [])) for day in defines.weekday_ids()) return len(unified_time_ranges) == 1
def group_by_wday(t): wday = time.localtime(t).tm_wday return defines.weekday_ids()[wday], window_start(t, 86400)
def _group_by_wday(t: Timestamp) -> Tuple[Timegroup, Timestamp]: wday = time.localtime(t).tm_wday return Timegroup(defines.weekday_ids()[wday]), _window_start(t, 86400)
def group_by_wday(t): # type: (Timestamp) -> Tuple[Timegroup, Timestamp] wday = time.localtime(t).tm_wday return defines.weekday_ids()[wday], window_start(t, 86400)