Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
N
nexpie-grafana-theme
Overview
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Registry
Registry
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Kornkitt Poolsup
nexpie-grafana-theme
Commits
d1c52383
Unverified
Commit
d1c52383
authored
Nov 20, 2019
by
Sofia Papagiannaki
Committed by
GitHub
Nov 20, 2019
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
API: Optionally list expired keys (#20468)
* API: Optionally list expired keys * Update docs
parent
1b38d945
Show whitespace changes
Inline
Side-by-side
Showing
11 changed files
with
46 additions
and
21 deletions
+46
-21
docs/sources/http_api/auth.md
+4
-0
pkg/api/apikey.go
+1
-1
pkg/models/apikey.go
+1
-1
pkg/services/sqlstore/apikey.go
+1
-1
pkg/services/sqlstore/apikey_test.go
+2
-2
public/app/features/api-keys/ApiKeysPage.test.tsx
+3
-2
public/app/features/api-keys/ApiKeysPage.tsx
+20
-6
public/app/features/api-keys/state/actions.ts
+10
-6
public/app/features/api-keys/state/reducers.ts
+1
-0
public/app/features/api-keys/state/selectors.test.ts
+2
-2
public/app/types/apiKeys.ts
+1
-0
No files found.
docs/sources/http_api/auth.md
View file @
d1c52383
...
@@ -67,6 +67,10 @@ Content-Type: application/json
...
@@ -67,6 +67,10 @@ Content-Type: application/json
Authorization
:
Bearer eyJrIjoiT0tTcG1pUlY2RnVKZTFVaDFsNFZXdE9ZWmNrMkZYbk
Authorization
:
Bearer eyJrIjoiT0tTcG1pUlY2RnVKZTFVaDFsNFZXdE9ZWmNrMkZYbk
```
```
Query Parameters:
-
`includeExpired`
: boolean. enable listing of expired keys. Optional.
**Example Response**
:
**Example Response**
:
```
http
```
http
...
...
pkg/api/apikey.go
View file @
d1c52383
...
@@ -10,7 +10,7 @@ import (
...
@@ -10,7 +10,7 @@ import (
)
)
func
GetAPIKeys
(
c
*
models
.
ReqContext
)
Response
{
func
GetAPIKeys
(
c
*
models
.
ReqContext
)
Response
{
query
:=
models
.
GetApiKeysQuery
{
OrgId
:
c
.
OrgId
}
query
:=
models
.
GetApiKeysQuery
{
OrgId
:
c
.
OrgId
,
IncludeExpired
:
c
.
QueryBool
(
"includeExpired"
)
}
if
err
:=
bus
.
Dispatch
(
&
query
);
err
!=
nil
{
if
err
:=
bus
.
Dispatch
(
&
query
);
err
!=
nil
{
return
Error
(
500
,
"Failed to list api keys"
,
err
)
return
Error
(
500
,
"Failed to list api keys"
,
err
)
...
...
pkg/models/apikey.go
View file @
d1c52383
...
@@ -50,7 +50,7 @@ type DeleteApiKeyCommand struct {
...
@@ -50,7 +50,7 @@ type DeleteApiKeyCommand struct {
type
GetApiKeysQuery
struct
{
type
GetApiKeysQuery
struct
{
OrgId
int64
OrgId
int64
Include
Invali
d
bool
Include
Expire
d
bool
Result
[]
*
ApiKey
Result
[]
*
ApiKey
}
}
...
...
pkg/services/sqlstore/apikey.go
View file @
d1c52383
...
@@ -19,7 +19,7 @@ func init() {
...
@@ -19,7 +19,7 @@ func init() {
func
GetApiKeys
(
query
*
models
.
GetApiKeysQuery
)
error
{
func
GetApiKeys
(
query
*
models
.
GetApiKeysQuery
)
error
{
sess
:=
x
.
Limit
(
100
,
0
)
.
Where
(
"org_id=? and ( expires IS NULL or expires >= ?)"
,
sess
:=
x
.
Limit
(
100
,
0
)
.
Where
(
"org_id=? and ( expires IS NULL or expires >= ?)"
,
query
.
OrgId
,
timeNow
()
.
Unix
())
.
Asc
(
"name"
)
query
.
OrgId
,
timeNow
()
.
Unix
())
.
Asc
(
"name"
)
if
query
.
Include
Invali
d
{
if
query
.
Include
Expire
d
{
sess
=
x
.
Limit
(
100
,
0
)
.
Where
(
"org_id=?"
,
query
.
OrgId
)
.
Asc
(
"name"
)
sess
=
x
.
Limit
(
100
,
0
)
.
Where
(
"org_id=?"
,
query
.
OrgId
)
.
Asc
(
"name"
)
}
}
...
...
pkg/services/sqlstore/apikey_test.go
View file @
d1c52383
...
@@ -91,7 +91,7 @@ func TestApiKeyDataAccess(t *testing.T) {
...
@@ -91,7 +91,7 @@ func TestApiKeyDataAccess(t *testing.T) {
// advance mocked getTime by 1s
// advance mocked getTime by 1s
timeNow
()
timeNow
()
query
:=
models
.
GetApiKeysQuery
{
OrgId
:
1
,
Include
Invali
d
:
false
}
query
:=
models
.
GetApiKeysQuery
{
OrgId
:
1
,
Include
Expire
d
:
false
}
err
=
GetApiKeys
(
&
query
)
err
=
GetApiKeys
(
&
query
)
assert
.
Nil
(
t
,
err
)
assert
.
Nil
(
t
,
err
)
...
@@ -101,7 +101,7 @@ func TestApiKeyDataAccess(t *testing.T) {
...
@@ -101,7 +101,7 @@ func TestApiKeyDataAccess(t *testing.T) {
}
}
}
}
query
=
models
.
GetApiKeysQuery
{
OrgId
:
1
,
Include
Invali
d
:
true
}
query
=
models
.
GetApiKeysQuery
{
OrgId
:
1
,
Include
Expire
d
:
true
}
err
=
GetApiKeys
(
&
query
)
err
=
GetApiKeys
(
&
query
)
assert
.
Nil
(
t
,
err
)
assert
.
Nil
(
t
,
err
)
...
...
public/app/features/api-keys/ApiKeysPage.test.tsx
View file @
d1c52383
...
@@ -23,6 +23,7 @@ const setup = (propOverrides?: object) => {
...
@@ -23,6 +23,7 @@ const setup = (propOverrides?: object) => {
setSearchQuery
:
jest
.
fn
(),
setSearchQuery
:
jest
.
fn
(),
addApiKey
:
jest
.
fn
(),
addApiKey
:
jest
.
fn
(),
apiKeysCount
:
0
,
apiKeysCount
:
0
,
includeExpired
:
false
,
};
};
Object
.
assign
(
props
,
propOverrides
);
Object
.
assign
(
props
,
propOverrides
);
...
@@ -63,7 +64,7 @@ describe('Life cycle', () => {
...
@@ -63,7 +64,7 @@ describe('Life cycle', () => {
instance
.
componentDidMount
();
instance
.
componentDidMount
();
expect
(
instance
.
props
.
loadApiKeys
).
toHaveBeenCalled
(
);
expect
(
instance
.
props
.
loadApiKeys
).
toHaveBeenCalled
With
(
false
);
});
});
});
});
...
@@ -72,7 +73,7 @@ describe('Functions', () => {
...
@@ -72,7 +73,7 @@ describe('Functions', () => {
it
(
'should call delete team'
,
()
=>
{
it
(
'should call delete team'
,
()
=>
{
const
{
instance
}
=
setup
();
const
{
instance
}
=
setup
();
instance
.
onDeleteApiKey
(
getMockKey
());
instance
.
onDeleteApiKey
(
getMockKey
());
expect
(
instance
.
props
.
deleteApiKey
).
toHaveBeenCalledWith
(
1
);
expect
(
instance
.
props
.
deleteApiKey
).
toHaveBeenCalledWith
(
1
,
false
);
});
});
});
});
...
...
public/app/features/api-keys/ApiKeysPage.tsx
View file @
d1c52383
...
@@ -12,7 +12,7 @@ import ApiKeysAddedModal from './ApiKeysAddedModal';
...
@@ -12,7 +12,7 @@ import ApiKeysAddedModal from './ApiKeysAddedModal';
import
config
from
'app/core/config'
;
import
config
from
'app/core/config'
;
import
appEvents
from
'app/core/app_events'
;
import
appEvents
from
'app/core/app_events'
;
import
EmptyListCTA
from
'app/core/components/EmptyListCTA/EmptyListCTA'
;
import
EmptyListCTA
from
'app/core/components/EmptyListCTA/EmptyListCTA'
;
import
{
DeleteButton
,
EventsWithValidation
,
FormLabel
,
Input
,
ValidationEvents
}
from
'@grafana/ui'
;
import
{
DeleteButton
,
EventsWithValidation
,
FormLabel
,
Input
,
Switch
,
ValidationEvents
}
from
'@grafana/ui'
;
import
{
NavModel
,
dateTime
,
isDateTime
}
from
'@grafana/data'
;
import
{
NavModel
,
dateTime
,
isDateTime
}
from
'@grafana/data'
;
import
{
FilterInput
}
from
'app/core/components/FilterInput/FilterInput'
;
import
{
FilterInput
}
from
'app/core/components/FilterInput/FilterInput'
;
import
{
store
}
from
'app/store/store'
;
import
{
store
}
from
'app/store/store'
;
...
@@ -51,6 +51,7 @@ export interface Props {
...
@@ -51,6 +51,7 @@ export interface Props {
setSearchQuery
:
typeof
setSearchQuery
;
setSearchQuery
:
typeof
setSearchQuery
;
addApiKey
:
typeof
addApiKey
;
addApiKey
:
typeof
addApiKey
;
apiKeysCount
:
number
;
apiKeysCount
:
number
;
includeExpired
:
boolean
;
}
}
export
interface
State
{
export
interface
State
{
...
@@ -76,7 +77,7 @@ const tooltipText =
...
@@ -76,7 +77,7 @@ const tooltipText =
export
class
ApiKeysPage
extends
PureComponent
<
Props
,
any
>
{
export
class
ApiKeysPage
extends
PureComponent
<
Props
,
any
>
{
constructor
(
props
:
Props
)
{
constructor
(
props
:
Props
)
{
super
(
props
);
super
(
props
);
this
.
state
=
{
isAdding
:
false
,
newApiKey
:
initialApiKeyState
};
this
.
state
=
{
isAdding
:
false
,
newApiKey
:
initialApiKeyState
,
includeExpired
:
false
};
}
}
componentDidMount
()
{
componentDidMount
()
{
...
@@ -84,17 +85,21 @@ export class ApiKeysPage extends PureComponent<Props, any> {
...
@@ -84,17 +85,21 @@ export class ApiKeysPage extends PureComponent<Props, any> {
}
}
async
fetchApiKeys
()
{
async
fetchApiKeys
()
{
await
this
.
props
.
loadApiKeys
();
await
this
.
props
.
loadApiKeys
(
this
.
state
.
includeExpired
);
}
}
onDeleteApiKey
(
key
:
ApiKey
)
{
onDeleteApiKey
(
key
:
ApiKey
)
{
this
.
props
.
deleteApiKey
(
key
.
id
);
this
.
props
.
deleteApiKey
(
key
.
id
,
this
.
props
.
includeExpired
);
}
}
onSearchQueryChange
=
(
value
:
string
)
=>
{
onSearchQueryChange
=
(
value
:
string
)
=>
{
this
.
props
.
setSearchQuery
(
value
);
this
.
props
.
setSearchQuery
(
value
);
};
};
onIncludeExpiredChange
=
(
value
:
boolean
)
=>
{
this
.
setState
({
hasFetched
:
false
,
includeExpired
:
value
},
this
.
fetchApiKeys
);
};
onToggleAdding
=
()
=>
{
onToggleAdding
=
()
=>
{
this
.
setState
({
isAdding
:
!
this
.
state
.
isAdding
});
this
.
setState
({
isAdding
:
!
this
.
state
.
isAdding
});
};
};
...
@@ -114,7 +119,7 @@ export class ApiKeysPage extends PureComponent<Props, any> {
...
@@ -114,7 +119,7 @@ export class ApiKeysPage extends PureComponent<Props, any> {
// make sure that secondsToLive is number or null
// make sure that secondsToLive is number or null
const
secondsToLive
=
this
.
state
.
newApiKey
[
'secondsToLive'
];
const
secondsToLive
=
this
.
state
.
newApiKey
[
'secondsToLive'
];
this
.
state
.
newApiKey
[
'secondsToLive'
]
=
secondsToLive
?
kbn
.
interval_to_seconds
(
secondsToLive
)
:
null
;
this
.
state
.
newApiKey
[
'secondsToLive'
]
=
secondsToLive
?
kbn
.
interval_to_seconds
(
secondsToLive
)
:
null
;
this
.
props
.
addApiKey
(
this
.
state
.
newApiKey
,
openModal
);
this
.
props
.
addApiKey
(
this
.
state
.
newApiKey
,
openModal
,
this
.
props
.
includeExpired
);
this
.
setState
((
prevState
:
State
)
=>
{
this
.
setState
((
prevState
:
State
)
=>
{
return
{
return
{
...
prevState
,
...
prevState
,
...
@@ -232,7 +237,7 @@ export class ApiKeysPage extends PureComponent<Props, any> {
...
@@ -232,7 +237,7 @@ export class ApiKeysPage extends PureComponent<Props, any> {
renderApiKeyList
()
{
renderApiKeyList
()
{
const
{
isAdding
}
=
this
.
state
;
const
{
isAdding
}
=
this
.
state
;
const
{
apiKeys
,
searchQuery
}
=
this
.
props
;
const
{
apiKeys
,
searchQuery
,
includeExpired
}
=
this
.
props
;
return
(
return
(
<>
<>
...
@@ -256,6 +261,14 @@ export class ApiKeysPage extends PureComponent<Props, any> {
...
@@ -256,6 +261,14 @@ export class ApiKeysPage extends PureComponent<Props, any> {
{
this
.
renderAddApiKeyForm
()
}
{
this
.
renderAddApiKeyForm
()
}
<
h3
className=
"page-heading"
>
Existing Keys
</
h3
>
<
h3
className=
"page-heading"
>
Existing Keys
</
h3
>
<
Switch
label=
"Show expired"
checked=
{
includeExpired
}
onChange=
{
event
=>
{
// @ts-ignore
this
.
onIncludeExpiredChange
(
event
.
target
.
checked
);
}
}
/>
<
table
className=
"filter-table"
>
<
table
className=
"filter-table"
>
<
thead
>
<
thead
>
<
tr
>
<
tr
>
...
@@ -304,6 +317,7 @@ function mapStateToProps(state: any) {
...
@@ -304,6 +317,7 @@ function mapStateToProps(state: any) {
navModel
:
getNavModel
(
state
.
navIndex
,
'apikeys'
),
navModel
:
getNavModel
(
state
.
navIndex
,
'apikeys'
),
apiKeys
:
getApiKeys
(
state
.
apiKeys
),
apiKeys
:
getApiKeys
(
state
.
apiKeys
),
searchQuery
:
state
.
apiKeys
.
searchQuery
,
searchQuery
:
state
.
apiKeys
.
searchQuery
,
includeExpired
:
state
.
includeExpired
,
apiKeysCount
:
getApiKeysCount
(
state
.
apiKeys
),
apiKeysCount
:
getApiKeysCount
(
state
.
apiKeys
),
hasFetched
:
state
.
apiKeys
.
hasFetched
,
hasFetched
:
state
.
apiKeys
.
hasFetched
,
};
};
...
...
public/app/features/api-keys/state/actions.ts
View file @
d1c52383
...
@@ -26,27 +26,31 @@ const apiKeysLoaded = (apiKeys: ApiKey[]): LoadApiKeysAction => ({
...
@@ -26,27 +26,31 @@ const apiKeysLoaded = (apiKeys: ApiKey[]): LoadApiKeysAction => ({
payload
:
apiKeys
,
payload
:
apiKeys
,
});
});
export
function
addApiKey
(
apiKey
:
ApiKey
,
openModal
:
(
key
:
string
)
=>
void
):
ThunkResult
<
void
>
{
export
function
addApiKey
(
apiKey
:
ApiKey
,
openModal
:
(
key
:
string
)
=>
void
,
includeExpired
:
boolean
):
ThunkResult
<
void
>
{
return
async
dispatch
=>
{
return
async
dispatch
=>
{
const
result
=
await
getBackendSrv
().
post
(
'/api/auth/keys'
,
apiKey
);
const
result
=
await
getBackendSrv
().
post
(
'/api/auth/keys'
,
apiKey
);
dispatch
(
setSearchQuery
(
''
));
dispatch
(
setSearchQuery
(
''
));
dispatch
(
loadApiKeys
());
dispatch
(
loadApiKeys
(
includeExpired
));
openModal
(
result
.
key
);
openModal
(
result
.
key
);
};
};
}
}
export
function
loadApiKeys
():
ThunkResult
<
void
>
{
export
function
loadApiKeys
(
includeExpired
:
boolean
):
ThunkResult
<
void
>
{
return
async
dispatch
=>
{
return
async
dispatch
=>
{
const
response
=
await
getBackendSrv
().
get
(
'/api/auth/keys
'
);
const
response
=
await
getBackendSrv
().
get
(
'/api/auth/keys
?includeExpired='
+
includeExpired
);
dispatch
(
apiKeysLoaded
(
response
));
dispatch
(
apiKeysLoaded
(
response
));
};
};
}
}
export
function
deleteApiKey
(
id
:
number
):
ThunkResult
<
void
>
{
export
function
deleteApiKey
(
id
:
number
,
includeExpired
:
boolean
):
ThunkResult
<
void
>
{
return
async
dispatch
=>
{
return
async
dispatch
=>
{
getBackendSrv
()
getBackendSrv
()
.
delete
(
'/api/auth/keys/'
+
id
)
.
delete
(
'/api/auth/keys/'
+
id
)
.
then
(
dispatch
(
loadApiKeys
()));
.
then
(
dispatch
(
loadApiKeys
(
includeExpired
)));
};
};
}
}
...
...
public/app/features/api-keys/state/reducers.ts
View file @
d1c52383
...
@@ -5,6 +5,7 @@ export const initialApiKeysState: ApiKeysState = {
...
@@ -5,6 +5,7 @@ export const initialApiKeysState: ApiKeysState = {
keys
:
[],
keys
:
[],
searchQuery
:
''
,
searchQuery
:
''
,
hasFetched
:
false
,
hasFetched
:
false
,
includeExpired
:
false
,
};
};
export
const
apiKeysReducer
=
(
state
=
initialApiKeysState
,
action
:
Action
):
ApiKeysState
=>
{
export
const
apiKeysReducer
=
(
state
=
initialApiKeysState
,
action
:
Action
):
ApiKeysState
=>
{
...
...
public/app/features/api-keys/state/selectors.test.ts
View file @
d1c52383
...
@@ -7,7 +7,7 @@ describe('API Keys selectors', () => {
...
@@ -7,7 +7,7 @@ describe('API Keys selectors', () => {
const
mockKeys
=
getMultipleMockKeys
(
5
);
const
mockKeys
=
getMultipleMockKeys
(
5
);
it
(
'should return all keys if no search query'
,
()
=>
{
it
(
'should return all keys if no search query'
,
()
=>
{
const
mockState
:
ApiKeysState
=
{
keys
:
mockKeys
,
searchQuery
:
''
,
hasFetched
:
false
};
const
mockState
:
ApiKeysState
=
{
keys
:
mockKeys
,
searchQuery
:
''
,
hasFetched
:
false
,
includeExpired
:
false
};
const
keys
=
getApiKeys
(
mockState
);
const
keys
=
getApiKeys
(
mockState
);
...
@@ -15,7 +15,7 @@ describe('API Keys selectors', () => {
...
@@ -15,7 +15,7 @@ describe('API Keys selectors', () => {
});
});
it
(
'should filter keys if search query exists'
,
()
=>
{
it
(
'should filter keys if search query exists'
,
()
=>
{
const
mockState
:
ApiKeysState
=
{
keys
:
mockKeys
,
searchQuery
:
'5'
,
hasFetched
:
false
};
const
mockState
:
ApiKeysState
=
{
keys
:
mockKeys
,
searchQuery
:
'5'
,
hasFetched
:
false
,
includeExpired
:
false
};
const
keys
=
getApiKeys
(
mockState
);
const
keys
=
getApiKeys
(
mockState
);
...
...
public/app/types/apiKeys.ts
View file @
d1c52383
...
@@ -18,4 +18,5 @@ export interface ApiKeysState {
...
@@ -18,4 +18,5 @@ export interface ApiKeysState {
keys
:
ApiKey
[];
keys
:
ApiKey
[];
searchQuery
:
string
;
searchQuery
:
string
;
hasFetched
:
boolean
;
hasFetched
:
boolean
;
includeExpired
:
boolean
;
}
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment