mirror of
https://github.com/Artemis-RGB/Artemis
synced 2025-12-13 05:48:35 +00:00
Updating - Initial GraphQL client commit
This commit is contained in:
parent
f2ef657d00
commit
3222eae876
@ -11,6 +11,7 @@
|
|||||||
<ProjectReference Include="..\Artemis.Core\Artemis.Core.csproj" />
|
<ProjectReference Include="..\Artemis.Core\Artemis.Core.csproj" />
|
||||||
<ProjectReference Include="..\Artemis.UI.Shared\Artemis.UI.Shared.csproj" />
|
<ProjectReference Include="..\Artemis.UI.Shared\Artemis.UI.Shared.csproj" />
|
||||||
<ProjectReference Include="..\Artemis.VisualScripting\Artemis.VisualScripting.csproj" />
|
<ProjectReference Include="..\Artemis.VisualScripting\Artemis.VisualScripting.csproj" />
|
||||||
|
<ProjectReference Include="..\Artemis.WebClient.Updating\Artemis.WebClient.Updating.csproj" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|||||||
@ -2,7 +2,6 @@
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Collections.ObjectModel;
|
using System.Collections.ObjectModel;
|
||||||
using System.Reactive;
|
using System.Reactive;
|
||||||
using System.Threading.Tasks;
|
|
||||||
using Artemis.Core;
|
using Artemis.Core;
|
||||||
using Artemis.Core.DryIoc;
|
using Artemis.Core.DryIoc;
|
||||||
using Artemis.UI.DryIoc;
|
using Artemis.UI.DryIoc;
|
||||||
@ -12,7 +11,6 @@ using Artemis.UI.Shared.DataModelPicker;
|
|||||||
using Artemis.UI.Shared.DryIoc;
|
using Artemis.UI.Shared.DryIoc;
|
||||||
using Artemis.UI.Shared.Services;
|
using Artemis.UI.Shared.Services;
|
||||||
using Artemis.VisualScripting.DryIoc;
|
using Artemis.VisualScripting.DryIoc;
|
||||||
using Artemis.WebClient.Updating;
|
|
||||||
using Artemis.WebClient.Updating.DryIoc;
|
using Artemis.WebClient.Updating.DryIoc;
|
||||||
using Avalonia;
|
using Avalonia;
|
||||||
using Avalonia.Controls;
|
using Avalonia.Controls;
|
||||||
|
|||||||
12
src/Artemis.WebClient.Updating/.config/dotnet-tools.json
Normal file
12
src/Artemis.WebClient.Updating/.config/dotnet-tools.json
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
{
|
||||||
|
"version": 1,
|
||||||
|
"isRoot": true,
|
||||||
|
"tools": {
|
||||||
|
"strawberryshake.tools": {
|
||||||
|
"version": "13.0.0-rc.4",
|
||||||
|
"commands": [
|
||||||
|
"dotnet-graphql"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
15
src/Artemis.WebClient.Updating/.graphqlconfig
Normal file
15
src/Artemis.WebClient.Updating/.graphqlconfig
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
{
|
||||||
|
"name": "Untitled GraphQL Schema",
|
||||||
|
"schemaPath": "schema.graphql",
|
||||||
|
"extensions": {
|
||||||
|
"endpoints": {
|
||||||
|
"Default GraphQL Endpoint": {
|
||||||
|
"url": "https://updating.artemis-rgb.com/graphql",
|
||||||
|
"headers": {
|
||||||
|
"user-agent": "JS GraphQL"
|
||||||
|
},
|
||||||
|
"introspect": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
22
src/Artemis.WebClient.Updating/.graphqlrc.json
Normal file
22
src/Artemis.WebClient.Updating/.graphqlrc.json
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
{
|
||||||
|
"schema": "schema.graphql",
|
||||||
|
"documents": "**/*.graphql",
|
||||||
|
"extensions": {
|
||||||
|
"strawberryShake": {
|
||||||
|
"name": "UpdatingClient",
|
||||||
|
"namespace": "Artemis.WebClient.Updating",
|
||||||
|
"url": "https://updating.artemis-rgb.com/graphql/",
|
||||||
|
"emitGeneratedCode": false,
|
||||||
|
"records": {
|
||||||
|
"inputs": false,
|
||||||
|
"entities": false
|
||||||
|
},
|
||||||
|
"transportProfiles": [
|
||||||
|
{
|
||||||
|
"default": "Http",
|
||||||
|
"subscription": "WebSocket"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,16 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<TargetFramework>net6.0</TargetFramework>
|
||||||
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
|
<Nullable>enable</Nullable>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="DryIoc.Microsoft.DependencyInjection" Version="6.1.0" />
|
||||||
|
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="7.0.0" />
|
||||||
|
<PackageReference Include="Microsoft.Extensions.Http" Version="7.0.0" />
|
||||||
|
<PackageReference Include="StrawberryShake.Server" Version="13.0.0-rc.4" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
</Project>
|
||||||
26
src/Artemis.WebClient.Updating/DryIoc/ContainerExtensions.cs
Normal file
26
src/Artemis.WebClient.Updating/DryIoc/ContainerExtensions.cs
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
using DryIoc;
|
||||||
|
using DryIoc.Microsoft.DependencyInjection;
|
||||||
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
|
||||||
|
namespace Artemis.WebClient.Updating.DryIoc;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Provides an extension method to register services onto a DryIoc <see cref="IContainer"/>.
|
||||||
|
/// </summary>
|
||||||
|
public static class ContainerExtensions
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Registers the updating client into the container.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="container">The builder building the current container</param>
|
||||||
|
public static void RegisterUpdatingClient(this IContainer container)
|
||||||
|
{
|
||||||
|
ServiceCollection serviceCollection = new();
|
||||||
|
serviceCollection
|
||||||
|
.AddHttpClient()
|
||||||
|
.AddUpdatingClient()
|
||||||
|
.ConfigureHttpClient(client => client.BaseAddress = new Uri("https://updating.artemis-rgb.com/graphql"));
|
||||||
|
|
||||||
|
container.WithDependencyInjectionAdapter(serviceCollection);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,16 @@
|
|||||||
|
query GetReleaseById {
|
||||||
|
release(id: "63b71dd69a5bb32a0a81a410") {
|
||||||
|
branch
|
||||||
|
commit
|
||||||
|
version
|
||||||
|
artifacts {
|
||||||
|
platform
|
||||||
|
artifactId
|
||||||
|
fileInfo {
|
||||||
|
md5Hash
|
||||||
|
downloadSize
|
||||||
|
downloads
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
13
src/Artemis.WebClient.Updating/schema.extensions.graphql
Normal file
13
src/Artemis.WebClient.Updating/schema.extensions.graphql
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
scalar _KeyFieldSet
|
||||||
|
|
||||||
|
directive @key(fields: _KeyFieldSet!) on SCHEMA | OBJECT
|
||||||
|
|
||||||
|
directive @serializationType(name: String!) on SCALAR
|
||||||
|
|
||||||
|
directive @runtimeType(name: String!) on SCALAR
|
||||||
|
|
||||||
|
directive @enumValue(value: String!) on ENUM_VALUE
|
||||||
|
|
||||||
|
directive @rename(name: String!) on INPUT_FIELD_DEFINITION | INPUT_OBJECT | ENUM | ENUM_VALUE
|
||||||
|
|
||||||
|
extend schema @key(fields: "id")
|
||||||
262
src/Artemis.WebClient.Updating/schema.graphql
Normal file
262
src/Artemis.WebClient.Updating/schema.graphql
Normal file
@ -0,0 +1,262 @@
|
|||||||
|
# This file was generated based on ".graphqlconfig". Do not edit manually.
|
||||||
|
|
||||||
|
schema {
|
||||||
|
query: Query
|
||||||
|
mutation: Mutation
|
||||||
|
}
|
||||||
|
|
||||||
|
"The `@defer` directive may be provided for fragment spreads and inline fragments to inform the executor to delay the execution of the current fragment to indicate deprioritization of the current fragment. A query with `@defer` directive will cause the request to potentially return multiple responses, where non-deferred data is delivered in the initial response and data deferred is delivered in a subsequent response. `@include` and `@skip` take precedence over `@defer`."
|
||||||
|
directive @defer(
|
||||||
|
"Deferred when true."
|
||||||
|
if: Boolean,
|
||||||
|
"If this argument label has a value other than null, it will be passed on to the result of this defer directive. This label is intended to give client applications a way to identify to which fragment a deferred result belongs to."
|
||||||
|
label: String
|
||||||
|
) on FRAGMENT_SPREAD | INLINE_FRAGMENT
|
||||||
|
|
||||||
|
"The `@stream` directive may be provided for a field of `List` type so that the backend can leverage technology such as asynchronous iterators to provide a partial list in the initial response, and additional list items in subsequent responses. `@include` and `@skip` take precedence over `@stream`."
|
||||||
|
directive @stream(
|
||||||
|
"Streamed when true."
|
||||||
|
if: Boolean,
|
||||||
|
"The initial elements that shall be send down to the consumer."
|
||||||
|
initialCount: Int! = 0,
|
||||||
|
"If this argument label has a value other than null, it will be passed on to the result of this stream directive. This label is intended to give client applications a way to identify to which fragment a streamed result belongs to."
|
||||||
|
label: String
|
||||||
|
) on FIELD
|
||||||
|
|
||||||
|
directive @authorize(
|
||||||
|
"Defines when when the resolver shall be executed.By default the resolver is executed after the policy has determined that the current user is allowed to access the field."
|
||||||
|
apply: ApplyPolicy! = BEFORE_RESOLVER,
|
||||||
|
"The name of the authorization policy that determines access to the annotated resource."
|
||||||
|
policy: String,
|
||||||
|
"Roles that are allowed to access the annotated resource."
|
||||||
|
roles: [String!]
|
||||||
|
) on SCHEMA | OBJECT | FIELD_DEFINITION
|
||||||
|
|
||||||
|
type ArtemisChannel {
|
||||||
|
branch: String!
|
||||||
|
releases: Int!
|
||||||
|
}
|
||||||
|
|
||||||
|
type Artifact {
|
||||||
|
artifactId: Long!
|
||||||
|
deltaFileInfo: ArtifactFileInfo!
|
||||||
|
fileInfo: ArtifactFileInfo!
|
||||||
|
fileName(deltaFile: Boolean!): String!
|
||||||
|
platform: Platform!
|
||||||
|
}
|
||||||
|
|
||||||
|
type ArtifactFileInfo {
|
||||||
|
downloadSize: Long!
|
||||||
|
downloads: Long!
|
||||||
|
md5Hash: String
|
||||||
|
}
|
||||||
|
|
||||||
|
type Mutation {
|
||||||
|
updateReleaseChangelog(input: UpdateReleaseChangelogInput!): UpdateReleaseChangelogPayload!
|
||||||
|
}
|
||||||
|
|
||||||
|
type Query {
|
||||||
|
channelByBranch(branch: String!): ArtemisChannel
|
||||||
|
channels: [ArtemisChannel!]!
|
||||||
|
nextRelease(branch: String!, platform: Platform!, version: String!): Release
|
||||||
|
release(id: String!): Release
|
||||||
|
releaseStatistics(order: [ReleaseStatisticSortInput!], where: ReleaseStatisticFilterInput): [ReleaseStatistic!]!
|
||||||
|
releases(order: [ReleaseSortInput!], where: ReleaseFilterInput): [Release!]!
|
||||||
|
}
|
||||||
|
|
||||||
|
type Release {
|
||||||
|
artifacts: [Artifact!]!
|
||||||
|
branch: String!
|
||||||
|
changelog: String!
|
||||||
|
commit: String!
|
||||||
|
createdAt: DateTime!
|
||||||
|
id: String!
|
||||||
|
isDraft: Boolean!
|
||||||
|
previousRelease: String
|
||||||
|
version: String!
|
||||||
|
workflowRunId: Long!
|
||||||
|
}
|
||||||
|
|
||||||
|
type ReleaseStatistic {
|
||||||
|
count: Int!
|
||||||
|
lastReportedUsage: DateTime!
|
||||||
|
linuxCount: Int!
|
||||||
|
oSXCount: Int!
|
||||||
|
releaseId: String!
|
||||||
|
windowsCount: Int!
|
||||||
|
}
|
||||||
|
|
||||||
|
type UpdateReleaseChangelogPayload {
|
||||||
|
release: Release
|
||||||
|
}
|
||||||
|
|
||||||
|
enum ApplyPolicy {
|
||||||
|
AFTER_RESOLVER
|
||||||
|
BEFORE_RESOLVER
|
||||||
|
}
|
||||||
|
|
||||||
|
enum Platform {
|
||||||
|
LINUX
|
||||||
|
OSX
|
||||||
|
WINDOWS
|
||||||
|
}
|
||||||
|
|
||||||
|
enum SortEnumType {
|
||||||
|
ASC
|
||||||
|
DESC
|
||||||
|
}
|
||||||
|
|
||||||
|
"The `DateTime` scalar represents an ISO-8601 compliant date time type."
|
||||||
|
scalar DateTime
|
||||||
|
|
||||||
|
"The `Long` scalar type represents non-fractional signed whole 64-bit numeric values. Long can represent values between -(2^63) and 2^63 - 1."
|
||||||
|
scalar Long
|
||||||
|
|
||||||
|
input ArtifactFileInfoFilterInput {
|
||||||
|
and: [ArtifactFileInfoFilterInput!]
|
||||||
|
downloadSize: ComparableInt64OperationFilterInput
|
||||||
|
downloads: ComparableInt64OperationFilterInput
|
||||||
|
md5Hash: StringOperationFilterInput
|
||||||
|
or: [ArtifactFileInfoFilterInput!]
|
||||||
|
}
|
||||||
|
|
||||||
|
input ArtifactFilterInput {
|
||||||
|
and: [ArtifactFilterInput!]
|
||||||
|
artifactId: ComparableInt64OperationFilterInput
|
||||||
|
deltaFileInfo: ArtifactFileInfoFilterInput
|
||||||
|
fileInfo: ArtifactFileInfoFilterInput
|
||||||
|
or: [ArtifactFilterInput!]
|
||||||
|
platform: PlatformOperationFilterInput
|
||||||
|
}
|
||||||
|
|
||||||
|
input BooleanOperationFilterInput {
|
||||||
|
eq: Boolean
|
||||||
|
neq: Boolean
|
||||||
|
}
|
||||||
|
|
||||||
|
input ComparableDateTimeOffsetOperationFilterInput {
|
||||||
|
eq: DateTime
|
||||||
|
gt: DateTime
|
||||||
|
gte: DateTime
|
||||||
|
in: [DateTime!]
|
||||||
|
lt: DateTime
|
||||||
|
lte: DateTime
|
||||||
|
neq: DateTime
|
||||||
|
ngt: DateTime
|
||||||
|
ngte: DateTime
|
||||||
|
nin: [DateTime!]
|
||||||
|
nlt: DateTime
|
||||||
|
nlte: DateTime
|
||||||
|
}
|
||||||
|
|
||||||
|
input ComparableInt32OperationFilterInput {
|
||||||
|
eq: Int
|
||||||
|
gt: Int
|
||||||
|
gte: Int
|
||||||
|
in: [Int!]
|
||||||
|
lt: Int
|
||||||
|
lte: Int
|
||||||
|
neq: Int
|
||||||
|
ngt: Int
|
||||||
|
ngte: Int
|
||||||
|
nin: [Int!]
|
||||||
|
nlt: Int
|
||||||
|
nlte: Int
|
||||||
|
}
|
||||||
|
|
||||||
|
input ComparableInt64OperationFilterInput {
|
||||||
|
eq: Long
|
||||||
|
gt: Long
|
||||||
|
gte: Long
|
||||||
|
in: [Long!]
|
||||||
|
lt: Long
|
||||||
|
lte: Long
|
||||||
|
neq: Long
|
||||||
|
ngt: Long
|
||||||
|
ngte: Long
|
||||||
|
nin: [Long!]
|
||||||
|
nlt: Long
|
||||||
|
nlte: Long
|
||||||
|
}
|
||||||
|
|
||||||
|
input ListFilterInputTypeOfArtifactFilterInput {
|
||||||
|
all: ArtifactFilterInput
|
||||||
|
any: Boolean
|
||||||
|
none: ArtifactFilterInput
|
||||||
|
some: ArtifactFilterInput
|
||||||
|
}
|
||||||
|
|
||||||
|
input PlatformOperationFilterInput {
|
||||||
|
eq: Platform
|
||||||
|
in: [Platform!]
|
||||||
|
neq: Platform
|
||||||
|
nin: [Platform!]
|
||||||
|
}
|
||||||
|
|
||||||
|
input ReleaseFilterInput {
|
||||||
|
and: [ReleaseFilterInput!]
|
||||||
|
artifacts: ListFilterInputTypeOfArtifactFilterInput
|
||||||
|
branch: StringOperationFilterInput
|
||||||
|
changelog: StringOperationFilterInput
|
||||||
|
commit: StringOperationFilterInput
|
||||||
|
createdAt: ComparableDateTimeOffsetOperationFilterInput
|
||||||
|
id: StringOperationFilterInput
|
||||||
|
isDraft: BooleanOperationFilterInput
|
||||||
|
or: [ReleaseFilterInput!]
|
||||||
|
previousRelease: StringOperationFilterInput
|
||||||
|
version: StringOperationFilterInput
|
||||||
|
workflowRunId: ComparableInt64OperationFilterInput
|
||||||
|
}
|
||||||
|
|
||||||
|
input ReleaseSortInput {
|
||||||
|
branch: SortEnumType
|
||||||
|
changelog: SortEnumType
|
||||||
|
commit: SortEnumType
|
||||||
|
createdAt: SortEnumType
|
||||||
|
id: SortEnumType
|
||||||
|
isDraft: SortEnumType
|
||||||
|
previousRelease: SortEnumType
|
||||||
|
version: SortEnumType
|
||||||
|
workflowRunId: SortEnumType
|
||||||
|
}
|
||||||
|
|
||||||
|
input ReleaseStatisticFilterInput {
|
||||||
|
and: [ReleaseStatisticFilterInput!]
|
||||||
|
count: ComparableInt32OperationFilterInput
|
||||||
|
lastReportedUsage: ComparableDateTimeOffsetOperationFilterInput
|
||||||
|
linuxCount: ComparableInt32OperationFilterInput
|
||||||
|
oSXCount: ComparableInt32OperationFilterInput
|
||||||
|
or: [ReleaseStatisticFilterInput!]
|
||||||
|
releaseId: StringOperationFilterInput
|
||||||
|
windowsCount: ComparableInt32OperationFilterInput
|
||||||
|
}
|
||||||
|
|
||||||
|
input ReleaseStatisticSortInput {
|
||||||
|
count: SortEnumType
|
||||||
|
lastReportedUsage: SortEnumType
|
||||||
|
linuxCount: SortEnumType
|
||||||
|
oSXCount: SortEnumType
|
||||||
|
releaseId: SortEnumType
|
||||||
|
windowsCount: SortEnumType
|
||||||
|
}
|
||||||
|
|
||||||
|
input StringOperationFilterInput {
|
||||||
|
and: [StringOperationFilterInput!]
|
||||||
|
contains: String
|
||||||
|
endsWith: String
|
||||||
|
eq: String
|
||||||
|
in: [String]
|
||||||
|
ncontains: String
|
||||||
|
nendsWith: String
|
||||||
|
neq: String
|
||||||
|
nin: [String]
|
||||||
|
nstartsWith: String
|
||||||
|
or: [StringOperationFilterInput!]
|
||||||
|
startsWith: String
|
||||||
|
}
|
||||||
|
|
||||||
|
input UpdateReleaseChangelogInput {
|
||||||
|
changelog: String!
|
||||||
|
id: String!
|
||||||
|
isDraft: Boolean!
|
||||||
|
}
|
||||||
@ -19,6 +19,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Artemis.UI.MacOS", "Artemis
|
|||||||
EndProject
|
EndProject
|
||||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Artemis.VisualScripting", "Artemis.VisualScripting\Artemis.VisualScripting.csproj", "{412B921A-26F5-4AE6-8B32-0C19BE54F421}"
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Artemis.VisualScripting", "Artemis.VisualScripting\Artemis.VisualScripting.csproj", "{412B921A-26F5-4AE6-8B32-0C19BE54F421}"
|
||||||
EndProject
|
EndProject
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Artemis.WebClient.Updating", "Artemis.WebClient.Updating\Artemis.WebClient.Updating.csproj", "{7C8C6F50-0CC8-45B3-B608-A7218C005E4B}"
|
||||||
|
EndProject
|
||||||
Global
|
Global
|
||||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
Debug|x64 = Debug|x64
|
Debug|x64 = Debug|x64
|
||||||
@ -57,6 +59,10 @@ Global
|
|||||||
{412B921A-26F5-4AE6-8B32-0C19BE54F421}.Debug|x64.Build.0 = Debug|x64
|
{412B921A-26F5-4AE6-8B32-0C19BE54F421}.Debug|x64.Build.0 = Debug|x64
|
||||||
{412B921A-26F5-4AE6-8B32-0C19BE54F421}.Release|x64.ActiveCfg = Release|x64
|
{412B921A-26F5-4AE6-8B32-0C19BE54F421}.Release|x64.ActiveCfg = Release|x64
|
||||||
{412B921A-26F5-4AE6-8B32-0C19BE54F421}.Release|x64.Build.0 = Release|x64
|
{412B921A-26F5-4AE6-8B32-0C19BE54F421}.Release|x64.Build.0 = Release|x64
|
||||||
|
{7C8C6F50-0CC8-45B3-B608-A7218C005E4B}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||||
|
{7C8C6F50-0CC8-45B3-B608-A7218C005E4B}.Debug|x64.Build.0 = Debug|Any CPU
|
||||||
|
{7C8C6F50-0CC8-45B3-B608-A7218C005E4B}.Release|x64.ActiveCfg = Release|Any CPU
|
||||||
|
{7C8C6F50-0CC8-45B3-B608-A7218C005E4B}.Release|x64.Build.0 = Release|Any CPU
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
GlobalSection(SolutionProperties) = preSolution
|
GlobalSection(SolutionProperties) = preSolution
|
||||||
HideSolutionNode = FALSE
|
HideSolutionNode = FALSE
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user