示例#1
0
    def start(self):
        w = self.contained.get_week()
        # assume start time of 8:00 ET, to be converted to UT below,
        # if necessary.
        dt = datetime(w.year, w.month, w.day, 8)

        if self.TZ != 'ET':
            dt = TimeAgent.est2utc(dt)

        return dt
示例#2
0
def _get_incidental_events(today, timezone):
    """
    Gathers up all the non-maintenance-period maintenance activities,
    and returns them in a list of CalEvent objects.
    """

    utc_today = TimeAgent.est2utc(today) if timezone == "ET" else today

    mas = (
        Maintenance_Activity.objects.filter(_start__gte=utc_today)
        .filter(_start__lt=utc_today + timedelta(days=1))
        .filter(group=None)
        .filter(deleted=False)
        .order_by("_start")
    )

    if mas.exists():
        ev = CalEventIncidental(mas, TZ=timezone)
        return [ev]

    return []
示例#3
0
    def read(self, request, *args, **kws):
        if len(args) == 1:
            tz,          = args
            startPeriods = request.GET.get("startPeriods", datetime.now().strftime("%Y-%m-%d"))
            daysPeriods  = request.GET.get("daysPeriods",  '14')

            dt           = TimeAgent.str2dt(startPeriods)
            start        = dt if tz == 'UTC' else TimeAgent.est2utc(dt)
            duration     = int(daysPeriods) * 24 * 60
            periods      = Period.get_periods(start, duration)
            pjson = [DssPeriodHttpAdapter(p).jsondict(tz) for p in periods]
            return HttpResponse(
                json.dumps(dict(total   = len(periods)
                              , periods = pjson
                              , success = 'ok'))
              , content_type = "application/json")
        else:
            tz, id = args
            p      = Period.objects.get(id = id)
            return HttpResponse(
                json.dumps(dict(DssPeriodHttpAdapter(p).jsondict(tz)
                              , success = 'ok'))
              , content_type = "application/json")
