Esempio n. 1
0
    def _parseListLine(self, parser, line):
        """
        Parse line with parser, returns a tuple of the form
        (options, projectList, filters)
        """
        args = parser.parse_args(line)
        if len(args.filter) > 0:
            projectName, keywordFilters = parseutils.extractKeywords(u" ".join(
                args.filter))
        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 = self._realProjectName(projectName[1:])
            projectList = Project.select(NOT(LIKE(Project.q.name,
                                                  projectName)))
        else:
            projectName = self._realProjectName(projectName)
            projectList = Project.select(LIKE(Project.q.name, projectName))

        if projectList.count() == 0:
            raise YokadiException("Found no project matching '%s'" %
                                  projectName)

        # Check keywords exist
        parseutils.warnIfKeywordDoesNotExist(keywordFilters)

        # Filtering and sorting according to parameters
        filters = []

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

        # Search
        if args.search:
            for word in args.search:
                if word.startswith("@"):
                    tui.warning(
                        "Maybe you want keyword search (without -s option) "
                        "instead of plain text search?")
                filters.append(
                    OR(LIKE(Task.q.title, "%" + word + "%"),
                       LIKE(Task.q.description, "%" + word + "%")))

        return args, projectList, filters
Esempio n. 2
0
    def testProjectCompleter(self):
        self.session.add_all([Project(name="foo"),
                             Project(name="foo2"),
                             Project(name="bar")])

        expected = ["foo ", "foo2 "]
        completer = completers.ProjectCompleter(1)
        result = completer("f", "t_add f", 6, 8)
        self.assertEqual(result, expected)
Esempio n. 3
0
    def testProjectCompleter(self):
        Project(name=u"foo")
        Project(name=u"foo2")
        Project(name=u"bar")

        expected = [u"foo ", u"foo2 "]
        completer = completers.ProjectCompleter(1)
        result = completer("f", "t_add f", 6, 8)
        self.assertEqual(result, expected)
Esempio n. 4
0
    def testGetOrCreateProject(self):
        # interactive
        tui.addInputAnswers("y")
        dbutils.getOrCreateProject("p1")
        self._assertOneObject(Project.selectBy(name="p1"))

        # !interactive
        dbutils.getOrCreateProject("p2", interactive=False)
        self._assertOneObject(Project.selectBy(name="p2"))
Esempio n. 5
0
    def testGetOrCreateProject(self):
        # interactive
        tui.addInputAnswers("y")
        dbutils.getOrCreateProject("p1")
        self._assertOneObject(Project.selectBy(name="p1"))

        # !interactive
        dbutils.getOrCreateProject("p2", interactive=False)
        self._assertOneObject(Project.selectBy(name="p2"))
Esempio n. 6
0
    def _parseListLine(self, parser, line):
        """
        Parse line with parser, returns a tuple of the form
        (options, projectList, filters)
        """
        args = parser.parse_args(line)
        if len(args.filter) > 0:
            projectName, keywordFilters = parseutils.extractKeywords(u" ".join(args.filter))
        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 = self._realProjectName(projectName[1:])
            projectList = Project.select(NOT(LIKE(Project.q.name, projectName)))
        else:
            projectName = self._realProjectName(projectName)
            projectList = Project.select(LIKE(Project.q.name, projectName))

        if projectList.count() == 0:
            raise YokadiException("Found no project matching '%s'" % projectName)

        # Check keywords exist
        parseutils.warnIfKeywordDoesNotExist(keywordFilters)

        # Filtering and sorting according to parameters
        filters = []

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

        # Search
        if args.search:
            for word in args.search:
                if word.startswith("@"):
                    tui.warning("Maybe you want keyword search (without -s option) "
                                "instead of plain text search?")
                filters.append(OR(LIKE(Task.q.title, "%" + word + "%"),
                                  LIKE(Task.q.description, "%" + word + "%")))

        return args, projectList, filters
