예제 #1
0
def create_task():
    post_body = json.loads(request.data)
    task = Task(description=post_body.get('description'),
                done=bool(post_body.get('done')))
    db.session.add(task)
    db.session.commit()
    return json.dumps({'success': True, 'data': task.serialize()}), 201
예제 #2
0
def scaner():
    """
    Main method to get data from queue. Get every 2 sec.
    :return:
    """
    engine = sa.create_engine(dsn)
    conn = engine.connect()
    executor = ThreadPoolExecutor(max_workers=4)

    while True:
        tasks = conn.execute(
            sa.select([Task]).where(
                sa.and_(Task.c.iscomplete == False,
                        Task.c.inprocess == False)))
        for task in tasks:
            try:
                conn.execute(Task.update().values(inprocess=True).where(
                    Task.c.id == task.id))
                executor.submit(scan, task, conn)
            except Exception as e:
                print(type(e), e)
            finally:
                conn.execute(Task.update().values(
                    inprocess=False,
                    iscomplete=True).where(Task.c.id == task.id))
            gc.collect()
        sleep(2)
예제 #3
0
파일: taskcmd.py 프로젝트: ryanakca/yokadi
        def taskHasWantedKeywordDict(task, wantedKeywordDict):
            """
            @param task: task object
            @param wantedKeywordDict: dict of name/value of wanted keyword
            # a task is considered a subset of wantedKeywordDict if:
            # 1. All wantedKeywordDict keys are in task or project keywords
            # 2. All wantedKeywordDict valued keywords have the same value
            #    in task or project keyword"""
            for wantedKeyword, wantedValue in wantedKeywordDict.items():
                taskFilters=[Task.q.id==task.id,
                         TaskKeyword.q.taskID==task.id,
                         TaskKeyword.q.keywordID==Keyword.q.id,
                         LIKE(Keyword.q.name, wantedKeyword)]

                projectFilters=[Project.q.id==task.projectID,
                                ProjectKeyword.q.projectID==Project.q.id,
                                ProjectKeyword.q.keyword==Keyword.q.id,
                                LIKE(Keyword.q.name, wantedKeyword)]

                if wantedValue:
                    taskFilters.append(TaskKeyword.q.value==wantedValue)
                    projectFilters.append(ProjectKeyword.q.value==wantedValue)

                if Task.select(AND(*taskFilters)).count()==0 and Task.select(AND(*projectFilters)).count()==0:
                    return False
            # All critera were met, return ok
            return True
예제 #4
0
파일: taskcmd.py 프로젝트: ryanakca/yokadi
    def do_t_reorder(self, line):
        """Reorder tasks of a project.
        It works by starting an editor with the task list: you can then change
        the order of the lines and save the list. The urgency field will be
        updated to match the order.
        t_reorder <project_name>"""
        project = Project.byName(projectName)
        taskList = Task.select(AND(Task.q.projectID == project.id,
                                   Task.q.status    != 'done'),
                               orderBy=-Task.q.urgency)
        lines = [ "%d,%s" % (x.id, x.title) for x in taskList]
        text = tui.editText("\n".join(lines))

        ids = []
        for line in text.split("\n"):
            line = line.strip()
            if not "," in line:
                continue
            id = int(line.split(",")[0])
            ids.append(id)

        ids.reverse()
        for urgency, id in enumerate(ids):
            task = Task.get(id)
            task.urgency = urgency
예제 #5
0
    def test_deps_text(self):
        text = ''
        task1 = Task(chat=1,
                     name='{}'.format(text),
                     status='TODO',
                     dependencies='',
                     parents='',
                     priority='')
        task2 = Task(chat=1,
                     name='{}'.format(text),
                     status='TODO',
                     dependencies='1,2,',
                     parents='',
                     priority='')
        task3 = Task(chat=1,
                     name='{}'.format(text),
                     status='TODO',
                     dependencies='2,',
                     parents='',
                     priority='')

        db.session.add(task1)
        db.session.add(task2)
        db.session.add(task3)
        db.session.commit()

        chat = 1
        preceed = ''

        assert text == Services().deps_text(task1, chat, preceed)
예제 #6
0
    def duplicate(self, message, chat, apiBot):
        """ Function description.
            :type message: string
            :type chat: int
        """
        if message.isdigit():
            task_id = int(message)
            try:
                task = self.find_task(task_id, chat)
            except sqlalchemy.orm.exc.NoResultFound:
                self.id_error_message(message, chat, apiBot)
                return

            duplicated_task = Task(chat=task.chat,
                                   name=task.name,
                                   status=task.status,
                                   dependencies=task.dependencies,
                                   parents=task.parents,
                                   priority=task.priority,
                                   duedate=task.duedate)
            db.session.add(duplicated_task)

            for dependent_task_id in task.dependencies.split(',')[:-1]:
                dependent_task = self.find_task(dependent_task_id, chat)
                dependent_task.parents += '{},'.format(duplicated_task.id)

            issue = repository.create_issue(duplicated_task.name)
            duplicated_task.issue_number = issue.number
            db.session.commit()
            apiBot.send_message(
                "New task *TODO* [[{}]] {}".format(duplicated_task.id,
                                                   duplicated_task.name), chat)
        else:
            self.id_error_message(message, chat, apiBot)
예제 #7
0
파일: app.py 프로젝트: cesard90/optix-demo
def save_task(task_request, job_id):
    task = Task()
    task.name = task_request['name']
    task.sequence = task_request['sequence']
    task.job_id = job_id
    session.add(task)
    session.commit()
    save_taskqueue(task_request, task.id)
    return 'ok'
예제 #8
0
def create_task(name, description, date, budget, event_id):
    new_task = Task(
        name=name,
        description=description,
        date=date,
        budget=budget,
        event_id=event_id
    )
    db.session.add(new_task)
    db.session.commit()
    return new_task.serialize()
예제 #9
0
def create_task():
    body = json.loads(request.data)

    new_task = Task(description=body['description'],
                    done=body.get('done', False)
                    # 無法取得數值時,給予初始值避免出錯
                    )

    db.session.add(new_task)
    db.session.commit()
    return success_response(new_task.serialize(), 201)
예제 #10
0
    def testAdd(self):
        tui.addInputAnswers("y", "2", "4", "123")
        self.cmd.do_bug_add("x t1")

        tasks = list(Task.select())
        result = [x.title for x in tasks]
        expected = [u"t1"]
        self.assertEqual(result, expected)

        kwDict = Task.get(1).getKeywordDict()
        self.assertEqual(kwDict, dict(_severity=2, _likelihood=4, _bug=123))