示例#4
0
    def transfer_fixed_periods(self, semester):
        """
        We can dump Carl's DB into MySQL tables and use these to suck
        whatever info we need in addition to what is in the DB that
        Carl dumped to.
        Here we will take all 'scheduled dates' and replicate them
        as periods so that in the simulations they get translated
        into fixed periods that we pack around.
        The tricky part is creating the correct projects & sessions:
        Maintanence & Shutdown is easy, but the different types of tests
        need the appropriate project & session names, along w/ appropriate
        observer.
        """

        self.total_periods_before = Period.objects.all()
        self.period_ids_before = []

        for i in self.total_periods_before:
            self.period_ids_before.append(i.id)

        testingTypes = ['Tests', 'Calibration', 'Commissioning']

        # Only transfer fixed periods from schedtime table that cover
        start, end = self.get_schedtime_dates(semester)

        # prepare for transfering over fixed periods by creating the
        # necessary projects & session we know we'll need
        self.create_project_and_session( semester
                                       , "Maintenance"
                                       , "non-science"
                                       , "Maintenance"
                                       , "maintenance")
        self.create_project_and_session( semester
                                       , "Shutdown"
                                       , "non-science"
                                       , "Shutdown"
                                       , "maintenance")


        query = """
        SELECT `etdate`, `startet`, `stopet`, `lengthet`, `type`, `pcode`, `vpkey`, `desc`,
               `bands`, `be`, `observers`
        FROM `schedtime`
        WHERE `etdate` >= %s AND `etdate` < %s
        ORDER BY `etdate`, `startet`
        """ % (start, end)

        self.cursor.execute(query)
        rows = self.cursor.fetchall()

        for row in rows:
            #print row
            # translate row:
            # first, datetime info
            dt = row[0]
            year = int(dt[:4])
            month = int(dt[4:6])
            day = int(dt[6:])

            start_time = row[1]
            hour = int(start_time[:2])
            minutesTrue = int(start_time[2:])

            # DSS operates on hourly quarters: so minutes must be -
            # 0, 15, 30, 45
            # round down starttime to avoid overlaps!
            if 0 <= minutesTrue and minutesTrue < 15:
                minute = 0
            elif 15 <= minutesTrue and minutesTrue < 30:
                minute = 15
            elif 30 <= minutesTrue and minutesTrue < 45:
                minute = 30
            else:
                minute = 45

            # raise an alarm?
            if minute != minutesTrue:
                print >> sys.stderr, "minutes changed from %d to %d for row: " % (minutesTrue, minute), row

            durationHrs = float(row[3].strip())

            # DSS operates on hourly quarters: we need to truncate these
            # down to the nearest quarter to avoid overlaps
            duration = (int((durationHrs * 60) / 15) * 15 ) / 60.0

            # raise an alarm?
            if abs(duration - durationHrs) > 0.01:
                print >> sys.stderr, "duration changed from %f to %f for row: " % (durationHrs, duration), row

            # create the starttime - translate from ET to UT
            start = TimeAgent.est2utc(datetime(year, month, day, hour, minute))

            # get other row values that we'll always need
            type = row[4].strip()
            pcode = row[5].strip()
            try:
                original_id = int(row[6])
            except:
                original_id = None



            # what session to link this to?
            if type in testingTypes:
                s = self.get_testing_session(row, duration, semester)
            elif type == "Maintenance":
                # Maintenance is simple
                s = Sesshun.objects.filter(name = "Maintenance")[0]
            elif type == "Shutdown":
                # Shutdown is simple - not a whole lot going on
                s = Sesshun.objects.filter(name = "Shutdown")[0]
            elif type == "Astronomy":
                # Astronomy is only complicated if something's not right
                # can we use the vpkey?
                if original_id is not None and original_id != 0:
                    # simple case - we're done
                    #print "looking for original_id: ", original_id
                    s = Sesshun.objects.filter(original_id = original_id)[0]
                elif pcode is not None and pcode != "":
                    # try getting a session from the project - we rarely see it
#                    print "Getting Session from pcode: ", pcode
                    p = Project.objects.get(pcode = pcode)
                    s = p.sesshun_set.all()[0] # totally arbitrary!
                else:
                    # failure: this will raise an alarm
                    s = None
            else:
                raise "Unknown Type in Schedtime table."

            # don't save stuff that will cause overlaps
            causesOverlap = self.findOverlap(start, duration)

            if s is not None:

                # check for problems
                # are we assigning fixed periods for open sessions?
                if s.session_type.type == 'open':
                    print >> sys.stderr, "Period fixed for Session of type: ",\
                          s.session_type.type, s, start, duration
                    if duration > s.max_duration or duration < s.min_duration:
                        print >> sys.stderr, "Open Session duration (%f) does not honor min/max: %f/%f"\
                            % (duration, s.min_duration, s.max_duration)
                        print >> sys.stderr, s

                # don't save it off if it caused an overlap
                if causesOverlap:
                    print >> sys.stderr, "Causes Overlap!: ", s, start, duration
                else:
                    #NOTE: we are no longer using windows
                    # instead, just saves these off as periods
                    pa = Period_Accounting(scheduled = duration)
                    pa.save()
                    pending = Period_State.get_state("P")
                    p = Period(session    = s
                             , start      = start
                             , duration   = duration
                             , score      = 0.0
                             , forecast   = datetime.now()
                             , backup     = False
                             , state      = pending
                             , accounting = pa)
                    p.save()
                    # keep track of this added one so we can
                    # check for subsequent overlaps
                    self.times.append((s, start, duration))
            else:
                # warn the user:
                print >> sys.stderr, "Schedtime2DSS: could not find session for row: ", row
示例#5
0
 def set_start(self, start, tzname = None):
     if tzname == 'ET':
         self._start = TimeAgent.est2utc(start)
     else:
         self._start = start
示例#6
0
def get_gbt_schedule_events(start, end, timezone, ignore_non_maint_period_maint_events=False):
    """
    Generate a list of schedule events.  The list returned consists of
    tuples: first element is a datetime, the second element is the
    list of events for that date.
    """
    days = (end - start).days
    calendar = []
    one_day = timedelta(days=1)
    utc_start = TimeAgent.est2utc(start) if timezone == "ET" else start
    old_monday = None

    for i in range(0, days):
        daily_events = []

        # must use UTC equivalents for database lookups if times given
        # in Eastern Time
        today = start + timedelta(days=i)
        utc_today = TimeAgent.est2utc(today) if timezone == "ET" else today
        utc_yesterday = utc_today - one_day
        utc_tomorrow = utc_today + one_day

        # get the Monday for the week.  The maintenance activity
        # groups are retrieved for the entire week, so we do this only
        # once per week.
        monday = today - timedelta(today.weekday())
        # if we go from Monday to Monday in ETC then we must convert
        # to the equivalent of Monday 00:00 ET into UTC to get the right
        # time range.  If already in UT, then it will stay whatever
        # 'monday' is set to.
        monday_in_utc = TimeAgent.est2utc(monday) if timezone == "ET" else monday

        if monday != old_monday:
            mags = Maintenance_Activity_Group.get_maintenance_activity_groups(monday_in_utc)
            old_monday = monday

        # Include previous day's periods because last one may end
        # today.  Perhaps there is a way to do this exclusively via
        # query, but there aren't that many periods in a day.  Exclude
        # the maintenance periods, because they are obtained above.
        ps = (
            Period.objects.filter(start__gte=utc_yesterday)
            .filter(start__lt=utc_tomorrow)
            .filter(state__name="Scheduled")
            .exclude(session__observing_type__type="maintenance")
        )

        for p in ps:
            if p.end() > utc_today:
                # periods can be everything non-maintenance
                ev = CalEventPeriod(
                    p, p.start < utc_today, p.end() > utc_tomorrow, True if not (p.moc is False) else False, timezone
                )
                daily_events.append(ev)

        daily_events += _get_fixed_maint_events(mags, today, timezone)

        # if today is monday, get floating maintenance events for the week
        if today.weekday() == 0:
            daily_events += _get_floating_maint_events(mags, timezone)

        # finally gather up the non-maintenance-period maintenance events
        if not ignore_non_maint_period_maint_events:
            daily_events += _get_incidental_events(today, timezone)

        # now sort the events and add to the calendar list
        daily_events.sort()
        calendar.append((today, daily_events))

    return calendar
示例#7
0
    def read(self, request, *args, **kws):

        tz = args[0]
        # one or many?
        if len(args) == 1:
            # we are getting periods from within a range of dates
            sortField = jsonMap.get(request.GET.get("sortField", "start"), "start")
            order = "-" if request.GET.get("sortDir", "ASC") == "DESC" else ""

            # Either filter by date, or by something else.
            filterWnd = request.GET.get("filterWnd", None)

            # make sure we have defaults for dates
            defStart = datetime.now().strftime("%Y-%m-%d") if filterWnd is None else None
            defDays = "1" if filterWnd is None else None

            # Filtering by date involves a pair of keywords
            filterWnd = request.GET.get("filterWnd", None)
            filterElc = request.GET.get("filterElc", None)

            # make sure we have defaults for dates
            defStart = datetime.now().strftime("%Y-%m-%d") if filterWnd is None and filterElc is None else None
            defDays = "1" if filterWnd is None and filterElc is None else None

            startPeriods = request.GET.get("startPeriods", defStart)
            daysPeriods = request.GET.get("daysPeriods", defDays)

            if startPeriods is not None and daysPeriods is not None:
                if startPeriods is None:
                    startPeriods = datetime.now().strftime("%Y-%m-%d")
                if daysPeriods is None:
                    daysPeriods = "1"
                dt = TimeAgent.str2dt(startPeriods)
                start = dt if tz == "UTC" else TimeAgent.est2utc(dt)
                duration = int(daysPeriods) * 24 * 60
                periods = Period.get_periods(start, duration)
            else:
                # filter by something else
                query_set = Period.objects

                # window id
                # filterWnd = request.GET.get("filterWnd", None)
                if filterWnd is not None:
                    wId = int(filterWnd)
                    query_set = query_set.filter(window__id=wId)

                # elective id
                # filterElc = request.GET.get("filterElc", None)
                if filterElc is not None:
                    eId = int(filterElc)
                    query_set = query_set.filter(elective__id=eId)

                periods = query_set.order_by(order + sortField)

            return HttpResponse(
                json.dumps(
                    dict(total=len(periods), periods=[PeriodHttpAdapter(p).jsondict(tz) for p in periods], success="ok")
                ),
                content_type="application/json",
            )
        else:
            # we're getting a single period as specified by ID
            p_id = int(args[1])
            # p       = Period.objects.get(id = p_id)
            p = get_object_or_404(Period, id=p_id)
            adapter = PeriodHttpAdapter(p)
            return HttpResponse(
                json.dumps(dict(period=adapter.jsondict(tz), success="ok")), content_type="application/json"
            )