Esempio n. 7
0
    def testAdd(self):
        tui.addInputAnswers("y")
        self.cmd.do_p_add("p1")

        tui.addInputAnswers("y", "y")
        self.cmd.do_p_add("p2 @kw1 @kw2=12")

        projects = list(Project.select())
        result = [x.name for x in projects]
        expected = [u"p1", u"p2"]
        self.assertEqual(result, expected)

        kwDict = Project.get(2).getKeywordDict()
        self.assertEqual(kwDict, dict(kw1=None, kw2=12))
Esempio n. 8
0
    def do_t_remove(self, line):
        parser = self.parser_t_remove()
        args = parser.parse_args(line)
        task = self.getTaskFromId(args.id)
        if not args.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)
Esempio n. 9
0
    def do_t_remove(self, line):
        parser = self.parser_t_remove()
        args = parser.parse_args(line)
        task = self.getTaskFromId(args.id)
        if not args.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)
Esempio n. 10
0
    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>"""
        try:
            project = Project.byName(line)
        except SQLObjectNotFound:
            raise BadUsageException("You must provide a valid project name")

        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
Esempio n. 11
0
    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>"""
        try:
            project = Project.byName(line)
        except SQLObjectNotFound:
            raise BadUsageException("You must provide a valid project name")

        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
Esempio n. 12
0
    def __init__(self, name, filter_string):
        self.name = name

        project_name, keyword_filters = parseutils.extractKeywords(
            filter_string)

        q_filters = [x.filter() for x in keyword_filters]

        project_list = Project.select(LIKE(Project.q.name, project_name))
        q_filters.append(IN(Task.q.project, project_list))

        # Skip notes
        q_filters.append(
            parseutils.KeywordFilter("!@" + NOTE_KEYWORD).filter())

        # Only list done tasks if they were done after min_date
        min_date = compute_min_date()
        q_filters.append(
            OR(Task.q.status != 'done', Task.q.doneDate >= min_date))

        self.tasks = Task.select(AND(*q_filters),
                                 orderBy=Task.q.id,
                                 distinct=True,
                                 join=LEFTJOINOn(
                                     Task, TaskKeyword,
                                     Task.q.id == TaskKeyword.q.taskID))
Esempio n. 13
0
 def do_p_add(self, line):
     """Add new project. Will prompt to create keywords if they do not exist.
     p_add <projectName> [@<keyword1>] [@<keyword2>]"""
     if not line:
         print "Give at least a project name !"
         return
     projectName, garbage, keywordDict = parseutils.parseLine(line)
     if garbage:
         raise BadUsageException("Cannot parse line, got garbage (%s)" % garbage)
     try:
         project = Project(name=projectName)
     except DuplicateEntryError:
         raise YokadiException("A project named %s already exists. Please find another name" % projectName)
     print "Added project '%s'" % projectName
     if not dbutils.createMissingKeywords(keywordDict.keys()):
         return None
     project.setKeywordDict(keywordDict)
Esempio n. 14
0
 def do_p_list(self, line):
     """List all projects."""
     for project in Project.select():
         if project.active:
             active = ""
         else:
             active = "(inactive)"
         print "%s %s %s %s" % (project.name.ljust(20), project.getKeywordsAsString().ljust(20), str(Task.select(Task.q.project == project).count()).rjust(4), active)
Esempio n. 15
0
    def testEdit(self):
        # Create project p1 and rename it to p2
        self.cmd.do_p_add("p1")
        project = Project.get(1)
        self.assertEqual(project.name, "p1")

        tui.addInputAnswers("p2")
        self.cmd.do_p_edit("p1")
        self.assertEqual(project.name, "p2")

        # Create project p3 and try to rename it to p2
        self.cmd.do_p_add("p3")
        project = Project.get(2)
        self.assertEqual(project.name, "p3")

        tui.addInputAnswers("p2")
        self.assertRaises(YokadiException, self.cmd.do_p_edit, "p3")
        self.assertEqual(project.name, "p3")
Esempio n. 16
0
 def do_p_add(self, line):
     """Add new project. Will prompt to create keywords if they do not exist.
     p_add <projectName> [@<keyword1>] [@<keyword2>]"""
     if not line:
         print "Give at least a project name !"
         return
     projectName, garbage, keywordDict = parseutils.parseLine(line)
     if garbage:
         raise BadUsageException("Cannot parse line, got garbage (%s)" %
                                 garbage)
     try:
         project = Project(name=projectName)
     except DuplicateEntryError:
         raise YokadiException(
             "A project named %s already exists. Please find another name" %
             projectName)
     print "Added project '%s'" % projectName
     if not dbutils.createMissingKeywords(keywordDict.keys()):
         return None
     project.setKeywordDict(keywordDict)
Esempio n. 17
0
 def do_p_list(self, line):
     """List all projects."""
     for project in Project.select():
         if project.active:
             active = ""
         else:
             active = "(inactive)"
         print "%s %s %s %s" % (
             project.name.ljust(20),
             project.getKeywordsAsString().ljust(20),
             str(Task.select(Task.q.project == project).count()).rjust(4),
             active)
Esempio n. 18
0
def getProjectFromName(name, parameterName="project_name"):
    """
    Helper function which returns a project given its name, or raise a
    YokadiException if it does not exist.
    """
    name = name.strip()
    if len(name) == 0:
        raise BadUsageException("Missing <%s> parameter" % parameterName)

    try:
        return Project.byName(name)
    except SQLObjectNotFound:
        raise YokadiException("Project '%s' not found. Use p_list to see all projects." % name)
Esempio n. 19
0
def getOrCreateProject(projectName, interactive=True, createIfNeeded=True):
    """Get a project by its name. Create it if needed
    @param projectName: project name as a string
    @param interactive: Ask user before creating project (this is the default)
    @type interactive: Bool
    @param createIfNeeded: create project if it does not exist (this is the default)
    @type createIfNeeded: Bool
    @return: Project instance or None if user cancel creation or createIfNeeded is False"""
    result = Project.selectBy(name=projectName)
    result = list(result)
    if len(result):
        return result[0]

    if not createIfNeeded:
        return None

    if interactive and not tui.confirm("Project '%s' does not exist, create it" % projectName):
        return None

    project = Project(name=projectName)
    print "Added project '%s'" % projectName
    return project
Esempio n. 20
0
 def do_p_add(self, line):
     """Add new project. Will prompt to create keywords if they do not exist.
     p_add <projectName> [@<keyword1>] [@<keyword2>]"""
     if not line:
         print("Give at least a project name !")
         return
     projectName, garbage, keywordDict = parseutils.parseLine(line)
     session = db.getSession()
     if garbage:
         raise BadUsageException("Cannot parse line, got garbage (%s)" % garbage)
     try:
         project = Project(name=projectName)
         session.add(project)
         session.commit()
     except IntegrityError:
         session.rollback()
         raise YokadiException("A project named %s already exists. Please find another name" % projectName)
     print("Added project '%s'" % projectName)
     if not dbutils.createMissingKeywords(list(keywordDict.keys())):
         return None
     project.setKeywordDict(keywordDict)
     session.merge(project)
     session.commit()
Esempio n. 21
0
def getProjectFromName(name, parameterName="project_name"):
    """
    Helper function which returns a project given its name, or raise a
    YokadiException if it does not exist.
    """
    name = name.strip()
    if len(name) == 0:
        raise BadUsageException("Missing <%s> parameter" % parameterName)

    try:
        return Project.byName(name)
    except SQLObjectNotFound:
        raise YokadiException(
            "Project '%s' not found. Use p_list to see all projects." % name)
Esempio n. 22
0
 def testTlistUrgency0(self):
     # Given a project with two tasks, one with a negative urgency
     prj = Project(name="prj")
     self.session.add(prj)
     t1 = Task(project=prj, title="t1")
     self.session.add(t1)
     t2 = Task(project=prj, title="t2", urgency=-1)
     self.session.add(t2)
     self.session.flush()
     # When I list tasks with -u 0
     renderer = testutils.TestRenderer()
     self.cmd.do_t_list("-u 0", renderer=renderer)
     # Then the task with a negative urgency is not listed
     self.assertEqual(renderer.tasks, [t1])