예제 #11
0
def api_feature(pid):
    user = get_user()
    project = Project.get(Project.id == pid)
    if user and request.method == 'POST' and project.can_validate:
        ref_and_audit = request.get_json()
        if ref_and_audit and len(ref_and_audit) == 2:
            skipped = ref_and_audit[1] is None
            feat = Feature.get(Feature.project == project, Feature.ref == ref_and_audit[0])
            user_did_it = Task.select(Task.id).where(
                Task.user == user, Task.feature == feat).count() > 0
            Task.create(user=user, feature=feat, skipped=skipped)
            if not skipped:
                if len(ref_and_audit[1]):
                    new_audit = json.dumps(ref_and_audit[1], sort_keys=True, ensure_ascii=False)
                else:
                    new_audit = None
                if feat.audit != new_audit:
                    feat.audit = new_audit
                    feat.validates_count = 1
                elif not user_did_it:
                    feat.validates_count += 1
                feat.save()
    fref = request.args.get('ref')
    if fref:
        feature = Feature.get(Feature.project == project, Feature.ref == fref)
    elif not user or request.args.get('browse') == '1':
        feature = Feature.select().where(Feature.project == project).order_by(fn_Random()).get()
    else:
        try:
            # Maybe use a join: https://stackoverflow.com/a/35927141/1297601
            task_query = Task.select(Task.id).where(Task.user == user, Task.feature == Feature.id)
            query = Feature.select().where(
                Feature.project == project, Feature.validates_count < 2).where(
                    ~fn.EXISTS(task_query)).order_by(fn_Random())
            if project.validate_modified:
                query = query.where(Feature.action == 'm')
            if user.bboxes:
                bboxes = BBoxes(user)
                feature = None
                for f in query:
                    if bboxes.contains(f.lat/1e7, f.lon/1e7):
                        feature = f
                        break
                    elif not feature:
                        feature = f
                if not feature:
                    raise Feature.DoesNotExist()
            else:
                feature = query.get()
        except Feature.DoesNotExist:
            return jsonify(feature={}, ref=None, audit=None)
    return jsonify(feature=json.loads(feature.feature), ref=feature.ref,
                   audit=json.loads(feature.audit or 'null'))
예제 #12
0
    def testAdd(self):
        tui.addInputAnswers("y")
        self.cmd.do_t_add("x t1")

        tui.addInputAnswers("y", "y")
        self.cmd.do_t_add("x @kw1 @kw2=12 t2")

        tasks = list(Task.select())
        result = [x.title for x in tasks]
        expected = [u"t1", u"t2"]
        self.assertEqual(result, expected)

        kwDict = Task.get(2).getKeywordDict()
        self.assertEqual(kwDict, dict(kw1=None, kw2=12))
예제 #13
0
파일: db_test.py 프로젝트: firerml/Tasker
 def setUp(self):
     with patch('db.datetime') as mock_datetime:
         mock_datetime.now.return_value = default_timestamp
         self.DB = Database(TEST_DB_URL)
         session = self.DB.sessionmaker()
         session.add(
             Task(assigner_id=user1,
                  assignee_id=user2,
                  description='order lunch'))
         session.add(
             Task(assigner_id=user1,
                  assignee_id=user2,
                  description='eat lunch'))
         session.commit()
예제 #14
0
    def testLastTaskId(self):
        # Using "_" with no prior task activity should raise an exception   
        self.assertRaises(YokadiException, self.cmd.getTaskFromId, "_")

        tui.addInputAnswers("y")
        self.cmd.do_t_add("x t1")
        task1 = Task.get(1)
        self.assertEqual(self.cmd.getTaskFromId("_"), task1)

        self.cmd.do_t_add("x t2")
        task2 = Task.get(2)
        self.assertEqual(self.cmd.getTaskFromId("_"), task2)

        self.cmd.do_t_mark_started("1")
        self.assertEqual(self.cmd.getTaskFromId("_"), task1)
예제 #15
0
def new_task(chat, msg):

    from datetime import datetime
    task = Task(chat=chat,
                name=msg,
                status='TODO',
                description='No description.',
                priority='None',
                duedate='')

    task.duedate = datetime.strptime(task.duedate, '')
    db.session.add(task)
    db.session.commit()

    send_message("New task *TODO* [[{}]] {}".format(task.id, task.name), chat)
예제 #16
0
    def end(self):
        # Adjust idColumn
        maxId = Task.select().max(Task.q.id)
        self.idColumn.width = max(2, len(str(maxId)))

        # Adjust dueColumn
        shortDateFormat = self.termWidth < 100
        if shortDateFormat:
            self.dueColumn.width = 8
        else:
            self.dueColumn.width = 26
        self.dueColumn.formater = DueDateFormater(self.today, shortDateFormat)

        # Adjust titleColumn
        self.titleColumn.width = self.maxTitleWidth
        totalWidth = sum([x.width for x in self.columns])
        if totalWidth > self.termWidth:
            self.titleColumn.width -= (totalWidth - self.termWidth) + len(self.columns)
        self.titleColumn.formater = TitleFormater(self.titleColumn.width)

        # Print table
        for sectionName, taskList in self.taskLists:
            self._renderTaskListHeader(sectionName)
            for task in taskList:
                self._renderTaskListRow(task)
예제 #17
0
 def setUp(self):
     self.task = Task(chat=1,
                      name="teste",
                      status='TODO',
                      dependencies='',
                      parents='2, 3',
                      priority='')
예제 #18
0
def project(name):
    project = Project.get(Project.name == name)
    desc = project.description.replace('\n', '<br>')
    cnt = project.feature_count
    val1 = Feature.select(Feature.id).where(Feature.project == project,
                                            Feature.validates_count > 0)
    val2 = Feature.select(Feature.id).where(Feature.project == project,
                                            Feature.validates_count >= 2)
    if project.validate_modified:
        val1 = val1.where(Feature.action == 'm')
        val2 = val2.where(Feature.action == 'm')
        cnt = Feature.select(Feature.id).where(Feature.project == project,
                                               Feature.action == 'm').count()
    corrected = Feature.select(Feature.id).where(
        Feature.project == project, Feature.audit.is_null(False), Feature.audit != '').count()
    skipped = Feature.select(Feature.id).where(
        Feature.project == project, Feature.audit.contains('"skip": true')).count()
    user = get_user()
    if user:
        has_skipped = Task.select().join(Feature).where(
            Task.user == user, Task.skipped == True, Feature.project == project).count() > 0
    else:
        has_skipped = False
    return render_template('project.html', project=project, admin=is_admin(user, project),
                           count=cnt, desc=desc, val1=val1.count(), val2=val2.count(),
                           corrected=corrected, skipped=skipped,
                           has_skipped=has_skipped)
