Skip to content

Commit

Permalink
Rework user flag to use new-style filters
Browse files Browse the repository at this point in the history
Also
- validates user input (according to core app `User#login` Regexp).
- supports lists of users (separated by a comma).
  • Loading branch information
myabc committed Feb 18, 2025
1 parent b5ab3d9 commit 7c4725a
Show file tree
Hide file tree
Showing 5 changed files with 101 additions and 44 deletions.
30 changes: 23 additions & 7 deletions cmd/list/time_entries.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,16 @@ package list

import (
"github.com/opf/openproject-cli/components/printer"
"github.com/opf/openproject-cli/components/requests"
"github.com/opf/openproject-cli/components/resources"
"github.com/opf/openproject-cli/components/resources/time_entries"
"github.com/opf/openproject-cli/components/resources/time_entries/filters"
"github.com/spf13/cobra"
)

var user string
var activeTimeEntryFilters = map[string]resources.Filter{
"user": filters.NewUserFilter(),
}

var timeEntriesCmd = &cobra.Command{
Use: "timeentries",
Expand All @@ -16,19 +21,30 @@ var timeEntriesCmd = &cobra.Command{
}

func listTimeEntries(_ *cobra.Command, _ []string) {
if all, err := time_entries.All(timeEntriesFilterOptions()); err == nil {
query, err := buildTimeEntriesQuery()
if err != nil {
printer.ErrorText(err.Error())
return
}

if all, err := time_entries.All(query); err == nil {
printer.TimeEntryList(all)
} else {
printer.Error(err)
}
}

func timeEntriesFilterOptions() *map[time_entries.FilterOption]string {
options := make(map[time_entries.FilterOption]string)
func buildTimeEntriesQuery() (requests.Query, error) {
var q requests.Query

for _, filter := range activeTimeEntryFilters {
err := filter.ValidateInput()
if err != nil {
return requests.NewEmptyQuery(), err
}

if len(user) > 0 {
options[time_entries.User] = user
q = q.Merge(filter.Query())
}

return &options
return q, nil
}
16 changes: 9 additions & 7 deletions cmd/list/time_entries_flags.go
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
package list

func initTimeEntriesFlags() {
timeEntriesCmd.Flags().StringVarP(
&user,
"user",
"u",
"me",
"User the time entry tracks expenditures for (can be name, ID or 'me')",
)
for _, filter := range activeTimeEntryFilters {
timeEntriesCmd.Flags().StringVarP(
filter.ValuePointer(),
filter.Name(),
filter.ShortHand(),
filter.DefaultValue(),
filter.Usage(),
)
}
}
19 changes: 0 additions & 19 deletions components/resources/time_entries/filters.go

This file was deleted.

68 changes: 68 additions & 0 deletions components/resources/time_entries/filters/user.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
package filters

import (
"fmt"
"regexp"
"strings"

"github.com/opf/openproject-cli/components/errors"
"github.com/opf/openproject-cli/components/printer"
"github.com/opf/openproject-cli/components/requests"
)

// validates the value is one or more of the following - separated by commas
// - a valid login (see https://github.com/opf/openproject/blob/dev/app/models/user.rb#L135)
// - a numeric id
// - me
const validValueRegexp = `^([\pL0-9_\-@.+ ]+|[0-9]+|me)(,([\pL0-9_\-@.+ ]+|[0-9]+|me))*$`

type UserFilter struct {
value string
}

func (f *UserFilter) ValuePointer() *string {
return &f.value
}

func (f *UserFilter) Value() string {
return f.value
}

func (f *UserFilter) Name() string {
return "user"
}

func (f *UserFilter) ShortHand() string {
return "u"
}

func (f *UserFilter) Usage() string {
return `User the time entry tracks expenditures for (can be name, ID or 'me')`
}

func (f *UserFilter) ValidateInput() error {
matched, _ := regexp.Match(validValueRegexp, []byte(f.value))
if !matched {
return errors.Custom(fmt.Sprintf("Invalid user value %s.", printer.Yellow(f.value)))
}

return nil
}

func (f *UserFilter) DefaultValue() string {
return "me"
}

func (f *UserFilter) Query() requests.Query {
return requests.NewQuery(nil, []requests.Filter{
{
Operator: "=",
Name: "user",
Values: strings.Split(f.value, ","),
},
})
}

func NewUserFilter() *UserFilter {
return &UserFilter{}
}
12 changes: 1 addition & 11 deletions components/resources/time_entries/functions.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,17 +8,7 @@ import (
"github.com/opf/openproject-cli/models"
)

func All(filterOptions *map[FilterOption]string) ([]*models.TimeEntry, error) {
var filters []requests.Filter

for updateOpt, value := range *filterOptions {
if updateOpt == User {
filters = append(filters, UserFilter(value))
}
}

query := requests.NewPaginatedQuery(-1, filters)

func All(query requests.Query) ([]*models.TimeEntry, error) {
response, err := requests.Get(paths.TimeEntries(), &query)
if err != nil {
return nil, err
Expand Down

0 comments on commit 7c4725a

Please sign in to comment.