Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,18 @@ Open a new shell and completion should work by using the `TAB` key as usual.
The OpenProject CLI commands are structured in a common, human-readable pattern. Every command is built
as `op VERB RESOURCE [additional information]`. You will see plenty of examples within this section.

### Login

You are able to login interactively to your openproject instance by running:
```shell
op login
```

The login command takes the optional flags `--host` and `--api-key` in order to login non-interactively:
```shell
op login --host https://openproject.org --api-key aaaaabbbbbccccdddddeeeeefffffggggghhhhhiiiiijjjjjkkkkklllllmmmmm
```

### Discoverability

Discoverability is key. As we won't document every single command within this README, it is important for the CLI tool,
Expand Down
110 changes: 85 additions & 25 deletions cmd/login.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,16 @@ var loginCmd = &cobra.Command{
Long: `Enables the login flow, which enables the user to use
this tool for a specific OpenProject instance. The login
needs the host URL of the OpenProject instance and a
generated API token.`,
generated API token. You can provide both with flags to
skip interactive input.`,
Run: login,
}

var (
loginHostFlag string
loginAPIKeyFlag string
)

const (
urlInputError = "There was a problem parsing the input. Please try again and put in a valid URL."
missingSchemeError = "URL scheme is missing, please define a complete URL."
Expand All @@ -41,51 +47,84 @@ func login(_ *cobra.Command, _ []string) {
var hostUrl *url.URL
var token string

for {
printer.Debug(Verbose, "Parsing host URL ...")
printer.Input("OpenProject host URL: ")

ok, msg, host := parseHostUrl()
if loginHostFlag != "" {
printer.Debug(Verbose, "Parsing host URL from --host ...")
ok, msg, host := parseHostUrlInput(loginHostFlag)
if !ok {
printer.ErrorText(msg)
continue
return
}

printer.Debug(Verbose, "Initializing requests client ...")
requests.Init(host, "", Verbose)
ok = checkOpenProjectApi()
if !ok {
if !checkOpenProjectApi() {
printer.ErrorText(noOpInstanceError)
continue
return
}

hostUrl = host
break
}

for {
fmt.Printf("OpenProject API Token (Visit %s/my/access_tokens to generate one): ", hostUrl)
ok, t := requestApiToken()
if !ok {
fmt.Println(tokenInputError)
continue
} else {
for {
printer.Debug(Verbose, "Parsing host URL ...")
printer.Input("OpenProject host URL: ")

ok, msg, host := parseHostUrl()
if !ok {
printer.ErrorText(msg)
continue
}

printer.Debug(Verbose, "Initializing requests client ...")
requests.Init(host, "", Verbose)
ok = checkOpenProjectApi()
if !ok {
printer.ErrorText(noOpInstanceError)
continue
}

hostUrl = host
break
}
}

token = common.SanitizeLineBreaks(t)

if loginAPIKeyFlag != "" {
token = common.SanitizeLineBreaks(loginAPIKeyFlag)
requests.Init(hostUrl, token, Verbose)
user, err := users.Me()
if err != nil {
printer.Error(err)
continue
return
}

if user.Name == "Anonymous" {
printer.ErrorText("no authenticate given")
continue
return
}
} else {
for {
fmt.Printf("OpenProject API Token (Visit %s/my/access_tokens to generate one): ", hostUrl)
ok, t := requestApiToken()
if !ok {
fmt.Println(tokenInputError)
continue
}

token = common.SanitizeLineBreaks(t)

requests.Init(hostUrl, token, Verbose)
user, err := users.Me()
if err != nil {
printer.Error(err)
continue
}

if user.Name == "Anonymous" {
printer.ErrorText("no authenticate given")
continue
}

break
}

break
}

storeLoginData(hostUrl, token)
Expand All @@ -100,6 +139,11 @@ func parseHostUrl() (ok bool, errMessage string, host *url.URL) {
return false, urlInputError, nil
}

return parseHostUrlInput(input)
}

func parseHostUrlInput(input string) (ok bool, errMessage string, host *url.URL) {

printer.Debug(Verbose, fmt.Sprintf("Parsed input %q.", input))
printer.Debug(Verbose, "Sanitizing input ...")

Expand All @@ -126,6 +170,22 @@ func parseHostUrl() (ok bool, errMessage string, host *url.URL) {
return true, "", parsed
}

func init() {
loginCmd.Flags().StringVar(
&loginHostFlag,
"host",
"",
"OpenProject host URL",
)

loginCmd.Flags().StringVar(
&loginAPIKeyFlag,
"api-key",
"",
"OpenProject API token",
)
}

func checkOpenProjectApi() bool {
printer.Debug(Verbose, "Fetching API root to check for instance configuration ...")

Expand Down