Skip to content

Commit

Permalink
Add activities list command
Browse files Browse the repository at this point in the history
  • Loading branch information
b12f committed Jun 29, 2023
1 parent 25a6c54 commit de7af3b
Show file tree
Hide file tree
Showing 15 changed files with 364 additions and 14 deletions.
46 changes: 46 additions & 0 deletions cmd/list/activities.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
package list

import (
"fmt"
"strconv"

"github.com/spf13/cobra"

"github.com/opf/openproject-cli/components/printer"
"github.com/opf/openproject-cli/components/resources/users"
"github.com/opf/openproject-cli/components/resources/work_packages"
)

var activitiesCmd = &cobra.Command{
Use: "activities [wpId]",
Aliases: []string{"ac"},
Short: "Lists activities for work package",
Long: `Get a list of activities for a work package.`,
Run: listActivities,
}

func listActivities(_ *cobra.Command, args []string) {
if len(args) != 1 {
printer.ErrorText(fmt.Sprintf("Expected 1 argument [wpId], but got %d", len(args)))
}

wpId, err := strconv.ParseUint(args[0], 10, 64)
if err != nil {
printer.ErrorText(err.Error())
}
activities, err := work_packages.Activities(wpId)
if err != nil {
printer.ErrorText(err.Error())
}

userIds := []uint64{}
for _, a := range activities {
if a.UserId > 0 {
userIds = append(userIds, a.UserId)
continue
}
}

users := users.ByIds(userIds)
printer.Activities(activities, users)
}
1 change: 1 addition & 0 deletions cmd/list/list.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,5 +44,6 @@ func init() {
projectsCmd,
notificationsCmd,
workPackagesCmd,
activitiesCmd,
)
}
59 changes: 59 additions & 0 deletions components/printer/activities.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
package printer

import (
"sort"
"strings"

"github.com/opf/openproject-cli/models"
)

func Activities(activities []*models.Activity, users []*models.User) {
for _, activity := range activities {
user := &models.User{
Id: 0,
Name: "",
FirstName: "",
LastName: "",
}
if activity.UserId > 0 {
userIndex := sort.Search(len(users)-1, func(i int) bool { return users[i].Id == activity.UserId })
user = users[userIndex]
}
printActivityHeadline(activity, user)
printActivityBody(activity)
println("")
}
}

func printActivityHeadline(activity *models.Activity, user *models.User) {
var parts []string

if len(user.Name) > 0 {
parts = append(parts, Green(user.Name))
}

parts = append(parts, Yellow(activity.UpdatedAt))

activePrinter.Println(strings.Join(parts, " "))
}

func printActivityBody(activity *models.Activity) {
var parts []string

if len(activity.Comment) > 0 {
parts = append(parts, Yellow(activity.Comment))

if len(activity.Details) > 0 {
parts = append(parts, "---")
}
}

var detailsParts []string
for _, detail := range activity.Details {
detailsParts = append(detailsParts, *detail)
}

parts = append(parts, strings.Join(detailsParts, "\n"))

activePrinter.Println(strings.Join(parts, "\n \n"))
}
1 change: 1 addition & 0 deletions components/resources/activities/functions.go
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
package main
28 changes: 28 additions & 0 deletions components/resources/users/filters.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package users