예제 #19
0
def get_or_create_task_for_user(user, date=None, ip=None):
    if not date:
        date = today()
    try:
        task_obj = Task.get(Task.user == user, Task.day == date)
        if task_obj.task not in get_tasks(user.level):
            task_obj.task = random_task_for_user(user)
            task_obj.save()
    except Task.DoesNotExist:
        if ip:
            task_name = random_task_for_ip(ip)
        else:
            task_name = random_task_for_user(user)
        task_obj = Task(user=user, day=date, task=task_name)
        task_obj.save()
    return task_obj
예제 #20
0
    def startGeneratingTasks(self, message):
        _log.debug("sleeping some time")
        some_locations = [[2, 9], [3, 10], [3, 9], [3, 11], [4, 4], [4, 1.5],
                          [2.5, 9], [4, 10], [4, 11]]
        number_of_locations = randint(1, 4)
        locations_to_visit = []
        for _ in range(number_of_locations):
            loc = randint(0, len(some_locations) - 1)
            locations_to_visit.append(some_locations[loc])
        locations = locations_to_visit

        user = "******"
        status = 'pending'
        locations = [Point(l) for l in locations]
        new_task = Task(username=user, locations=locations, status=status)
        try:
            self.session.add(new_task)
            self.session.commit()
            entry_id = new_task.id
            _log.debug("-------------------------sending new request")
            self.send_message(to=settings.SCHEDULER, directive="request",\
                                           body = {'locations':locations, 'request_id':entry_id})
            yield from asyncio.sleep(30)
            self.send_message(to="generator", directive="start")

        except Exception as e:
            self.session.rollback()
            self.set_status(400)
예제 #21
0
파일: main.py 프로젝트: hojovi/shanbei
def todayWord():
    if current_user.task is None:
        current_user.task=Task(user=current_user,wordNumPerDay=0)
        session.commit()
    if session.query(HistoryTask).filter(HistoryTask.user==current_user,HistoryTask.taskTime==date.today()).count()==0:
        history=HistoryTask(userId=current_user.id,taskTime=date.today(),plan=current_user.task.wordNumPerDay,complete=0)
        session.add(history)
        session.commit()
    else:
        history=session.query(HistoryTask).filter(HistoryTask.user==current_user,HistoryTask.taskTime==date.today()).first()
    need=history.plan-history.complete
    # print(need)
    count=session.query(Word).filter(Word.progresses.any(and_(Progress.progress<5,Progress.userId==current_user.id))).count()
    # print(count)
    try:
        if count<need:
            extendProgressCount=extendProgress(current_user, 1000)
            if count==0 and extendProgressCount.rowcount==0:
                return error({'message':'您已背完所有单词!'})
        if need<=0:
            return success({'words':[]})
        progresses=session.query(Progress).filter(Progress.userId==current_user.id,Progress.progress<5).order_by(Progress.progress).limit(need).all()
        # print(progresses)
        words=[progress.word.asDict() for progress in progresses]
        return success({'words':words})
    except Exception as e:
        print(e)
        import traceback
        traceback.print_exc()
        session.rollback()
        return error({'message':"抱歉出现错误,请发送详细内容到[email protected]"})
    def duplicate(self, bot, update, args):
        if args[0].isdigit():
            task_id = int(args[0])
            query = db.session.query(Task).filter_by(
                id=task_id, chat=update.message.chat_id)
            try:
                task = query.one()
            except sqlalchemy.orm.exc.NoResultFound:
                self.services.not_found_message(bot, update, task_id)
                return

            dtask = Task(chat=task.chat, name=task.name, status=task.status,
                         dependencies=task.dependencies, parents=task.parents,
                         priority=task.priority, duedate=task.duedate)
            db.session.add(dtask)

            for each_task in task.dependencies.split(',')[:-1]:
                each_query = db.session.query(Task).filter_by(
                    id=int(each_task), chat=update.message.chat_id)
                each_task = each_query.one()
                each_task.parents += '{},'.format(dtask.id)

            db.session.commit()
            bot.send_message(chat_id=update.message.chat_id,
                             text="New task *TODO* [[{}]] {}"
                             .format(dtask.id, dtask.name))
        else:
            bot.send_message(chat_id=update.message.chat_id,
                             text="You must inform the task id")
예제 #23
0
파일: yical.py 프로젝트: mathstuf/yokadi
def generateCal():
    cal = icalendar.Calendar()
    cal.add("prodid", '-//Yokadi calendar //yokadi.github.com//')
    cal.add("version", "2.0")
    # Add projects
    for project in Project.select(Project.q.active == True):
        todo = icalendar.Todo()
        todo.add("summary", project.name)
        todo["uid"] = PROJECT_UID % project.id
        cal.add_component(todo)
    # Add tasks
    for task in Task.select(Task.q.status != "done"):
        todo = icalendar.Todo()
        todo["uid"] = TASK_UID % task.id
        todo["related-to"] = PROJECT_UID % task.project.id
        todo.add("dtstamp", task.creationDate)
        todo.add("priority", task.urgency)
        todo.add("summary", "%s (%s)" % (task.title, task.id))
        todo.add("dtstart", task.creationDate)
        if task.dueDate:
            todo.add("due", task.dueDate)
        if task.description:
            todo.add("description", task.description)
        categories = [task.project, ] # Add project as a keyword
        if task.keywords:
            categories.extend([k.name for k in task.keywords])
        todo.add("categories", categories)
        cal.add_component(todo)

    return cal
    def duplicate(self, command, msg, chat):
        '''
        Duplica uma task
        '''
        msg = self.strip_message(msg)
        for i in range(len(msg)):
            if self.check_msg_not_exists(msg[i]):
                self.msg_no_task(chat)
            else:
                task_id = int(msg[i])

                try:
                    task = self.query_one(task_id, chat)
                except sqlalchemy.orm.exc.NoResultFound:
                    self.task_not_found_msg(task_id, chat)
                    continue
                dep_task = Task(chat=task.chat, name=task.name,
                                status=task.status,
                                dependencies=task.dependencies,
                                parents=task.parents,
                                priority=task.priority, duedate=task.duedate)
                db.session.add(dep_task)
                for t in task.dependencies.split(',')[:-1]:
                    query_dep = db.session.query(Task).\
                                                filter_by(id=int(t),
                                                          chat=chat)
                    t = query_dep.one()
                    t.parents += '{},'.format(dep_task.id)
                db.session.commit()
                text_message = 'New task *TODO* [[{}]] {}'
                self.send_message(text_message.format(dep_task.id,
                                                      dep_task.name),
                                  chat)
