本文整理汇总了Python中superdesk.errors.SuperdeskApiError类的典型用法代码示例。如果您正苦于以下问题:Python SuperdeskApiError类的具体用法?Python SuperdeskApiError怎么用?Python SuperdeskApiError使用的例子?那么恭喜您, 这里精选的类代码示例或许可以为您提供帮助。
在下文中一共展示了SuperdeskApiError类的20个代码示例,这些例子默认根据受欢迎程度排序。您可以为喜欢或者感觉有用的代码点赞,您的评价将有助于我们的系统推荐出更棒的Python代码示例。
示例1: move_content
def move_content(self, id, doc):
archive_service = get_resource_service(ARCHIVE)
archived_doc = archive_service.find_one(req=None, _id=id)
if not archived_doc:
raise SuperdeskApiError.notFoundError('Fail to found item with guid: %s' % id)
current_stage_of_item = archived_doc.get('task', {}).get('stage')
if current_stage_of_item and str(current_stage_of_item) == str(doc.get('task', {}).get('stage')):
raise SuperdeskApiError.preconditionFailedError(message='Move is not allowed within the same stage.')
if not is_workflow_state_transition_valid('submit_to_desk', archived_doc[config.CONTENT_STATE]):
raise InvalidStateTransitionError()
original = dict(archived_doc)
send_to(archived_doc, doc.get('task', {}).get('desc'), doc.get('task', {}).get('stage'))
if archived_doc[config.CONTENT_STATE] not in ['published', 'scheduled', 'killed']:
archived_doc[config.CONTENT_STATE] = 'submitted'
resolve_document_version(archived_doc, ARCHIVE, 'PATCH', original)
del archived_doc['_id']
archive_service.update(original['_id'], archived_doc, original)
insert_into_versions(id_=original['_id'])
return archived_doc
开发者ID:ahilles107,项目名称:superdesk-1,代码行数:29,代码来源:archive_move.py
示例2: lock
def lock(self, item_filter, user_id, session_id, etag):
item_model = get_model(ItemModel)
item = item_model.find_one(item_filter)
if not item:
raise SuperdeskApiError.notFoundError()
can_user_lock, error_message = self.can_lock(item, user_id, session_id)
if can_user_lock:
self.app.on_item_lock(item, user_id)
updates = {LOCK_USER: user_id, LOCK_SESSION: session_id, 'lock_time': utcnow()}
item_model.update(item_filter, updates)
if item.get(TASK):
item[TASK]['user'] = user_id
else:
item[TASK] = {'user': user_id}
superdesk.get_resource_service('tasks').assign_user(item[config.ID_FIELD], item[TASK])
self.app.on_item_locked(item, user_id)
push_notification('item:lock',
item=str(item.get(config.ID_FIELD)),
item_version=str(item.get(config.VERSION)),
user=str(user_id), lock_time=updates['lock_time'],
lock_session=str(session_id))
else:
raise SuperdeskApiError.forbiddenError(message=error_message)
item = item_model.find_one(item_filter)
return item
开发者ID:MiczFlor,项目名称:superdesk-core,代码行数:31,代码来源:item_lock.py
示例3: __validate_schedule
def __validate_schedule(self, schedule):
if schedule is not None \
and (len(schedule) == 0
or (schedule.get('day_of_week') is None
or len(schedule.get('day_of_week', [])) == 0)):
raise SuperdeskApiError.badRequestError(message="Schedule when defined can't be empty.")
if schedule:
day_of_week = [str(week_day).upper() for week_day in schedule.get('day_of_week', [])]
if not (len(set(day_of_week) & set(self.day_of_week)) == len(day_of_week)):
raise SuperdeskApiError.badRequestError(message="Invalid values for day of week.")
if schedule.get('hour_of_day_from') or schedule.get('hour_of_day_to'):
try:
from_time = datetime.strptime(schedule.get('hour_of_day_from'), '%H%M')
except:
raise SuperdeskApiError.badRequestError(message="Invalid value for from time.")
try:
to_time = datetime.strptime(schedule.get('hour_of_day_to'), '%H%M')
except:
raise SuperdeskApiError.badRequestError(message="Invalid value for to time.")
if from_time > to_time:
raise SuperdeskApiError.badRequestError(message="From time should be less than To Time.")
开发者ID:oxcarh,项目名称:superdesk,代码行数:25,代码来源:routing_rules.py
示例4: get_expiry
def get_expiry(desk_id, stage_id, offset=None):
"""
Calculates the expiry for a content from fetching the expiry duration from one of the below
1. desk identified by desk_id
2. stage identified by stage_id
:param desk_id: desk identifier
:param stage_id: stage identifier
:return: when the doc will expire
"""
stage = None
desk = None
if desk_id:
desk = superdesk.get_resource_service('desks').find_one(req=None, _id=desk_id)
if not desk:
raise SuperdeskApiError.notFoundError('Invalid desk identifier %s' % desk_id)
if stage_id:
stage = get_resource_service('stages').find_one(req=None, _id=stage_id)
if not stage:
raise SuperdeskApiError.notFoundError('Invalid stage identifier %s' % stage_id)
return get_item_expiry(desk, stage, offset)
开发者ID:vladnicoara,项目名称:superdesk,代码行数:25,代码来源:common.py
示例5: on_update
def on_update(self, updates, original):
user = get_user()
if 'unique_name' in updates and not is_admin(user) \
and (user['active_privileges'].get('metadata_uniquename', 0) == 0):
raise SuperdeskApiError.forbiddenError("Unauthorized to modify Unique Name")
remove_unwanted(updates)
if self.__is_req_for_save(updates):
update_state(original, updates)
lock_user = original.get('lock_user', None)
force_unlock = updates.get('force_unlock', False)
original_creator = updates.get('original_creator', None)
if not original_creator:
updates['original_creator'] = original['original_creator']
str_user_id = str(user.get('_id'))
if lock_user and str(lock_user) != str_user_id and not force_unlock:
raise SuperdeskApiError.forbiddenError('The item was locked by another user')
updates['versioncreated'] = utcnow()
set_item_expiry(updates, original)
updates['version_creator'] = str_user_id
update_word_count(updates)
if force_unlock:
del updates['force_unlock']
开发者ID:marwoodandrew,项目名称:superdesk-server,代码行数:30,代码来源:archive.py
示例6: delete
def delete(self, lookup):
filter_id = lookup.get('_id')
# check if the filter is referenced by any subscribers...
subscribers = self._get_referencing_subscribers(filter_id)
if subscribers.count() > 0:
references = ','.join(s['name'] for s in subscribers)
raise SuperdeskApiError.badRequestError(
'Content filter has been referenced by '
'subscriber(s) {}'.format(references)
)
# check if the filter is referenced by any routing schemes...
schemes = self._get_referencing_routing_schemes(filter_id)
if schemes.count() > 0:
references = ','.join(s['name'] for s in schemes)
raise SuperdeskApiError.badRequestError(
'Content filter has been referenced by '
'routing scheme(s) {}'.format(references)
)
# check if the filter is referenced by any other content filters...
referenced_filters = self._get_content_filters_by_content_filter(filter_id)
if referenced_filters.count() > 0:
references = ','.join([pf['name'] for pf in referenced_filters])
raise SuperdeskApiError.badRequestError(
'Content filter has been referenced in {}'.format(references))
return super().delete(lookup)
开发者ID:ancafarcas,项目名称:superdesk,代码行数:29,代码来源:content_filter.py
示例7: _validate_disable
def _validate_disable(self, updates, original):
"""
Checks the templates and desks that are referencing the given
content profile if the profile is being disabled
"""
if 'enabled' in updates and updates.get('enabled') is False and original.get('enabled') is True:
templates = list(superdesk.get_resource_service('content_templates').
get_templates_by_profile_id(original.get('_id')))
if len(templates) > 0:
template_names = ', '.join([t.get('template_name') for t in templates])
raise SuperdeskApiError.badRequestError(
message='Cannot disable content profile as following templates are referencing: {}'.
format(template_names))
req = ParsedRequest()
all_desks = list(superdesk.get_resource_service('desks').get(req=req, lookup={}))
profile_desks = [desk for desk in all_desks if
desk.get('default_content_profile') == str(original.get('_id'))]
if len(profile_desks) > 0:
profile_desk_names = ', '.join([d.get('name') for d in profile_desks])
raise SuperdeskApiError.badRequestError(
message='Cannot disable content profile as following desks are referencing: {}'.
format(profile_desk_names))
开发者ID:sjunaid,项目名称:superdesk-core,代码行数:25,代码来源:content_types.py
示例8: create
def create(self, docs, **kwargs):
for doc in docs:
if doc.get('group_by') and doc.get('desk'):
raise SuperdeskApiError.badRequestError('The desk must not be defined when group by is defined.')
if not doc.get('group_by', False) and not doc.get('desk'):
raise SuperdeskApiError.badRequestError('The desk is required when group by desk is false')
return super().create(docs, **kwargs)
开发者ID:Anca21,项目名称:superdesk-analytics,代码行数:7,代码来源:saved_activity_reports.py
示例9: create
def create(self, docs, **kwargs):
target_id = request.view_args['target_id']
doc = docs[0]
link_id = doc.get('link_id')
desk_id = doc.get('desk')
service = get_resource_service(ARCHIVE)
target = service.find_one(req=None, _id=target_id)
self._validate_link(target, target_id)
link = {}
if is_genre(target, BROADCAST_GENRE):
raise SuperdeskApiError.badRequestError("Cannot add new take to the story with genre as broadcast.")
if desk_id:
link = {'task': {'desk': desk_id}}
user = get_user()
lookup = {'_id': desk_id, 'members.user': user['_id']}
desk = get_resource_service('desks').find_one(req=None, **lookup)
if not desk:
raise SuperdeskApiError.forbiddenError("No privileges to create new take on requested desk.")
link['task']['stage'] = desk['working_stage']
if link_id:
link = service.find_one(req=None, _id=link_id)
linked_item = self.packageService.link_as_next_take(target, link)
doc.update(linked_item)
build_custom_hateoas(CUSTOM_HATEOAS, doc)
return [linked_item['_id']]
开发者ID:actionless,项目名称:superdesk,代码行数:30,代码来源:archive_link.py
示例10: on_update
def on_update(self, updates, original):
"""Called on the patch request to mark a activity/notification/comment as read and nothing else
:param updates:
:param original:
:return:
"""
user = getattr(g, 'user', None)
if not user:
raise SuperdeskApiError.notFoundError('Can not determine user')
user_id = user.get('_id')
# make sure that the user making the read notification is in the notification list
if not self.is_recipient(updates, user_id):
raise SuperdeskApiError.forbiddenError('User is not in the notification list')
# make sure the transition is from not read to read
if not self.is_read(updates, user_id) and self.is_read(original, user_id):
raise SuperdeskApiError.forbiddenError('Can not set notification as read')
# make sure that no other users are being marked as read
for recipient in updates.get('recipients', []):
if recipient['user_id'] != user_id:
if self.is_read(updates, recipient['user_id']) != self.is_read(original, recipient['user_id']):
raise SuperdeskApiError.forbiddenError('Can not set other users notification as read')
# make sure that no other fields are being up dated just read and _updated
if len(updates) != 2:
raise SuperdeskApiError.forbiddenError('Can not update')
开发者ID:superdesk,项目名称:superdesk-core,代码行数:29,代码来源:activity.py
示例11: __validate_seq_num_settings
def __validate_seq_num_settings(self, output_channel):
"""
Validates the 'sequence_num_settings' property if present in output_channel. Below are the validation rules:
1. If min value is present then it should be greater than 0
2. If min is present and max value isn't available then it's defaulted to MAX_VALUE_OF_PUBLISH_SEQUENCE
3. If start_from present then the value should be between min and max.
Otherwise, it's defaulted to the value of min
:return: True if validation succeeds otherwise return False.
"""
if output_channel.get('sequence_num_settings'):
min = output_channel.get('sequence_num_settings').get('min', 1)
max = output_channel.get('sequence_num_settings').get('max', MAX_VALUE_OF_PUBLISH_SEQUENCE)
start_from = output_channel.get('sequence_num_settings').get('start_from', min)
if min <= 0:
raise SuperdeskApiError.badRequestError(payload={"sequence_num_settings.min": 1},
message="Value of Minimum in Sequence Number Settings should "
"be greater than 0")
if min >= max:
raise SuperdeskApiError.badRequestError(payload={"sequence_num_settings.min": 1},
message="Value of Minimum in Sequence Number Settings should "
"be less than the value of Maximum")
if not min <= start_from <= max:
raise SuperdeskApiError.badRequestError(payload={"sequence_num_settings.start_from": 1},
message="Value of Start From in Sequence Number Settings "
"should be between Minimum and Maximum")
del output_channel['sequence_num_settings']
output_channel['sequence_num_settings'] = {"min": min, "max": max, "start_from": start_from}
return True
开发者ID:ahilles107,项目名称:superdesk-1,代码行数:35,代码来源:output_channels.py
示例12: create
def create(self, docs, **kwargs):
service = get_resource_service('archive')
doc = docs[0]
formatter_name = doc.get('formatter_name')
if not formatter_name:
raise SuperdeskApiError.badRequestError('Formatter name not found')
formatter = self._get_formatter(formatter_name)
if not formatter:
raise SuperdeskApiError.badRequestError('Formatter not found')
if 'article_id' in doc:
article_id = doc.get('article_id')
article = service.find_one(req=None, _id=article_id)
if not article:
raise SuperdeskApiError.badRequestError('Article not found!')
try:
self._validate(article)
sequence, formatted_doc = formatter.format(article, {'_id': '0'}, None)[0]
formatted_doc = formatted_doc.replace('\'\'', '\'')
except Exception as ex:
raise SuperdeskApiError.\
badRequestError('Error in formatting article: {}'.format(str(ex)))
return [{'formatted_doc': formatted_doc}]
开发者ID:liveblog,项目名称:superdesk-core,代码行数:29,代码来源:service.py
示例13: get
def get(self, req, lookup):
"""
Return a list of items related to the given item. The given item id is retrieved
from the lookup dictionary as 'item_id'
"""
if 'item_id' not in lookup:
raise SuperdeskApiError.badRequestError('The item identifier is required')
item = get_resource_service('archive_autosave').find_one(req=None, _id=lookup['item_id'])
if not item:
item = get_resource_service('archive').find_one(req=None, _id=lookup['item_id'])
if not item:
raise SuperdeskApiError.notFoundError('Invalid item identifer')
keywords = self.provider.get_keywords(self._transform(item))
if not keywords:
return ElasticCursor([])
query = {
'query': {
'filtered': {
'query': {
'query_string': {
'query': ' '.join(kwd['text'] for kwd in keywords)
}
}
}
}
}
req = ParsedRequest()
req.args = {'source': json.dumps(query), 'repo': 'archive,published,archived'}
return get_resource_service('search').get(req=req, lookup=None)
开发者ID:hlmnrmr,项目名称:superdesk-core,代码行数:33,代码来源:service.py
示例14: move_content
def move_content(self, id, doc):
archive_service = get_resource_service(ARCHIVE)
archived_doc = archive_service.find_one(req=None, _id=id)
if not archived_doc:
raise SuperdeskApiError.notFoundError('Fail to found item with guid: %s' % id)
current_stage_of_item = archived_doc.get('task', {}).get('stage')
if current_stage_of_item and str(current_stage_of_item) == str(doc.get('task', {}).get('stage')):
raise SuperdeskApiError.preconditionFailedError(message='Move is not allowed within the same stage.')
if not is_workflow_state_transition_valid('submit_to_desk', archived_doc[ITEM_STATE]):
raise InvalidStateTransitionError()
original = dict(archived_doc)
user = get_user()
send_to(doc=archived_doc, desk_id=doc.get('task', {}).get('desc'), stage_id=doc.get('task', {}).get('stage'),
user_id=user.get(config.ID_FIELD))
if archived_doc[ITEM_STATE] not in {CONTENT_STATE.PUBLISHED, CONTENT_STATE.SCHEDULED, CONTENT_STATE.KILLED}:
archived_doc[ITEM_STATE] = CONTENT_STATE.SUBMITTED
archived_doc[ITEM_OPERATION] = ITEM_MOVE
set_sign_off(archived_doc, original=original)
resolve_document_version(archived_doc, ARCHIVE, 'PATCH', original)
del archived_doc[config.ID_FIELD]
archive_service.update(original[config.ID_FIELD], archived_doc, original)
insert_into_versions(id_=original[config.ID_FIELD])
return archived_doc
开发者ID:chalkjockey,项目名称:superdesk,代码行数:33,代码来源:archive_move.py
示例15: _validate_aspect_ratio
def _validate_aspect_ratio(self, crop, doc):
"""
Checks if the aspect ratio is consistent with one in defined in spec
:param crop: Spec parameters
:param doc: Posted parameters
:raises SuperdeskApiError.badRequestError:
"""
if 'CropLeft' not in doc:
return
width = doc['CropRight'] - doc['CropLeft']
height = doc['CropBottom'] - doc['CropTop']
if not (crop.get('width') or crop.get('height') or crop.get('ratio')):
raise SuperdeskApiError.badRequestError(
message='Crop data are missing. width, height or ratio need to be defined')
if crop.get('width') and crop.get('height'):
expected_crop_width = int(crop['width'])
expected_crop_height = int(crop['height'])
if width < expected_crop_width or height < expected_crop_height:
raise SuperdeskApiError.badRequestError(
message='Wrong crop size. Minimum crop size is {}x{}.'.format(crop['width'], crop['height']))
doc_ratio = round(width / height, 1)
spec_ratio = round(expected_crop_width / expected_crop_height, 1)
if doc_ratio != spec_ratio:
raise SuperdeskApiError.badRequestError(message='Wrong aspect ratio!')
elif crop.get('ratio'):
ratio = crop.get('ratio')
if type(ratio) not in [int, float]:
ratio = ratio.split(':')
ratio = int(ratio[0]) / int(ratio[1])
if abs((width / height) - ratio) > 0.01:
raise SuperdeskApiError.badRequestError(
message='Ratio %s is not respected. We got %f' % (crop.get('ratio'), abs((width / height))))
开发者ID:MiczFlor,项目名称:superdesk-core,代码行数:33,代码来源:crop.py
示例16: _validate
def _validate(self, doc_in_archive, doc, guid_to_duplicate):
"""Validates if the given archived_doc is still eligible to be duplicated.
Rules:
1. Is the item requested found in archive collection?
2. Is workflow transition valid?
3. Is item locked by another user?
:param doc_in_archive: object representing the doc in archive collection
:type doc_in_archive: dict
:param doc: object received as part of request
:type doc: dict
:param guid_to_duplicate: GUID of the item to duplicate
:type guid_to_duplicate: str
:raises
SuperdeskApiError.notFoundError: If doc_in_archive is None
SuperdeskApiError.forbiddenError: if item is locked
InvalidStateTransitionError: if workflow transition is invalid
"""
if not doc_in_archive:
raise SuperdeskApiError.notFoundError('Fail to found item with guid: %s' % guid_to_duplicate)
if not is_workflow_state_transition_valid('duplicate', doc_in_archive[ITEM_STATE]):
raise InvalidStateTransitionError()
lock_user = doc_in_archive.get('lock_user', None)
force_unlock = doc_in_archive.get('force_unlock', False)
user = get_user()
str_user_id = str(user.get(config.ID_FIELD)) if user else None
if lock_user and str(lock_user) != str_user_id and not force_unlock:
raise SuperdeskApiError.forbiddenError('The item was locked by another user')
开发者ID:superdesk,项目名称:superdesk-core,代码行数:32,代码来源:archive_duplication.py
示例17: validate_crop
def validate_crop(self, original, updates, crop_name):
"""
:param dict original: original item
:param dict updates: updated renditions
:param str crop_name: name of the crop
:param dict doc: crop co-ordinates
:raises SuperdeskApiError.badRequestError:
For following conditions:
1) if type != picture
2) if renditions are missing in the original image
3) if original rendition is missing
4) Crop name is invalid
"""
# Check if type is picture
if original[ITEM_TYPE] != CONTENT_TYPE.PICTURE:
raise SuperdeskApiError.badRequestError(message='Only images can be cropped!')
# Check if the renditions exists
if not original.get('renditions'):
raise SuperdeskApiError.badRequestError(message='Missing renditions!')
# Check if the original rendition exists
if not original.get('renditions').get('original'):
raise SuperdeskApiError.badRequestError(message='Missing original rendition!')
# Check if the crop name is valid
crop = self.get_crop_by_name(crop_name)
crop_data = updates.get('renditions', {}).get(crop_name, {})
if not crop and 'CropLeft' in crop_data:
raise SuperdeskApiError.badRequestError(message='Unknown crop name! (name=%s)' % crop_name)
self._validate_values(crop_data)
self._validate_poi(original, updates, crop_name)
self._validate_aspect_ratio(crop, crop_data)
开发者ID:MiczFlor,项目名称:superdesk-core,代码行数:34,代码来源:crop.py
示例18: create_crop
def create_crop(self, original_image, crop_name, crop_data):
"""Create a new crop based on the crop co-ordinates
:param original: Article to add the crop
:param crop_name: Name of the crop
:param doc: Crop details
:raises SuperdeskApiError.badRequestError
:return dict: rendition
"""
original_file = superdesk.app.media.fetch_rendition(original_image)
if not original_file:
raise SuperdeskApiError.badRequestError('Original file couldn\'t be found')
try:
cropped, out = crop_image(original_file, crop_name, crop_data)
crop = self.get_crop_by_name(crop_name)
if not cropped:
raise SuperdeskApiError.badRequestError('Saving crop failed.')
# resize if needed
if crop.get('width') or crop.get('height'):
out, width, height = _resize_image(out,
size=(crop.get('width'), crop.get('height')),
keepProportions=crop.get('keep_proportions', True))
crop['width'] = width
crop['height'] = height
out.seek(0)
return self._save_cropped_image(out, original_image, crop_data)
except SuperdeskApiError:
raise
except Exception as ex:
raise SuperdeskApiError.badRequestError('Generating crop failed: {}'.format(str(ex)))
开发者ID:nistormihai,项目名称:superdesk-core,代码行数:30,代码来源:crop.py
示例19: on_delete
def on_delete(self, doc):
"""
Checks if deleting the stage would not violate data integrity, raises an exception if it does.
1/ Can't delete the default incoming stage
2/ The stage must have no documents (spiked or unspiked)
3/ The stage can not be referred to by a ingest routing rule
:param doc:
:return:
"""
if doc['default_incoming'] is True:
desk_id = doc.get('desk', None)
if desk_id and superdesk.get_resource_service('desks').find_one(req=None, _id=desk_id):
raise SuperdeskApiError.preconditionFailedError(message='Cannot delete a default stage.')
archive_versions_query = {'task.stage': str(doc[config.ID_FIELD])}
items = superdesk.get_resource_service('archive_versions').get(req=None, lookup=archive_versions_query)
if items and items.count():
raise SuperdeskApiError.preconditionFailedError(
message='Cannot delete stage as it has article(s) or referenced by versions of the article(s).')
# check if the stage is referred to in a ingest routing rule
rules = self._stage_in_rule(doc[config.ID_FIELD])
if rules.count() > 0:
rule_names = ', '.join(rule.get('name') for rule in rules)
raise SuperdeskApiError.preconditionFailedError(
message='Stage is referred by Ingest Routing Schemes : {}'.format(rule_names))
开发者ID:ancafarcas,项目名称:superdesk,代码行数:28,代码来源:stages.py
示例20: send_to
def send_to(doc, desk_id=None, stage_id=None):
"""Send item to given desk and stage.
:param doc: item to be sent
:param desk: id of desk where item should be sent
:param stage: optional stage within the desk
"""
task = doc.get('task', {})
task.setdefault('desk', desk_id)
task.setdefault('stage', stage_id)
calculate_expiry_from = None
if desk_id and not stage_id:
desk = superdesk.get_resource_service('desks').find_one(req=None, _id=desk_id)
if not desk:
raise SuperdeskApiError.notFoundError('Invalid desk identifier %s' % desk_id)
calculate_expiry_from = desk
task['desk'] = desk_id
task['stage'] = desk.get('incoming_stage')
if stage_id:
stage = get_resource_service('stages').find_one(req=None, _id=stage_id)
if not stage:
raise SuperdeskApiError.notFoundError('Invalid stage identifier %s' % stage_id)
calculate_expiry_from = stage
task['desk'] = stage['desk']
task['stage'] = stage_id
if stage.get('task_status'):
task['status'] = stage['task_status']
doc['task'] = task
doc['expiry'] = get_expiry(desk_or_stage_doc=calculate_expiry_from)
开发者ID:ahilles107,项目名称:superdesk-1,代码行数:35,代码来源:tasks.py
注:本文中的superdesk.errors.SuperdeskApiError类示例由纯净天空整理自Github/MSDocs等源码及文档管理平台,相关代码片段筛选自各路编程大神贡献的开源项目,源码版权归原作者所有,传播和使用请参考对应项目的License;未经允许,请勿转载。 |
请发表评论