import (
"strconv"

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

func IdFilter(ids []uint64) requests.Filter {
idsStr := make([]string, len(ids))
for idx, id := range ids {
idsStr[idx] = strconv.FormatUint(id, 10)
}

return requests.Filter{
Operator: "=",
Name: "id",
Values: idsStr,
}
}

func NameFilter(name string) requests.Filter {
return requests.Filter{
Operator: "~",
Name: "name",
Values: []string{name},
}
}
32 changes: 32 additions & 0 deletions components/resources/users/functions.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package users

import (
"github.com/opf/openproject-cli/components/parser"
"github.com/opf/openproject-cli/components/printer"
"github.com/opf/openproject-cli/components/requests"
"github.com/opf/openproject-cli/dtos"
"github.com/opf/openproject-cli/models"
)

const apiPath = "api/v3"
const usersPath = apiPath + "/principals"

func ByIds(ids []uint64) []*models.User {
if len(ids) == 0 {
return []*models.User{}
}
var filters []requests.Filter
filters = append(filters, IdFilter(ids))

query := requests.NewQuery(filters)

requestUrl := usersPath

status, response := requests.Get(requestUrl, &query)
if !requests.IsSuccess(status) {
printer.ResponseError(status, response)
}

userCollection := parser.Parse[dtos.UserCollectionDto](response)
return userCollection.Convert()
}
22 changes: 22 additions & 0 deletions components/resources/work_packages/activities.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package work_packages

import (
"path/filepath"
"strconv"

"github.com/opf/openproject-cli/components/parser"
"github.com/opf/openproject-cli/components/printer"
"github.com/opf/openproject-cli/components/requests"
"github.com/opf/openproject-cli/dtos"
"github.com/opf/openproject-cli/models"
)

func Activities(id uint64) (activites []*models.Activity, err error) {
status, response := requests.Get(filepath.Join(workPackagesPath, strconv.FormatUint(id, 10), "activities"), nil)
if !requests.IsSuccess(status) {
printer.ResponseError(status, response)
}

activitiesDto := parser.Parse[dtos.ActivityCollectionDto](response)
return activitiesDto.Convert()
}
83 changes: 83 additions & 0 deletions dtos/activity.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
package dtos

import (
"strconv"
"strings"

"github.com/opf/openproject-cli/models"
)

type ActivityDto struct {
Id uint64 `json:"id,omitempty"`
Comment *LongTextDto `json:"comment,omitempty"`
Details []*LongTextDto `json:"details,omitempty"`
Version uint64 `json:"version,omitempty"`
CreatedAt string `json:"createdAt,omitempty"`
UpdatedAt string `json:"updatedAt,omitempty"`
Links *activityLinksDto `json:"_links,omitempty"`
}

type activityElements struct {
Elements []*ActivityDto `json:"elements"`
}

type ActivityCollectionDto struct {
Embedded activityElements `json:"_embedded"`
Type string `json:"_type"`
Total uint64 `json:"total"`
Count uint64 `json:"count"`
}

type activityLinksDto struct {
User *activityUserLinkDto `json:"user"`
}

type activityUserLinkDto struct {
Href string `json:"href"`
}

/////////////// MODEL CONVERSION ///////////////

func (dto *ActivityDto) Convert() (activity *models.Activity, err error) {
var userId uint64
if len(dto.Links.User.Href) > 0 {
userHrefParts := strings.Split(dto.Links.User.Href, "/")
userIdStr := userHrefParts[len(userHrefParts)-1]
userId, err = strconv.ParseUint(userIdStr, 10, 64)
if err != nil {
return nil, err
}
}

return &models.Activity{
Id: dto.Id,
Comment: dto.Comment.Raw,
Details: mapDetailsDto(dto.Details),
Version: dto.Version,
CreatedAt: dto.CreatedAt,
UpdatedAt: dto.UpdatedAt,
UserId: userId,
}, nil
}

func (dto *ActivityCollectionDto) Convert() (act []*models.Activity, err error) {
var activities = make([]*models.Activity, len(dto.Embedded.Elements))

for idx, p := range dto.Embedded.Elements {
activities[idx], err = p.Convert()
if err != nil {
return nil, err
}
}

return activities, nil
}

func mapDetailsDto(detailsDto []*LongTextDto) []*string {
var details = make([]*string, len(detailsDto))
for idx, d := range detailsDto {
details[idx] = &d.Convert().Raw
}

return details
}
18 changes: 18 additions & 0 deletions dtos/long_text.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package dtos

import "github.com/opf/openproject-cli/models"

type LongTextDto struct {
Format string `json:"format"`
Raw string `json:"raw"`
Html string `json:"html"`
}

// ///////////// MODEL CONVERSION ///////////////
func (dto *LongTextDto) Convert() *models.LongText {
return &models.LongText{
Format: dto.Format,
Raw: dto.Raw,
Html: dto.Html,
}
}
42 changes: 42 additions & 0 deletions dtos/user.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
package dtos

import "github.com/opf/openproject-cli/models"

type UserDto struct {
Id uint64 `json:"id,omitempty"`
Name string `json:"name,omitempty"`
FirstName string `json:"firstName,omitempty"`
LastName string `json:"lastName,omitempty"`
}

type userElements struct {
Elements []*UserDto `json:"elements"`
}

type UserCollectionDto struct {
Embedded userElements `json:"_embedded"`
Type string `json:"_type"`
Total uint64 `json:"total"`
Count uint64 `json:"count"`
}

/////////////// MODEL CONVERSION ///////////////

func (dto *UserDto) Convert() *models.User {
return &models.User{
Id: dto.Id,
Name: dto.Name,
FirstName: dto.FirstName,
LastName: dto.LastName,
}
}

func (dto *UserCollectionDto) Convert() []*models.User {
var users = make([]*models.User, len(dto.Embedded.Elements))

for idx, p := range dto.Embedded.Elements {
users[idx] = p.Convert()
}

return users
}
16 changes: 6 additions & 10 deletions dtos/work_package.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,17 +15,13 @@ type WorkPackageLinksDto struct {
PrepareAttachment *LinkDto `json:"prepareAttachment,omitempty"`
}

type workPackageDescription struct {
Raw string `json:"raw"`
}

type WorkPackageDto struct {
Id int64 `json:"id,omitempty"`
Subject string `json:"subject,omitempty"`
Links *WorkPackageLinksDto `json:"_links,omitempty"`
Description *workPackageDescription `json:"description,omitempty"`
Embedded *embeddedDto `json:"_embedded,omitempty"`
LockVersion int `json:"lockVersion"`
Id int64 `json:"id,omitempty"`
Subject string `json:"subject,omitempty"`
Links *WorkPackageLinksDto `json:"_links,omitempty"`
Description *LongTextDto `json:"description,omitempty"`
Embedded *embeddedDto `json:"_embedded,omitempty"`
LockVersion int `json:"lockVersion,omitempty"`
}

type embeddedDto struct {
Expand Down
4 changes: 0 additions & 4 deletions go.sum
Original file line number Diff line number Diff line change
@@ -1,14 +1,10 @@
github.com/cpuguy83/go-md2man/v2 v2.0.2 h1:p1EgwI/C7NhT0JmVkwCD2ZBK8j4aeHQX2pMHHBfMQ6w=
github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk=
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/spf13/cobra v1.7.0 h1:hyqWnYt1ZQShIddO5kBpj3vu05/++x6tJ6dg8EC572I=
github.com/spf13/cobra v1.7.0/go.mod h1:uLxZILRyS/50WlhOIKD7W6V5bgeIt+4sICxh6uRMrb0=
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
11 changes: 11 additions & 0 deletions models/activity.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package models

type Activity struct {
Id uint64
Comment string
Details []*string
Version uint64
CreatedAt string
UpdatedAt string
UserId uint64
}
Loading

0 comments on commit de7af3b

Please sign in to comment.