예제 #25
0
    def testRecurs(self):
        tui.addInputAnswers("y")
        self.cmd.do_t_add("x t1")
        task = Task.get(1)
        self.cmd.do_t_recurs("1 daily 10:00")
        desc = str(task.recurrence)
        self.cmd.do_t_recurs("1 weekly FR 23:00")
        self.cmd.do_t_recurs("1 none")
        self.cmd.do_t_recurs("1 weekly fr 23:00")
        self.cmd.do_t_recurs("1 weekly Fr 23:00")
        self.cmd.do_t_recurs("1 weekly Friday 23:00")
        self.cmd.do_t_recurs("1 monthly 3 13:00")
        self.cmd.do_t_recurs("1 monthly second friday 13:00")
        self.cmd.do_t_recurs("1 yearly 3/07 11:20")
        self.cmd.do_t_recurs("1 quarterly 14 11:20")
        self.cmd.do_t_recurs("1 quarterly first monday 23:20")
        self.assertNotEqual(desc, str(task.recurrence))
        self.assertEqual(task.status, "new")
        self.cmd.do_t_mark_done("1")
        self.assertEqual(task.status, "new")

        for bad_input in ("", # No task
                          "1", # No recurence
                          "1 foo", # Unknown recurrence
                          "1 daily", # No time
                          "1 weekly", # No day
                          "1 weekly monday", # No time
                          "1 monthly", # No day
                          "1 monthly 10", # No time
                          "1 quarterly", # No day
                          "1 quarterly 10", # No time
                          "1 monthly foo 12:00", # Bad date
                          ):
            self.assertRaises(YokadiException, self.cmd.do_t_recurs, bad_input)
예제 #26
0
def new_task(msg, chat):
    task = Task(chat=chat, name=msg, status='TODO',
                dependencies='', parents='', priority='')
    db.session.add(task)
    db.session.commit()
    send_message("New task *TODO* [[{}]] {}".format(task.id, task.name), chat)
    create_issue(task.name, 'Task ID: [{}]\n\ Task Name: {}'.format(task.id, task.name))
예제 #27
0
 def duplicate_assigment(msg, chat):
     if not msg.isdigit():
         self.u.send_message("You must inform the task id", chat)
     else:
         task_id = int(msg)
         query = db.session.query(Task).filter_by(id=task_id, chat=chat)
         try:
             task = query.one()
         except sqlalchemy.orm.exc.NoResultFound:
             self.u.send_message(
                 "_404_ Task {} not found x.x".format(task_id), chat)
             return
         dtask = Task(chat=task.chat,
                      name=task.name,
                      status=task.status,
                      dependencies=task.dependencies,
                      parents=task.parents,
                      priority=task.priority,
                      duedate=task.duedate)
         db.session.add(dtask)
         for t in task.dependencies.split(',')[:-1]:
             qy = db.session.query(Task).filter_by(id=int(t), chat=chat)
             t = qy.one()
             t.parents += '{},'.format(dtask.id)
         db.session.commit()
         self.u.send_message(
             "New task *TODO* [[{}]] {}".format(dtask.id, dtask.name),
             chat)
예제 #28
0
    def duplicate_task(cls, msg, chat):
        """This function duplicates the task."""
        if not msg.isdigit():
            return "You must inform the task id"
        else:
            task_id = int(msg)
            query = db.session.query(Task).filter_by(id=task_id, chat=chat)
            try:
                task = query.one()
            except sqlalchemy.orm.exc.NoResultFound:
                return "_404_ Task {} not found x.x".format(task_id)

            dtask = Task(chat=task.chat,
                         name=task.name,
                         status=task.status,
                         dependencies=task.dependencies,
                         parents=task.parents,
                         priority=task.priority,
                         overdue=task.overdue,
                         duedate=task.duedate)
            db.session.add(dtask)

            for dependency in task.dependencies.split(',')[:-1]:
                query = db.session.query(Task).filter_by(id=int(dependency),
                                                         chat=chat)
                dependency = query.one()
                dependency.parents += '{},'.format(dtask.id)

            db.session.commit()
            return "New task *TODO* [[{}]] {}".format(dtask.id, dtask.name)
예제 #29
0
def handle_file(code, task, file):
    task_obj = Task.get(name=task)
    data = get_data_for_code(code)
    if task_obj is None:
        return {"error": "Report type not found: " + str(task)}, 404

    committee = data["group"]["codeName"]
    year = str(data["year"])
    lp = str(data["study_period"])

    name = task + "_" + committee + "_" + year + "_" + lp + ".pdf"
    path = "./uploads/" + year + "/lp" + lp + "/" + str(
        data["meeting_no"]) + "/" + str(committee)

    if not os.path.exists(path):
        os.makedirs(path)

    save_loc = path + "/" + name

    print("Saving file " + str(file) + " in " + path)
    file.save(save_loc)

    code_file = CodeFile.get(code=code, task=task)
    if code_file is None:
        CodeFile(code=code, task=task, file_location=save_loc)
        return {"overwrite": False}
    else:
        print("OVERWRITE!")
        code_file.date = datetime.datetime.now()
        return {"overwrite": True}
예제 #30
0
파일: taskcmd.py 프로젝트: ryanakca/yokadi
 def do_t_purge(self, line):
     parser = self.parser_t_purge()
     options, args = parser.parse_args(line)
     filters=[]
     filters.append(Task.q.status=="done")
     filters.append(Task.q.doneDate<(datetime.now()-timedelta(days=options.delay)))
     tasks=Task.select(AND(*filters))
     if tasks.count()==0:
         print "No tasks need to be purged"
         return
     print "The following tasks will be removed:"
     print "\n".join(["%s: %s" % (task.id, task.title) for task in tasks])
     if options.force or tui.confirm("Do you really want to remove those tasks (this action cannot be undone)?"):
         Task.deleteMany(AND(*filters))
         print "Tasks deleted"
     else:
         print "Purge canceled"
예제 #31
0
def get_last_task_day(user):
    try:
        last_task = Task.select(Task.day).where(
            Task.user == user,
            Task.changeset.is_null(False)).order_by(Task.day.desc()).get()
        return last_task.day
    except Task.DoesNotExist:
        return None
예제 #32
0
def changeset():
    if 'osm_token' not in session:
        redirect(url_for('login'))

    cs_data = request.args.get('changeset')
    if not cs_data.strip():
        return redirect(url_for('front'))
    user = get_user()
    # TODO: call submit_changeset instead
    try:
        changeset = parse_changeset_id(cs_data)
        cs_date, conforms = validate_changeset(user, changeset, None,
                                               openstreetmap)
    except ValueError as e:
        flash(str(e))
        return redirect(url_for('front'))
    if not cs_date or cs_date != today():
        flash('Date of the changeset is wrong')
        return redirect(url_for('front'))
    task = Task.get(Task.user == user, Task.day == cs_date)
    try:
        last_task = Task.select(Task.day).where(
            Task.user == user,
            Task.changeset.is_null(False)).order_by(Task.day.desc()).get()
        is_streak = last_task.day == cs_date - cs_date.resolution
    except Task.DoesNotExist:
        is_streak = False
    task.changeset = changeset
    task.correct = conforms
    if is_streak:
        user.streak += 1
    else:
        user.streak = 1
    user.score += int(math.log(user.streak + 1, 2))
    if conforms:
        flash('An extra point for completing the task')
        user.score += 1
    if user.level < len(config.LEVELS) + 1:
        if user.score >= config.LEVELS[user.level - 1]:
            user.level += 1
            flash('Congratulations on gaining a level!')
    with database.atomic():
        task.save()
        user.save()
    flash('Changeset noted, thank you!')
    return redirect(url_for('front'))
def get_tasks():
    arr = []
    tasks = Task.select()
    for task in tasks:
        arr.append({"name": task.name, "display_name": task.display_name})

    print("===SAVING {0} {1}===".format(len(arr), "Tasks"))
    return arr
예제 #34
0
def taskIdCompleter(cmd, text, line, begidx, endidx):
    #TODO: filter on parameter position
    #TODO: potential performance issue with lots of tasks, find a better way to do it
    tasks=[x for x in Task.select(Task.q.status!='done') if str(x.id).startswith(text)]
    print
    for task in tasks:
        # Move that in a renderer class ?
        print "%s: %s / %s" % (task.id, task.project.name, task.title)
    return [str(x.id) for x in tasks]
예제 #35
0
def random_task_for_user(user):
    tasks = set(get_tasks(user.level))
    if not tasks:
        return None
    last_tasks = set([
        x[0] for x in Task.select(Task.task).where(Task.user == user).order_by(
            Task.day.desc()).limit(int(len(tasks) * 0.7)).tuples()
    ])
    return choice(list(tasks - last_tasks))
예제 #36
0
 def testMark(self):
     tui.addInputAnswers("y")
     self.cmd.do_t_add("x t1")
     task = Task.get(1)
     self.assertEqual(task.status, "new")
     self.cmd.do_t_mark_started("1")
     self.assertEqual(task.status, "started")
     self.cmd.do_t_mark_done("1")
     self.assertEqual(task.status, "done")
예제 #37
0
def create_task(journal_id):
    journal = Journal.query.filter_by(id = journal_id).first()
    if journal is None:
        return failure_response("Journal not found")
    
    body = json.loads(request.data)
    description = body.get("description")
    if description is None:
        return failure_response("No description provided")

    new_task = Task(
        description = description,
        done = body.get("done", False),
        journal_id = journal_id
    )
    db.session.add(new_task)
    db.session.commit()
    return success_response(new_task.serialize())
예제 #38
0
 def new(self, message, chat, apiBot):
     """ Function description.
         :type message: string
         :type chat: int
     """
     task = Task(chat=chat,
                 name=message,
                 status='TODO',
                 dependencies='',
                 parents='',
                 priority='low',
                 duedate=datetime.date(2100, 12, 12))
     issue = repository.create_issue(message)
     task.issue_number = issue.number
     db.session.add(task)
     db.session.commit()
     apiBot.send_message(
         "New task *TODO* [[{}]] {}".format(task.id, task.name), chat)
예제 #39
0
    def newTask(self, msg, chat):
        text, msg = self.checkMsg(msg)

        if text == '':
            task = Task(chat=chat,
                        name=msg,
                        status='TODO',
                        dependencies='',
                        parents='',
                        priority='')
            db.session.add(task)
            db.session.commit()
            self.send_message(
                "New task *TODO* [[{}]] {}".format(task.id, task.name), chat)
            self.upload_github_issue(
                task.name, 'ID : [{}]\n\
                                                Name : [{}]\n\
                                                Priority : [None]\n\
                                                Issue created from and with 404tasknotfoundbot tasks'
                .format(task.id, task.name))
        else:
            if text.lower() not in ['high', 'medium', 'low']:
                self.send_message(
                    "The priority *must be* one of the following: high, medium, low",
                    chat)
            else:
                priority = text.lower()
                task = Task(chat=chat,
                            name=msg,
                            status='TODO',
                            dependencies='',
                            parents='',
                            priority=priority)
                db.session.add(task)
                db.session.commit()
                self.send_message(
                    "New task *TODO* [[{}]] {} with priority {}".format(
                        task.id, task.name, task.priority), chat)
                self.upload_github_issue(
                    task.name, 'ID : [{}]\n\
                                                     Name : [{}]\n\
                                                     Priority : [{}]\n\
                                                     Issue created from and with 404tasknotfoundbot tasks'
                    .format(task.id, task.name, task.priority))
예제 #40
0
def new(chat, msg):
    task = Task(chat=chat,
                name=msg,
                status='TODO',
                dependencies='',
                parents='',
                priority='')
    db.session.add(task)
    db.session.commit()
    send_message("New task *TODO* [[{}]] {}".format(task.id, task.name), chat)
예제 #41
0
def clear_skipped(pid):
    project = Project.get(Project.id == pid)
    user = get_user()
    if user:
        features = Feature.select().where(Feature.project == project)
        query = Task.delete().where(
            Task.user == user, Task.skipped == True,
            Task.feature.in_(features))
        query.execute()
    return redirect(url_for('project', name=project.name))
예제 #42
0
    def testAddKeywords(self):
        tui.addInputAnswers("y")
        self.cmd.do_t_add("x t1")
        task = Task.get(1)

        tui.addInputAnswers("y", "y")
        self.cmd.do_t_add_keywords("1 @kw1 @kw2=12")

        kwDict = task.getKeywordDict()
        self.assertEqual(kwDict, dict(kw1=None, kw2=12))
예제 #43
0
    def testAdd(self):
        tui.addInputAnswers("y", "2", "4", "123")
        self.cmd.do_bug_add("x t1")

        tui.addInputAnswers("n")
        self.cmd.do_bug_add("notExistingProject newBug")

        tasks = list(Task.select())
        result = [x.title for x in tasks]
        expected = [u"t1"]
        self.assertEqual(result, expected)

        kwDict = Task.get(1).getKeywordDict()
        self.assertEqual(kwDict, dict(_severity=2, _likelihood=4, _bug=123))

        for bad_input in ("", # No project
                          "x", # No task name
                          "x t1"): # Existing task
            self.assertRaises(YokadiException, self.cmd.do_bug_add, bad_input)
예제 #44
0
파일: yokadid.py 프로젝트: ryanakca/yokadi
def eventLoop():
    """Main event loop"""
    delta=timedelta(hours=float(Config.byName("ALARM_DELAY").value))
    suspend=timedelta(hours=float(Config.byName("ALARM_SUSPEND").value))
    cmdDelayTemplate=Config.byName("ALARM_DELAY_CMD").value
    cmdDueTemplate=Config.byName("ALARM_DUE_CMD").value
    # For the two following dict, task id is key, and value is (duedate, triggerdate)
    triggeredDelayTasks={}
    triggeredDueTasks={}
    activeTaskFilter=[Task.q.status!="done",
                      Task.q.projectID == Project.q.id,
                      Project.q.active == True]
    while event[0]:
        time.sleep(DELAY)
        now=datetime.today().replace(microsecond=0)
        delayTasks=Task.select(AND(Task.q.dueDate < now+delta,
                                   Task.q.dueDate > now,
                                   *activeTaskFilter))
        dueTasks=Task.select(AND(Task.q.dueDate < now,
                                 *activeTaskFilter))
        processTasks(delayTasks, triggeredDelayTasks, cmdDelayTemplate, suspend)
        processTasks(dueTasks, triggeredDueTasks, cmdDueTemplate, suspend)
예제 #45
0
    def testAdd(self):
        tui.addInputAnswers("y")
        self.cmd.do_t_add("x t1")

        tui.addInputAnswers("y", "y")
        self.cmd.do_t_add("x @kw1 @kw2=12 t2")

        tui.addInputAnswers("n")
        self.cmd.do_t_add("notExistingProject newTask")

        tasks = list(Task.select())
        result = [x.title for x in tasks]
        expected = [u"t1", u"t2"]
        self.assertEqual(result, expected)

        kwDict = Task.get(2).getKeywordDict()
        self.assertEqual(kwDict, dict(kw1=None, kw2=12))

        for bad_input in ("", # No project
                          "x", # No task name
                          "x t1"): # Existing task
            self.assertRaises(YokadiException, self.cmd.do_t_add, bad_input)
예제 #46
0
파일: taskcmd.py 프로젝트: ryanakca/yokadi
    def do_t_remove(self, line):
        parser = self.parser_t_remove()
        options, args = parser.parse_args(line)
        task=dbutils.getTaskFromId(' '.join(args))
        if not options.force:
            if not tui.confirm("Remove task '%s'" % task.title):
                return
        projectId = task.project.id
        task.destroySelf()
        print "Task '%s' removed" % (task.title)

        # Delete project with no associated tasks
        if Task.select(Task.q.projectID == projectId).count() == 0:
            Project.delete(projectId)
예제 #47
0
파일: dbutils.py 프로젝트: ryanakca/yokadi
def addTask(projectName, title, keywordDict):
    """Adds a task based on title and keywordDict.
    @param projectName: name of project as a string
    @param title: task title as a string
    @param keywordDict: dictionary of keywords (name : value)
    @returns : Task instance on success, None if cancelled."""
    # Create missing keywords
    if not createMissingKeywords(keywordDict.keys()):
        return None

    # Create missing project
    project = getOrCreateProject(projectName)
    if not project:
        return None

    # Create task
    try:
        task = Task(creationDate=datetime.now(), project=project, title=title, description="", status="new")
        task.setKeywordDict(keywordDict)
    except DuplicateEntryError:
        raise YokadiException("A task named %s already exists in this project. Please find another name" % title)

    return task
예제 #48
0
 def do_p_remove(self, line):
     parser = self.parser_p_remove()
     options, args = parser.parse_args(line)
     project = getProjectFromName(' '.join(args))
     if not options.force:
         if not tui.confirm("Remove project '%s' and all its tasks" % project.name):
             return
     taskList = Task.select(Task.q.projectID == project.id)
     taskList = list(taskList)
     print "Removing project tasks:"
     for task in taskList:
         task.delete(task.id)
         print "- task %(id)-3s: %(title)-30s" % dict(id=str(task.id), title=str(task.title))
     project.delete(project.id)
     print "Project removed"
예제 #49
0
    def testAddKeywords(self):
        tui.addInputAnswers("y")
        self.cmd.do_t_add("x t1")
        task = Task.get(1)

        tui.addInputAnswers("y", "y")
        self.cmd.do_t_add_keywords("1 @kw1 @kw2=12")

        kwDict = task.getKeywordDict()
        self.assertEqual(kwDict, dict(kw1=None, kw2=12))

        for bad_input in ("", # No task
                          "1", # No keyword
                          "1 kw1"): # No @ before kw1
            self.assertRaises(YokadiException, self.cmd.do_t_add_keywords, bad_input)
예제 #50
0
파일: yokadid.py 프로젝트: mathstuf/yokadi
def main():
    #TODO: check that yokadid is not already running for this database ? Not very harmful...
    #TODO: change unix process name to "yokadid"

    # Make the event list global to allow communication with main event loop
    global event

    (options, args) = parseOptions()

    if options.kill:
        killYokadid(options.filename)
        sys.exit(0)

    signal(SIGTERM, sigTermHandler)
    signal(SIGHUP, sigHupHandler)


    if not options.foreground:
        doubleFork()

    if not options.filename:
        options.filename = os.path.join(os.path.expandvars("$HOME"), ".yokadi.db")
        print "Using default database (%s)" % options.filename

    connectDatabase(options.filename, createIfNeeded=False)

    # Basic tests :
    if not (Task.tableExists() and Config.tableExists()):
        print "Your database seems broken or not initialised properly. Start yokadi command line tool to do it"
        sys.exit(1)

    # Start ical http handler
    if options.icalserver:
        yokadiIcalServer = YokadiIcalServer(options.tcpPort, options.tcpListen)
        yokadiIcalServer.start()

    # Start the main event Loop
    try:
        while event[1] != "SIGTERM":
            eventLoop()
            event[0] = True
    except KeyboardInterrupt:
        print "\nExiting..."
