Compare commits
7 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| a7fbba4967 | |||
| 66785b1ee8 | |||
| fb240f6a5b | |||
| 2c459024d1 | |||
| b62161f762 | |||
| 9ad55bac99 | |||
| 3d3b7899e5 |
+1
-1
@@ -134,7 +134,7 @@ In ``urls.py``:
|
|||||||
)
|
)
|
||||||
|
|
||||||
urlpatterns = [
|
urlpatterns = [
|
||||||
url(r'^swagger(?P<format>.json|.yaml)$', schema_view.without_ui(cache_timeout=None), name='schema-json'),
|
url(r'^swagger(?P<format>\.json|\.yaml)$', schema_view.without_ui(cache_timeout=None), name='schema-json'),
|
||||||
url(r'^swagger/$', schema_view.with_ui('swagger', cache_timeout=None), name='schema-swagger-ui'),
|
url(r'^swagger/$', schema_view.with_ui('swagger', cache_timeout=None), name='schema-swagger-ui'),
|
||||||
url(r'^redoc/$', schema_view.with_ui('redoc', cache_timeout=None), name='schema-redoc'),
|
url(r'^redoc/$', schema_view.with_ui('redoc', cache_timeout=None), name='schema-redoc'),
|
||||||
...
|
...
|
||||||
|
|||||||
@@ -3,6 +3,38 @@ Changelog
|
|||||||
#########
|
#########
|
||||||
|
|
||||||
|
|
||||||
|
*********
|
||||||
|
**1.5.0**
|
||||||
|
*********
|
||||||
|
|
||||||
|
*Release date: Mar 12, 2018*
|
||||||
|
|
||||||
|
- **IMPROVED:** ``serializers.HiddenField`` are now hidden (:issue:`78`, :pr:`79`, thanks to :ghuser:`therefromhere`)
|
||||||
|
|
||||||
|
*NOTE:* in order for this to work, you will have to add the new ``drf_yasg.inspectors.HiddenFieldInspector`` to your
|
||||||
|
``DEFAULT_FIELD_INSPECTORS`` array if you changed it from the default value
|
||||||
|
|
||||||
|
- **IMPROVED:** type of model field is now detected for ``serializers.SlugRelatedField`` with ``read_only=True``
|
||||||
|
(:issue:`82`, :pr:`83`, thanks to :ghuser:`therefromhere`)
|
||||||
|
|
||||||
|
*********
|
||||||
|
**1.4.7**
|
||||||
|
*********
|
||||||
|
|
||||||
|
*Release date: Mar 05, 2018*
|
||||||
|
|
||||||
|
- **FIXED:** prevent crashes caused by attempting to delete object attributes which do not exist in the first place
|
||||||
|
(:issue:`76`)
|
||||||
|
|
||||||
|
*********
|
||||||
|
**1.4.6**
|
||||||
|
*********
|
||||||
|
|
||||||
|
*Release date: Mar 05, 2018*
|
||||||
|
|
||||||
|
- **IMPROVED:** updated ``swagger-ui`` to version 3.12.0
|
||||||
|
- **IMPROVED:** updated ``ReDoc`` to version 1.21.2
|
||||||
|
|
||||||
*********
|
*********
|
||||||
**1.4.5**
|
**1.4.5**
|
||||||
*********
|
*********
|
||||||
|
|||||||
@@ -66,6 +66,7 @@ to this list.
|
|||||||
:class:`'drf_yasg.inspectors.ChoiceFieldInspector' <.inspectors.ChoiceFieldInspector>`, |br| \
|
:class:`'drf_yasg.inspectors.ChoiceFieldInspector' <.inspectors.ChoiceFieldInspector>`, |br| \
|
||||||
:class:`'drf_yasg.inspectors.FileFieldInspector' <.inspectors.FileFieldInspector>`, |br| \
|
:class:`'drf_yasg.inspectors.FileFieldInspector' <.inspectors.FileFieldInspector>`, |br| \
|
||||||
:class:`'drf_yasg.inspectors.DictFieldInspector' <.inspectors.DictFieldInspector>`, |br| \
|
:class:`'drf_yasg.inspectors.DictFieldInspector' <.inspectors.DictFieldInspector>`, |br| \
|
||||||
|
:class:`'drf_yasg.inspectors.HiddenFieldInspector' <.inspectors.HiddenFieldInspector>`, |br| \
|
||||||
:class:`'drf_yasg.inspectors.SimpleFieldInspector' <.inspectors.SimpleFieldInspector>`, |br| \
|
:class:`'drf_yasg.inspectors.SimpleFieldInspector' <.inspectors.SimpleFieldInspector>`, |br| \
|
||||||
:class:`'drf_yasg.inspectors.StringDefaultFieldInspector' <.inspectors.StringDefaultFieldInspector>`, |br| \
|
:class:`'drf_yasg.inspectors.StringDefaultFieldInspector' <.inspectors.StringDefaultFieldInspector>`, |br| \
|
||||||
``]``
|
``]``
|
||||||
|
|||||||
Generated
+10
-10
@@ -211,9 +211,9 @@
|
|||||||
"integrity": "sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw=="
|
"integrity": "sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw=="
|
||||||
},
|
},
|
||||||
"readable-stream": {
|
"readable-stream": {
|
||||||
"version": "2.3.4",
|
"version": "2.3.5",
|
||||||
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.4.tgz",
|
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.5.tgz",
|
||||||
"integrity": "sha512-vuYxeWYM+fde14+rajzqgeohAI7YoJcHE7kXDAc4Nk0EbuKnJfqtY9YtRkLo/tqkuF7MsBQRhPnPeyjYITp3ZQ==",
|
"integrity": "sha512-tK0yDhrkygt/knjowCUiWP9YdV7c5R+8cR0r/kt9ZhBU906Fs6RpQJCEilamRJj1Nx2rWI6LkW9gKqjTkshhEw==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"core-util-is": "1.0.2",
|
"core-util-is": "1.0.2",
|
||||||
"inherits": "2.0.3",
|
"inherits": "2.0.3",
|
||||||
@@ -225,9 +225,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"redoc": {
|
"redoc": {
|
||||||
"version": "1.21.0",
|
"version": "1.21.2",
|
||||||
"resolved": "https://registry.npmjs.org/redoc/-/redoc-1.21.0.tgz",
|
"resolved": "https://registry.npmjs.org/redoc/-/redoc-1.21.2.tgz",
|
||||||
"integrity": "sha1-RY8E7b7MqyVbQORhZA0eRG949N0=",
|
"integrity": "sha1-uMeLfDxtwFjmeZniwvYbqFjewaY=",
|
||||||
"requires": {
|
"requires": {
|
||||||
"core-js": "2.5.3",
|
"core-js": "2.5.3",
|
||||||
"dropkickjs": "2.1.10",
|
"dropkickjs": "2.1.10",
|
||||||
@@ -301,7 +301,7 @@
|
|||||||
"requires": {
|
"requires": {
|
||||||
"builtin-status-codes": "3.0.0",
|
"builtin-status-codes": "3.0.0",
|
||||||
"inherits": "2.0.3",
|
"inherits": "2.0.3",
|
||||||
"readable-stream": "2.3.4",
|
"readable-stream": "2.3.5",
|
||||||
"to-arraybuffer": "1.0.1",
|
"to-arraybuffer": "1.0.1",
|
||||||
"xtend": "4.0.1"
|
"xtend": "4.0.1"
|
||||||
}
|
}
|
||||||
@@ -315,9 +315,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"swagger-ui-dist": {
|
"swagger-ui-dist": {
|
||||||
"version": "3.10.0",
|
"version": "3.12.1",
|
||||||
"resolved": "https://registry.npmjs.org/swagger-ui-dist/-/swagger-ui-dist-3.10.0.tgz",
|
"resolved": "https://registry.npmjs.org/swagger-ui-dist/-/swagger-ui-dist-3.12.1.tgz",
|
||||||
"integrity": "sha1-ilrzP/ImPHFaFD9z8qjUfVOZQ+8="
|
"integrity": "sha1-uIeIiPAM8BPvlf9xfluRK9SoTjo="
|
||||||
},
|
},
|
||||||
"tiny-emitter": {
|
"tiny-emitter": {
|
||||||
"version": "2.0.2",
|
"version": "2.0.2",
|
||||||
|
|||||||
+2
-2
@@ -1,8 +1,8 @@
|
|||||||
{
|
{
|
||||||
"name": "drf-yasg",
|
"name": "drf-yasg",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"redoc": "^1.21.0",
|
"redoc": "^1.21.2",
|
||||||
"swagger-ui-dist": "^3.10.0"
|
"swagger-ui-dist": "^3.12.1"
|
||||||
},
|
},
|
||||||
"repository": {
|
"repository": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ SWAGGER_DEFAULTS = {
|
|||||||
'drf_yasg.inspectors.ChoiceFieldInspector',
|
'drf_yasg.inspectors.ChoiceFieldInspector',
|
||||||
'drf_yasg.inspectors.FileFieldInspector',
|
'drf_yasg.inspectors.FileFieldInspector',
|
||||||
'drf_yasg.inspectors.DictFieldInspector',
|
'drf_yasg.inspectors.DictFieldInspector',
|
||||||
|
'drf_yasg.inspectors.HiddenFieldInspector',
|
||||||
'drf_yasg.inspectors.SimpleFieldInspector',
|
'drf_yasg.inspectors.SimpleFieldInspector',
|
||||||
'drf_yasg.inspectors.StringDefaultFieldInspector',
|
'drf_yasg.inspectors.StringDefaultFieldInspector',
|
||||||
],
|
],
|
||||||
|
|||||||
@@ -356,9 +356,9 @@ class OpenAPISchemaGenerator(object):
|
|||||||
|
|
||||||
view_inspector = view_inspector_cls(view, path, method, components, request, overrides)
|
view_inspector = view_inspector_cls(view, path, method, components, request, overrides)
|
||||||
operation = view_inspector.get_operation(operation_keys)
|
operation = view_inspector.get_operation(operation_keys)
|
||||||
if set(operation.consumes) == set(self.consumes):
|
if 'consumes' in operation and set(operation.consumes) == set(self.consumes):
|
||||||
del operation.consumes
|
del operation.consumes
|
||||||
if set(operation.produces) == set(self.produces):
|
if 'produces' in operation and set(operation.produces) == set(self.produces):
|
||||||
del operation.produces
|
del operation.produces
|
||||||
return operation
|
return operation
|
||||||
|
|
||||||
|
|||||||
@@ -4,7 +4,8 @@ from .base import (
|
|||||||
)
|
)
|
||||||
from .field import (
|
from .field import (
|
||||||
CamelCaseJSONFilter, ChoiceFieldInspector, DictFieldInspector, FileFieldInspector, InlineSerializerInspector,
|
CamelCaseJSONFilter, ChoiceFieldInspector, DictFieldInspector, FileFieldInspector, InlineSerializerInspector,
|
||||||
ReferencingSerializerInspector, RelatedFieldInspector, SimpleFieldInspector, StringDefaultFieldInspector
|
ReferencingSerializerInspector, RelatedFieldInspector, SimpleFieldInspector, StringDefaultFieldInspector,
|
||||||
|
HiddenFieldInspector,
|
||||||
)
|
)
|
||||||
from .query import CoreAPICompatInspector, DjangoRestResponsePagination
|
from .query import CoreAPICompatInspector, DjangoRestResponsePagination
|
||||||
from .view import SwaggerAutoSchema
|
from .view import SwaggerAutoSchema
|
||||||
@@ -24,7 +25,7 @@ __all__ = [
|
|||||||
# field inspectors
|
# field inspectors
|
||||||
'InlineSerializerInspector', 'ReferencingSerializerInspector', 'RelatedFieldInspector', 'SimpleFieldInspector',
|
'InlineSerializerInspector', 'ReferencingSerializerInspector', 'RelatedFieldInspector', 'SimpleFieldInspector',
|
||||||
'FileFieldInspector', 'ChoiceFieldInspector', 'DictFieldInspector', 'StringDefaultFieldInspector',
|
'FileFieldInspector', 'ChoiceFieldInspector', 'DictFieldInspector', 'StringDefaultFieldInspector',
|
||||||
'CamelCaseJSONFilter',
|
'CamelCaseJSONFilter', 'HiddenFieldInspector',
|
||||||
|
|
||||||
# view inspectors
|
# view inspectors
|
||||||
'SwaggerAutoSchema',
|
'SwaggerAutoSchema',
|
||||||
|
|||||||
@@ -89,9 +89,9 @@ class InlineSerializerInspector(SerializerInspector):
|
|||||||
properties=properties,
|
properties=properties,
|
||||||
required=required or None,
|
required=required or None,
|
||||||
)
|
)
|
||||||
if not ref_name:
|
if not ref_name and 'title' in result:
|
||||||
# on an inline model, the title is derived from the field name
|
# on an inline model, the title is derived from the field name
|
||||||
# but is visually displayed like the model named, which is confusing
|
# but is visually displayed like the model name, which is confusing
|
||||||
# it is better to just remove title from inline models
|
# it is better to just remove title from inline models
|
||||||
del result.title
|
del result.title
|
||||||
return result
|
return result
|
||||||
@@ -161,7 +161,11 @@ def get_related_model(model, source):
|
|||||||
:return: related model or ``None``
|
:return: related model or ``None``
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
return getattr(model, source).rel.related_model
|
descriptor = getattr(model, source)
|
||||||
|
try:
|
||||||
|
return descriptor.rel.related_model
|
||||||
|
except Exception:
|
||||||
|
return descriptor.field.remote_field.model
|
||||||
except Exception: # pragma: no cover
|
except Exception: # pragma: no cover
|
||||||
return None
|
return None
|
||||||
|
|
||||||
@@ -465,11 +469,21 @@ class DictFieldInspector(FieldInspector):
|
|||||||
return NotHandled
|
return NotHandled
|
||||||
|
|
||||||
|
|
||||||
|
class HiddenFieldInspector(FieldInspector):
|
||||||
|
"""Hide ``HiddenField``."""
|
||||||
|
|
||||||
|
def field_to_swagger_object(self, field, swagger_object_type, use_references, **kwargs):
|
||||||
|
if isinstance(field, serializers.HiddenField):
|
||||||
|
return None
|
||||||
|
|
||||||
|
return NotHandled
|
||||||
|
|
||||||
|
|
||||||
class StringDefaultFieldInspector(FieldInspector):
|
class StringDefaultFieldInspector(FieldInspector):
|
||||||
"""For otherwise unhandled fields, return them as plain :data:`.TYPE_STRING` objects."""
|
"""For otherwise unhandled fields, return them as plain :data:`.TYPE_STRING` objects."""
|
||||||
|
|
||||||
def field_to_swagger_object(self, field, swagger_object_type, use_references, **kwargs): # pragma: no cover
|
def field_to_swagger_object(self, field, swagger_object_type, use_references, **kwargs): # pragma: no cover
|
||||||
# TODO unhandled fields: TimeField HiddenField JSONField
|
# TODO unhandled fields: TimeField JSONField
|
||||||
SwaggerType, ChildSwaggerType = self._get_partial_types(field, swagger_object_type, use_references, **kwargs)
|
SwaggerType, ChildSwaggerType = self._get_partial_types(field, swagger_object_type, use_references, **kwargs)
|
||||||
return SwaggerType(type=openapi.TYPE_STRING)
|
return SwaggerType(type=openapi.TYPE_STRING)
|
||||||
|
|
||||||
|
|||||||
+2
-2
File diff suppressed because one or more lines are too long
@@ -45,11 +45,18 @@
|
|||||||
oauth2.auth.code = qp.code;
|
oauth2.auth.code = qp.code;
|
||||||
oauth2.callback({auth: oauth2.auth, redirectUrl: redirectUrl});
|
oauth2.callback({auth: oauth2.auth, redirectUrl: redirectUrl});
|
||||||
} else {
|
} else {
|
||||||
|
let oauthErrorMsg
|
||||||
|
if (qp.error) {
|
||||||
|
oauthErrorMsg = "["+qp.error+"]: " +
|
||||||
|
(qp.error_description ? qp.error_description+ ". " : "no accessCode received from the server. ") +
|
||||||
|
(qp.error_uri ? "More info: "+qp.error_uri : "");
|
||||||
|
}
|
||||||
|
|
||||||
oauth2.errCb({
|
oauth2.errCb({
|
||||||
authId: oauth2.auth.name,
|
authId: oauth2.auth.name,
|
||||||
source: "auth",
|
source: "auth",
|
||||||
level: "error",
|
level: "error",
|
||||||
message: "Authorization failed: no accessCode received from the server"
|
message: oauthErrorMsg || "[Authorization failed]: no accessCode received from the server"
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -0,0 +1,36 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# Generated by Django 1.11.11 on 2018-03-10 01:42
|
||||||
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
import django.db.models.deletion
|
||||||
|
import uuid
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('articles', '0002_article_article_type'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='ArticleGroup',
|
||||||
|
fields=[
|
||||||
|
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
|
('uuid', models.UUIDField(default=uuid.uuid4, editable=False, unique=True)),
|
||||||
|
('title', models.CharField(help_text='title model help_text', max_length=255, unique=True)),
|
||||||
|
('slug', models.SlugField(blank=True, help_text='slug model help_text', unique=True)),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='article',
|
||||||
|
name='group',
|
||||||
|
field=models.ForeignKey(blank=True, default=None, on_delete=django.db.models.deletion.PROTECT, related_name='articles_as_main', to='articles.ArticleGroup'),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='article',
|
||||||
|
name='original_group',
|
||||||
|
field=models.ForeignKey(blank=True, default=None, on_delete=django.db.models.deletion.PROTECT, related_name='articles_as_original', to='articles.ArticleGroup'),
|
||||||
|
),
|
||||||
|
]
|
||||||
@@ -1,3 +1,5 @@
|
|||||||
|
import uuid
|
||||||
|
|
||||||
from django.db import models
|
from django.db import models
|
||||||
|
|
||||||
|
|
||||||
@@ -14,3 +16,14 @@ class Article(models.Model):
|
|||||||
)
|
)
|
||||||
|
|
||||||
cover = models.ImageField(upload_to='article/original/', blank=True)
|
cover = models.ImageField(upload_to='article/original/', blank=True)
|
||||||
|
group = models.ForeignKey('ArticleGroup', related_name='articles_as_main', blank=True, default=None,
|
||||||
|
on_delete=models.PROTECT)
|
||||||
|
original_group = models.ForeignKey('ArticleGroup', related_name='articles_as_original', blank=True, default=None,
|
||||||
|
on_delete=models.PROTECT)
|
||||||
|
|
||||||
|
|
||||||
|
class ArticleGroup(models.Model):
|
||||||
|
uuid = models.UUIDField(default=uuid.uuid4, editable=False, unique=True)
|
||||||
|
|
||||||
|
title = models.CharField(help_text="title model help_text", max_length=255, blank=False, unique=True)
|
||||||
|
slug = models.SlugField(help_text="slug model help_text", unique=True, blank=True)
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
from django.utils.translation import ugettext_lazy as _
|
from django.utils.translation import ugettext_lazy as _
|
||||||
from rest_framework import serializers
|
from rest_framework import serializers
|
||||||
|
|
||||||
from articles.models import Article
|
from articles.models import Article, ArticleGroup
|
||||||
|
|
||||||
|
|
||||||
class ArticleSerializer(serializers.ModelSerializer):
|
class ArticleSerializer(serializers.ModelSerializer):
|
||||||
@@ -12,11 +12,13 @@ class ArticleSerializer(serializers.ModelSerializer):
|
|||||||
)
|
)
|
||||||
uuid = serializers.UUIDField(help_text="should articles have UUIDs?", read_only=True)
|
uuid = serializers.UUIDField(help_text="should articles have UUIDs?", read_only=True)
|
||||||
cover_name = serializers.FileField(use_url=False, source='cover', read_only=True)
|
cover_name = serializers.FileField(use_url=False, source='cover', read_only=True)
|
||||||
|
group = serializers.SlugRelatedField(slug_field='uuid', queryset=ArticleGroup.objects.all())
|
||||||
|
original_group = serializers.SlugRelatedField(slug_field='uuid', read_only=True)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = Article
|
model = Article
|
||||||
fields = ('title', 'author', 'body', 'slug', 'date_created', 'date_modified',
|
fields = ('title', 'author', 'body', 'slug', 'date_created', 'date_modified',
|
||||||
'references', 'uuid', 'cover', 'cover_name', 'article_type')
|
'references', 'uuid', 'cover', 'cover_name', 'article_type', 'group', 'original_group', )
|
||||||
read_only_fields = ('date_created', 'date_modified',
|
read_only_fields = ('date_created', 'date_modified',
|
||||||
'references', 'uuid', 'cover_name')
|
'references', 'uuid', 'cover_name')
|
||||||
lookup_field = 'slug'
|
lookup_field = 'slug'
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
from django.utils import timezone
|
||||||
from rest_framework import serializers
|
from rest_framework import serializers
|
||||||
|
|
||||||
from .models import Todo, TodoAnother, TodoYetAnother
|
from .models import Todo, TodoAnother, TodoYetAnother
|
||||||
@@ -6,7 +7,9 @@ from .models import Todo, TodoAnother, TodoYetAnother
|
|||||||
class TodoSerializer(serializers.ModelSerializer):
|
class TodoSerializer(serializers.ModelSerializer):
|
||||||
class Meta:
|
class Meta:
|
||||||
model = Todo
|
model = Todo
|
||||||
fields = ('title',)
|
fields = ('title', 'a_hidden_field',)
|
||||||
|
|
||||||
|
a_hidden_field = serializers.HiddenField(default=timezone.now)
|
||||||
|
|
||||||
|
|
||||||
class TodoAnotherSerializer(serializers.ModelSerializer):
|
class TodoAnotherSerializer(serializers.ModelSerializer):
|
||||||
|
|||||||
@@ -542,6 +542,7 @@ definitions:
|
|||||||
required:
|
required:
|
||||||
- title
|
- title
|
||||||
- body
|
- body
|
||||||
|
- group
|
||||||
type: object
|
type: object
|
||||||
properties:
|
properties:
|
||||||
title:
|
title:
|
||||||
@@ -601,6 +602,13 @@ definitions:
|
|||||||
- 3
|
- 3
|
||||||
- 7
|
- 7
|
||||||
- 8
|
- 8
|
||||||
|
group:
|
||||||
|
type: string
|
||||||
|
format: uuid
|
||||||
|
original_group:
|
||||||
|
type: string
|
||||||
|
format: uuid
|
||||||
|
readOnly: true
|
||||||
Project:
|
Project:
|
||||||
required:
|
required:
|
||||||
- projectName
|
- projectName
|
||||||
|
|||||||
Reference in New Issue
Block a user