示例#8
0
文件: views.py 项目: mmccarty/nell
def scheduling_email(request, *args, **kwds):
    address_key = ["observer_address", "changed_address", "staff_address"]
    subject_key = ["observer_subject", "changed_subject", "staff_subject"]
    body_key    = ["observer_body", "changed_body", "staff_body"]
    email_key   = ["observer", "changed", "staff"]

    if request.method == 'GET':
        # Show the schedule from now until 8am eastern 'duration' days from now.
        start    = datetime.utcnow()
        duration = int(request.GET.get("duration"))
        end      = TimeAgent.est2utc(TimeAgent.utc2est(start + timedelta(days = duration - 1))
                                     .replace(hour = 8, minute = 0, second = 0,
                                              microsecond = 0))

        # The class that sets up the emails needs the periods in the
        # scheduling range, and all the periods in the future.
        currentPs = list(Period.objects.filter(start__gt = start
                                             , start__lt = end))
        futurePs  = list(Period.objects.filter(start__gte = start).order_by("start"))
        notifier.setPeriods(currentPs, futurePs)

        return HttpResponse(
            json.dumps({
                'observer_address' : notifier.getAddresses("observer"),
                'observer_subject' : notifier.getSubject("observer"),
                'observer_body'    : notifier.getBody("observer"),
                'changed_address'  : notifier.getAddresses("changed"),
                'changed_subject'  : notifier.getSubject("changed"),
                'changed_body'     : notifier.getBody("changed"),
                'staff_address'    : notifier.getAddresses("staff"),
                'staff_subject'    : notifier.getSubject("staff"),
                'staff_body'       : notifier.getBody("staff"),
                'obs_periods'      : [p.id for p in notifier.observingPeriods],
                'changed_periods'  : [p.id for p in notifier.changedPeriods]
            })
          , mimetype = "text/plain")

    elif request.method == 'POST':
        # here we are overriding what/who gets sent for the first round
        # of emails
        for i in xrange(3):
            addr = str(request.POST.get(address_key[i], "")).replace(" ", "").split(",")
            notifier.setAddresses(email_key[i], addr)
            notifier.setSubject(email_key[i], request.POST.get(subject_key[i], ""))
            notifier.setBody(email_key[i], request.POST.get(body_key[i], ""))

        notifier.notify()

        # Remember when we did this to allow time-tagging of the schedule
        sn = Schedule_Notification(date = datetime.utcnow())
        sn.save()

        # Emails for a given period shouldn't be sent more then is
        # necessary, so here we set the last_notification timestamp.
        # However, the client can change the recipients and text of the
        # 'changes' email - this ignores those changes.
        # See Story: https://www.pivotaltracker.com/story/show/14550249
        now = datetime.utcnow()
        set_periods_last_notification(now, request, "changed_periods")
        set_periods_last_notification(now, request, "obs_periods")

        return HttpResponse(json.dumps({'success':'ok'})
                          , mimetype = "text/plain")
    else:
        return HttpResponse(
                 json.dumps({'error': 'request.method is neither GET or POST!'})
               , mimetype = "text/plain")