예제 #51
0
 def testRecurs(self):
     tui.addInputAnswers("y")
     self.cmd.do_t_add("x t1")
     task = Task.get(1)
     self.cmd.do_t_recurs("1 daily 10:00")
     desc = str(task.recurrence)
     self.cmd.do_t_recurs("1 weekly FR 23:00")
     self.cmd.do_t_recurs("1 weekly fr 23:00")
     self.cmd.do_t_recurs("1 weekly Fr 23:00")
     self.cmd.do_t_recurs("1 weekly Friday 23:00")
     self.cmd.do_t_recurs("1 monthly 3 13:00")
     self.cmd.do_t_recurs("1 monthly second friday 13:00")
     self.cmd.do_t_recurs("1 yearly 3/07 11:20")
     self.cmd.do_t_recurs("1 quarterly 14 11:20")
     self.cmd.do_t_recurs("1 quarterly first monday 23:20")
     self.assertNotEqual(desc, str(task.recurrence))
     self.assertEqual(task.status, "new")
     self.cmd.do_t_mark_done("1")
     self.assertEqual(task.status, "new")
예제 #52
0
파일: dbutils.py 프로젝트: ryanakca/yokadi
def getTaskFromId(line, parameterName="id"):
    """Returns a task given its id, or raise a YokadiException if it does not
    exist.
    @param line: taskId string
    @param parameterName: name of the parameter to mention in exception
    @return: Task instance or None if existingTask is False"""
    line = line.strip()
    if len(line) == 0:
        raise YokadiException("Missing <%s> parameter" % parameterName)

    # We do not use line.isdigit() because it returns True if line is '¹'!
    try:
        taskId = int(line)
    except ValueError:
        raise YokadiException("<%s> should be a number" % parameterName)

    try:
        return Task.get(taskId)
    except SQLObjectNotFound:
        raise YokadiException("Task %s does not exist. Use t_list to see all tasks" % taskId)
예제 #53
0
파일: taskcmd.py 프로젝트: mathstuf/yokadi
    def do_t_list(self, line):

        def selectRendererClass():
            if options.format != "auto":
                return gRendererClassDict[options.format]

            defaultRendererClass = TextListRenderer
            if not options.output:
                return defaultRendererClass

            ext = os.path.splitext(options.output)[1]
            if not ext:
                return defaultRendererClass

            return gRendererClassDict.get(ext[1:], defaultRendererClass)

        #BUG: completion based on parameter position is broken when parameter is given
        parser = self.parser_t_list()
        options, args = parser.parse_args(line)
        if len(args) > 0:
            projectName, keywordFilters = parseutils.extractKeywords(u" ".join(args))
        else:
            projectName = ""
            keywordFilters = []

        if self.kFilters:
            # Add keyword filter
            keywordFilters.extend(self.kFilters)

        if not projectName:
            if self.pFilter:
                # If a project filter is defined, use it as none was provided
                projectName = self.pFilter
            else:
                # Take all project if none provided
                projectName = "%"

        if projectName.startswith("!"):
            projectName = projectName[1:]
            projectList = Project.select(NOT(LIKE(Project.q.name, projectName)))
        else:
            projectList = Project.select(LIKE(Project.q.name, projectName))

        if projectList.count() == 0:
            tui.error("Found no project matching '%s'" % projectName)
            return

        # Check keywords exist
        parseutils.warnIfKeywordDoesNotExist(keywordFilters)

        # Filtering and sorting according to parameters
        filters = []

        # Filter on keywords
        for keywordFilter in keywordFilters:
            filters.append(keywordFilter.filter())

        order = -Task.q.urgency, Task.q.creationDate
        limit = None
        if options.done:
            filters.append(Task.q.status == 'done')
            if options.done != "all":
                filters.append(parseutils.createFilterFromRange(options.done))
        elif not options.all:
            filters.append(Task.q.status != 'done')
        if options.topUrgent:
            order = -Task.q.urgency
            limit = 5
        if options.topDue:
            filters.append(Task.q.dueDate != None)
            order = Task.q.dueDate
            limit = 5
        if options.overdue:
            filters.append(Task.q.dueDate < datetime.now())
            order = Task.q.dueDate
        if options.search:
            for word in options.search:
                filters.append(OR(LIKE(Task.q.title, "%" + word + "%"),
                                  LIKE(Task.q.description, "%" + word + "%")))

        # Define output
        if options.output:
            out = open(options.output, "w")
        else:
            out = tui.stdout

        # Instantiate renderer
        rendererClass = selectRendererClass()
        renderer = rendererClass(out)

        # Fill the renderer
        if options.keyword:
            if options.keyword.startswith("@"):
                options.keyword = options.keyword[1:]
            for keyword in Keyword.select(LIKE(Keyword.q.name, options.keyword)):
                if unicode(keyword.name).startswith("_") and not options.keyword.startswith("_"):
                    #BUG: cannot filter on db side because sqlobject does not understand ESCAPE needed whith _
                    continue
                taskList = Task.select(AND(TaskKeyword.q.keywordID == keyword.id,
                                           *filters),
                                       orderBy=order, limit=limit, distinct=True,
                                       join=LEFTJOINOn(Task, TaskKeyword, Task.q.id == TaskKeyword.q.taskID))
                taskList = list(taskList)
                if projectList:
                    taskList = [x for x in taskList if x.project in projectList]
                if len(taskList) == 0:
                    continue

                renderer.addTaskList(unicode(keyword), taskList)
            # Call renderer
            renderer.end()
        else:
            hiddenProjectNames = []
            for project in projectList:
                if not project.active:
                    hiddenProjectNames.append(project.name)
                    continue
                taskList = Task.select(AND(Task.q.projectID == project.id, *filters),
                                       orderBy=order, limit=limit, distinct=True,
                                       join=LEFTJOINOn(Task, TaskKeyword, Task.q.id == TaskKeyword.q.taskID))
                taskList = list(taskList)

                if len(taskList) == 0:
                    continue

                renderer.addTaskList(unicode(project), taskList)
            renderer.end()

            if len(hiddenProjectNames) > 0:
                tui.info("hidden projects: %s" % ", ".join(hiddenProjectNames))
예제 #54
0
        osc = changes_to_osc(changes, changeset_id)
        resp = requests.post('{0}/api/0.6/changeset/{1}/upload'.format(API_ENDPOINT, changeset_id), osc, auth=oauth)
        if resp.status_code == 200:
            task.status = 'done'
            task.error = str(changeset_id)
        else:
            # We don't want to exit before closing the changeset
            task.status = 'error'
            task.error = 'Server rejected the changeset with code {0}: {1}'.format(resp.code, resp.text)
        task.save()
    finally:
        resp = requests.put('{0}/api/0.6/changeset/{1}/close'.format(API_ENDPOINT, changeset_id), auth=oauth)