Esempio n. 23
0
    def testRenderListSectionOrder(self):
        projectNames = "ccc", "aaa", "UPPER_CASE", "zzz", "mmm"
        projectList = []
        for name in projectNames:
            prj = Project(name=name)
            task = Task(project=prj, title="Hello")
            self.session.add(prj)
            self.session.add(task)
            projectList.append(prj)
        self.session.flush()

        renderer = testutils.TestRenderer()
        self.cmd._renderList(renderer, projectList, filters=[], order=[])

        self.assertEqual(list(renderer.taskDict.keys()), sorted(projectNames, key=lambda x: x.lower()))
Esempio n. 24
0
 def do_p_add(self, line):
     """Add new project.
     p_add <projectName>"""
     if not line:
         print("Missing project name.")
         return
     projectName = parseutils.parseOneWordName(line)
     session = db.getSession()
     try:
         project = Project(name=projectName)
         session.add(project)
         session.commit()
     except IntegrityError:
         session.rollback()
         raise YokadiException("A project named %s already exists. Please find another name" % projectName)
     print("Added project '%s'" % projectName)
Esempio n. 25
0
    def testRenderListSectionOrderKeywords(self):
        prj = Project(name="prj")
        keywordNames = ["kw_" + x for x in ("ccc", "aaa", "UPPER_CASE", "zzz", "mmm")]
        keywordList = []
        for name in keywordNames:
            keyword = Keyword(name=name)
            task = Task(project=prj, title="Hello")
            TaskKeyword(task=task, keyword=keyword)
            self.session.add(task)
            keywordList.append(prj)
        self.session.flush()

        renderer = testutils.TestRenderer()
        self.cmd._renderList(renderer, [prj], filters=[], order=[], groupKeyword="kw_%")

        self.assertEqual(list(renderer.taskDict.keys()), sorted(keywordNames, key=lambda x: x.lower()))
Esempio n. 26
0
def generateCal():
    """Generate an ical calendar from yokadi database
    @return: icalendar.Calendar object"""
    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):
        vTodo = icalendar.Todo()
        vTodo.add("summary", project.name)
        vTodo["uid"] = PROJECT_UID % project.id
        cal.add_component(vTodo)
    # Add tasks
    for task in Task.select(Task.q.status != "done"):
        vTodo = createVTodoFromTask(task)
        cal.add_component(vTodo)

    return cal
Esempio n. 27
0
def generateCal():
    """Generate an ical calendar from yokadi database
    @return: icalendar.Calendar object"""
    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):
        vTodo = icalendar.Todo()
        vTodo.add("summary", project.name)
        vTodo["uid"] = PROJECT_UID % project.id
        cal.add_component(vTodo)
    # Add tasks
    for task in Task.select(Task.q.status != "done"):
        vTodo = createVTodoFromTask(task)
        cal.add_component(vTodo)

    return cal
Esempio n. 28
0
def getOrCreateProject(projectName, interactive=True, createIfNeeded=True):
    """Get a project by its name. Create it if needed
    @param projectName: project name as a string
    @param interactive: Ask user before creating project (this is the default)
    @type interactive: Bool
    @param createIfNeeded: create project if it does not exist (this is the default)
    @type createIfNeeded: Bool
    @return: Project instance or None if user cancel creation or createIfNeeded is False"""
    session = db.getSession()
    result = session.query(Project).filter_by(name=projectName).all()
    if len(result):
        return result[0]

    if not createIfNeeded:
        return None

    if interactive and not tui.confirm(
            "Project '%s' does not exist, create it" % projectName):
        return None

    project = Project(name=projectName)
    session.add(project)
    print("Added project '%s'" % projectName)
    return project
Esempio n. 29
0
 def testMergeItselfFails(self):
     project = Project(name="p1")
     self.assertRaises(YokadiException, project.merge, self.session,
                       project)