示例#9
0
 def getUTCHour(self, dt, estHour):
     dtEst = datetime(dt.year, dt.month, dt.day, estHour)
     dtUtc = TimeAgent.est2utc(dtEst)
     return dtUtc.hour
示例#10
0
    def from_post(self, fdata, tz):
        # only update the score if something in the period has changed
        update_score = False
        if not update_score:
            update_score = self.period.id is None
        # if newly created then start with a default 
        if update_score:
            self.period.reinit_score()
        handle = fdata.get("handle", "")
        if handle:
            new_session = Sesshun.handle2session(handle)
            if not update_score:
                update_score = self.period.session != new_session
            self.period.session = new_session
        else:
            try:
                maintenance = Project.objects.get(pcode='Maintenance')
                self.period.session = Sesshun.objects.get(project=maintenance)
            except:
                self.period.session  = Sesshun.objects.get(id=fdata.get("session", 1))
        now           = TimeAgent.quarter(datetime.utcnow())
        date          = fdata.get("date", None)
        time          = fdata.get("time", "00:00")
        if date is None:
            self.period.start = now
        else:
            new_start = TimeAgent.quarter(strStr2dt(date, time + ':00'))
            if tz == 'ET':
                new_start = TimeAgent.est2utc(self.period.start)
            if not update_score:
                update_score = self.period.start != new_start
            self.period.start = new_start
        new_duration = TimeAgent.rndHr2Qtr(float(fdata.get("duration", "1.0")))
        if not update_score:
            update_score = self.period.duration != new_duration
        self.period.duration = new_duration
        
        # if the score needs to be updated, then prepare it for this
        if update_score and now < self.period.start:
            self.period.reinit_score()
        self.period.backup   = True if fdata.get("backup", None) == 'true' else False
        stateAbbr = fdata.get("state", "P")
        self.period.state = Period_State.objects.get(abbreviation=stateAbbr)
        self.period.moc_ack = fdata.get("moc_ack", self.period.moc_ack)

        # elective? 
        eId = fdata.get("elective_id", None)
        if eId is not None:
            self.period.elective_id = eId

        # window?    
        wId = fdata.get("window_id", None)
        if wId is not None:
            self.period.window_id = wId
            try:
                win = Window.objects.get(id = wId)
            except Window.DoesNotExist:
                pass
            else:
                end = win.last_date()
                if end and date is None:
                    self.period.start = datetime(end.year, end.month, end.day)
                    self.period.duration = 1
                    
        elif self.period.session.isWindowed() and self.period.window_id is None:
            # just because the window id wasn't specified doesn't mean
            # we don't want to assign this a window:
            # for instance, if this period was created outside of the 
            # Windowed Period Explorer, we'll have to assign a window
            self.period.assign_a_window()

        # is this period a default period for a window?
        default = fdata.get("wdefault", None)
        if default is not None: #
            if default == "true" and self.period.window is not None:
                # assign this period as a default
                self.period.window.default_period = self.period
                self.period.window.save()
            elif default == "false" and self.period.window is not None:
                # unassign this period as a default
                self.period.window.default_period = None
                self.period.window.save()
            
        # how to initialize scheduled time? when they get published!
        # so, only create an accounting object if it needs it.
        if self.period.accounting is None:
            schd = self.period.duration if self.period.isScheduled() else 0.0 
            pa = Period_Accounting(scheduled = schd)
            pa.save()
            self.period.accounting = pa

        self.period.accounting.update_from_post(fdata)

        self.period.save()

        # now that we have an id (from saving), we can specify the relation
        # between this period and assocaited rcvrs
        self.update_rcvrs_from_post(fdata)