if __name__ == '__main__':
    if not lock():
        sys.exit(0)

    database.connect()
    database.create_tables([Task], safe=True)
    try:
        task = Task.get(Task.pending)
    except Task.DoesNotExist:
        # Yay, no jobs for us.
        sys.exit(0)

    try:
        process(task)
    except Exception as e:
        update_status_exit_on_error(task, 'system error', str(e))
예제 #55
0
파일: taskcmd.py 프로젝트: ryanakca/yokadi
    def do_t_list(self, line):
        doneRangeList= ["today", "thisweek", "thismonth"]

        def keywordDictIsSubsetOf(taskKeywordDict, wantedKeywordDict):
            # Returns true if taskKeywordDict is a subset of wantedKeywordDict
            # taskKeywordDict is considered a subset of wantedKeywordDict if:
            # 1. All wantedKeywordDict keys are in taskKeywordDict
            # 2. All wantedKeywordDict valued keywords have the same value
            #    in taskKeywordDict
            for wantedKeyword, wantedValue in wantedKeywordDict.items():
                if not wantedKeyword in taskKeywordDict:
                    return False
                if wantedValue and taskKeywordDict[wantedKeyword] != wantedValue:
                    return False
            return True

        def taskHasWantedKeywordDict(task, wantedKeywordDict):
            """
            @param task: task object
            @param wantedKeywordDict: dict of name/value of wanted keyword
            # a task is considered a subset of wantedKeywordDict if:
            # 1. All wantedKeywordDict keys are in task or project keywords
            # 2. All wantedKeywordDict valued keywords have the same value
            #    in task or project keyword"""
            for wantedKeyword, wantedValue in wantedKeywordDict.items():
                taskFilters=[Task.q.id==task.id,
                         TaskKeyword.q.taskID==task.id,
                         TaskKeyword.q.keywordID==Keyword.q.id,
                         LIKE(Keyword.q.name, wantedKeyword)]

                projectFilters=[Project.q.id==task.projectID,
                                ProjectKeyword.q.projectID==Project.q.id,
                                ProjectKeyword.q.keyword==Keyword.q.id,
                                LIKE(Keyword.q.name, wantedKeyword)]

                if wantedValue:
                    taskFilters.append(TaskKeyword.q.value==wantedValue)
                    projectFilters.append(ProjectKeyword.q.value==wantedValue)

                if Task.select(AND(*taskFilters)).count()==0 and Task.select(AND(*projectFilters)).count()==0:
                    return False
            # All critera were met, return ok
            return True

        def createFilterFromRange(_range):
            # Parse the _range string and return an SQLObject filter
            minDate = date.today()
            if _range == "today":
                pass
            elif _range == "thisweek":
                minDate -= timedelta(minDate.weekday())
            elif _range == "thismonth":
                minDate = minDate.replace(day = 1)
            else:
                raise YokadiException("Invalid range value '%s'" % _range)

            return Task.q.doneDate>=minDate

        def selectRendererClass():
            if options.format != "auto":
                return gRendererClassDict[options.format]

            defaultRendererClass = TextListRenderer
            if not options.output:
                return defaultRendererClass

            ext = os.path.splitext(options.output)[1]
            if not ext:
                return defaultRendererClass

            return gRendererClassDict.get(ext[1:], defaultRendererClass)

        #BUG: completion based on parameter position is broken when parameter is given
        parser = self.parser_t_list()
        options, args = parser.parse_args(line)
        if len(args) > 0:
            projectName, keywordDict = parseutils.extractKeywords(u" ".join(args))
        else:
            projectName = ""
            keywordDict = {}

        if not projectName:
            # Take all project if none provided
            projectName="%"

        projectList = Project.select(LIKE(Project.q.name, projectName))

        if projectList.count()==0:
            tui.error("Found no project matching '%s'" % projectName)
            return

        # Check keywords exist
        for keyword in keywordDict.keys():
            if Keyword.select(LIKE(Keyword.q.name, keyword)).count()==0:
                tui.error("Keyword %s is unknown." % keyword)

        # Filtering and sorting according to parameters
        filters=[]
        order=-Task.q.urgency, Task.q.creationDate
        limit=None
        if options.done:
            filters.append(Task.q.status=='done')
            if options.done != "all":
                filters.append(createFilterFromRange(options.done))
        elif not options.all:
            filters.append(Task.q.status!='done')
        if options.topUrgent:
            order=-Task.q.urgency
            limit=5
        if options.topDue:
            filters.append(Task.q.dueDate!=None)
            order=Task.q.dueDate
            limit=5
        if options.search:
            for word in options.search:
                filters.append(OR(LIKE(Task.q.title, "%"+word+"%"),
                                  LIKE(Task.q.description, "%"+word+"%")))

        # Define output
        if options.output:
            out = open(options.output, "w")
        else:
            out = tui.stdout

        # Instantiate renderer
        rendererClass = selectRendererClass()
        renderer = rendererClass(out)

        # Fill the renderer
        if options.keyword:
            if options.keyword.startswith("@"):
                options.keyword = options.keyword[1:]
            for keyword in Keyword.select(LIKE(Keyword.q.name, options.keyword)):
                if unicode(keyword.name).startswith("_") and not options.keyword.startswith("_"):
                    #BUG: cannot filter on db side because sqlobject does not understand ESCAPE needed whith _
                    continue
                taskList = Task.select(AND(TaskKeyword.q.taskID == Task.q.id,
                                           TaskKeyword.q.keywordID == keyword.id,
                                           *filters),
                                        orderBy=order, limit=limit)
                taskList = list(taskList)
                if keywordDict:
                    # FIXME: factorize (see project oriented rendering below)
                    taskList = [x for x in taskList if taskHasWantedKeywordDict(x, keywordDict)]
                if projectList:
                    taskList = [x for x in taskList if x.project in projectList]
                if len(taskList) == 0:
                    continue

                renderer.addTaskList(unicode(keyword), taskList)
            # Call renderer
            renderer.end()
        else:
            hiddenProjectNames = []
            for project in projectList:
                if not project.active:
                    hiddenProjectNames.append(project.name)
                    continue
                taskList = Task.select(AND(Task.q.projectID == project.id, *filters),
                                       orderBy=order, limit=limit)

                if keywordDict:
                    taskList = [x for x in taskList if taskHasWantedKeywordDict(x, keywordDict)]
                else:
                    taskList = list(taskList)
    
                if len(taskList) == 0:
                    continue

                renderer.addTaskList(unicode(project), taskList)
            renderer.end()
    
            if len(hiddenProjectNames) > 0:
                tui.info("hidden projects: %s" % ", ".join(hiddenProjectNames))