add OAuth
Showing
11 changed files
with
395 additions
and
8 deletions
| ... | @@ -11,6 +11,8 @@ tags: | ... | @@ -11,6 +11,8 @@ tags: | 
| 11 | schemes: | 11 | schemes: | 
| 12 | - https | 12 | - https | 
| 13 | - http | 13 | - http | 
| 14 | security: | ||
| 15 | - OAuth2: [] | ||
| 14 | paths: | 16 | paths: | 
| 15 | /api/create/v1: | 17 | /api/create/v1: | 
| 16 | post: | 18 | post: | 
| ... | @@ -32,6 +34,43 @@ paths: | ... | @@ -32,6 +34,43 @@ paths: | 
| 32 | description: ok | 34 | description: ok | 
| 33 | schema: | 35 | schema: | 
| 34 | $ref: '#/definitions/ApiResponse' | 36 | $ref: '#/definitions/ApiResponse' | 
| 37 | /api/priority/v1: | ||
| 38 | post: | ||
| 39 | tags: | ||
| 40 | - doc | ||
| 41 | summary: GCAP提高申请单对应文件优先级 | ||
| 42 | consumes: | ||
| 43 | - application/json | ||
| 44 | produces: | ||
| 45 | - application/json | ||
| 46 | parameters: | ||
| 47 | - in: body | ||
| 48 | name: body | ||
| 49 | required: true | ||
| 50 | schema: | ||
| 51 | $ref: '#/definitions/Application' | ||
| 52 | responses: | ||
| 53 | 200: | ||
| 54 | description: ok | ||
| 55 | schema: | ||
| 56 | $ref: '#/definitions/ApiResponse' | ||
| 57 | securityDefinitions: | ||
| 58 | OAuth2: | ||
| 59 | type: oauth2 | ||
| 60 | flow: application | ||
| 61 | description: 'This API uses OAuth 2 with the application(clientCredentials) grant | ||
| 62 | flow. | ||
| 63 | |||
| 64 | client_id=sMlciTkppsMzARwHpCVarm5q7DP2Vucj3ny8JFhw | ||
| 65 | |||
| 66 | client_secret=WNoOilDx140ZLcenDKfsnikv7S2LIFs60DciYoqnrZaYLqYsKpcmt7mJIL69o9AEf84uQvRnS3K2UioxfjNyImjR4UOyXbDcF6qYgTLC4KDVByKFdVhKfrn2Lc4q4BNW | ||
| 67 | |||
| 68 | scopes=write | ||
| 69 | |||
| 70 | ' | ||
| 71 | tokenUrl: https://staging-bmw-ocr.situdata.com/api/oauth/token/ | ||
| 72 | scopes: | ||
| 73 | write: Grants write access | ||
| 35 | responses: | 74 | responses: | 
| 36 | ErrorResponse: | 75 | ErrorResponse: | 
| 37 | description: 调用异常, 具体情况请参考`HTTP`状态码和`code`字段 | 76 | description: 调用异常, 具体情况请参考`HTTP`状态码和`code`字段 | 
| ... | @@ -130,6 +169,54 @@ definitions: | ... | @@ -130,6 +169,54 @@ definitions: | 
| 130 | description: 元数据版本ID | 169 | description: 元数据版本ID | 
| 131 | type: string | 170 | type: string | 
| 132 | example: '8410480' | 171 | example: '8410480' | 
| 172 | Application: | ||
| 173 | type: object | ||
| 174 | required: | ||
| 175 | - APPLICATION_INFORMATION | ||
| 176 | properties: | ||
| 177 | APPLICATION_INFORMATION: | ||
| 178 | description: 申请单信息 | ||
| 179 | type: object | ||
| 180 | required: | ||
| 181 | - SUBMIT_DATETIME | ||
| 182 | - STATUS | ||
| 183 | - ENTITY | ||
| 184 | - RATING | ||
| 185 | - APPLICATION_ID | ||
| 186 | - APPLICATION_VERSION | ||
| 187 | - INTERMEDIATE_DECISION | ||
| 188 | properties: | ||
| 189 | SUBMIT_DATETIME: | ||
| 190 | description: 提交时间 | ||
| 191 | type: string | ||
| 192 | example: 2020-07-08 18:33:31+08:00 | ||
| 193 | STATUS: | ||
| 194 | description: 状态 | ||
| 195 | type: integer | ||
| 196 | example: 42 | ||
| 197 | ENTITY: | ||
| 198 | description: 业务类型 | ||
| 199 | type: string | ||
| 200 | example: CO00001 | ||
| 201 | enum: | ||
| 202 | - CO00001 | ||
| 203 | - CO00002 | ||
| 204 | RATING: | ||
| 205 | description: 排名 | ||
| 206 | type: integer | ||
| 207 | example: 4 | ||
| 208 | APPLICATION_ID: | ||
| 209 | description: 申请id | ||
| 210 | type: string | ||
| 211 | example: CH-B0011010101 | ||
| 212 | APPLICATION_VERSION: | ||
| 213 | description: 申请版本 | ||
| 214 | type: integer | ||
| 215 | example: 1 | ||
| 216 | INTERMEDIATE_DECISION: | ||
| 217 | description: '' | ||
| 218 | type: string | ||
| 219 | example: MUW | ||
| 133 | ApiResponse: | 220 | ApiResponse: | 
| 134 | description: 响应对象,code字段用于表示响应的状态; data字段用于存放响应内容 | 221 | description: 响应对象,code字段用于表示响应的状态; data字段用于存放响应内容 | 
| 135 | type: object | 222 | type: object | ... | ... | 
| ... | @@ -9,6 +9,7 @@ certifi==2020.6.20 | ... | @@ -9,6 +9,7 @@ certifi==2020.6.20 | 
| 9 | chardet==3.0.4 | 9 | chardet==3.0.4 | 
| 10 | defusedxml==0.6.0 | 10 | defusedxml==0.6.0 | 
| 11 | Django==2.1 | 11 | Django==2.1 | 
| 12 | django-oauth-toolkit==1.3.2 | ||
| 12 | djangorestframework==3.9.0 | 13 | djangorestframework==3.9.0 | 
| 13 | djangorestframework-jwt==1.11.0 | 14 | djangorestframework-jwt==1.11.0 | 
| 14 | idna==2.9 | 15 | idna==2.9 | 
| ... | @@ -17,6 +18,7 @@ isodate==0.6.0 | ... | @@ -17,6 +18,7 @@ isodate==0.6.0 | 
| 17 | lxml==4.5.1 | 18 | lxml==4.5.1 | 
| 18 | marshmallow==3.6.1 | 19 | marshmallow==3.6.1 | 
| 19 | multidict==4.7.6 | 20 | multidict==4.7.6 | 
| 21 | oauthlib==3.1.0 | ||
| 20 | pdfminer3k==1.3.4 | 22 | pdfminer3k==1.3.4 | 
| 21 | Pillow==7.1.2 | 23 | Pillow==7.1.2 | 
| 22 | ply==3.11 | 24 | ply==3.11 | ... | ... | 
src/apps/account/authentication.py
0 → 100644
| 1 | from django.contrib.auth import get_user_model | ||
| 2 | from oauth2_provider.contrib.rest_framework import OAuth2Authentication | ||
| 3 | from oauth2_provider.oauth2_backends import get_oauthlib_core | ||
| 4 | |||
| 5 | |||
| 6 | class OAuth2AuthenticationWithUser(OAuth2Authentication): | ||
| 7 | """ | ||
| 8 | OAuth 2 authentication backend using `django-oauth-toolkit` | ||
| 9 | """ | ||
| 10 | www_authenticate_realm = "api" | ||
| 11 | user = get_user_model().objects.first() | ||
| 12 | |||
| 13 | def authenticate(self, request): | ||
| 14 | """ | ||
| 15 | Returns two-tuple of (user, token) if authentication succeeds, | ||
| 16 | or None otherwise. | ||
| 17 | """ | ||
| 18 | oauthlib_core = get_oauthlib_core() | ||
| 19 | valid, r = oauthlib_core.verify_request(request, scopes=[]) | ||
| 20 | if valid: | ||
| 21 | return self.user, r.access_token | ||
| 22 | request.oauth2_error = getattr(r, "oauth2_error", {}) | ||
| 23 | return None | 
| 1 | import os | ||
| 2 | import fitz | ||
| 3 | import signal | ||
| 4 | from PIL import Image | ||
| 5 | from io import BytesIO | ||
| 6 | |||
| 7 | from django.core.management import BaseCommand | ||
| 8 | from common.mixins import LoggerMixin | ||
| 9 | |||
| 10 | |||
| 11 | class Command(BaseCommand, LoggerMixin): | ||
| 12 | |||
| 13 | def __init__(self): | ||
| 14 | super().__init__() | ||
| 15 | self.log_base = '[pdf to img]' | ||
| 16 | # 处理文件开关 | ||
| 17 | self.switch = True | ||
| 18 | # pdf页面转图片 | ||
| 19 | self.zoom_x = 2.0 | ||
| 20 | self.zoom_y = 2.0 | ||
| 21 | self.trans = fitz.Matrix(self.zoom_x, self.zoom_y).preRotate(0) # zoom factor 2 in each dimension | ||
| 22 | # 优雅退出信号:15 | ||
| 23 | signal.signal(signal.SIGTERM, self.signal_handler) | ||
| 24 | |||
| 25 | def signal_handler(self, sig, frame): | ||
| 26 | self.switch = False # 停止处理文件 | ||
| 27 | |||
| 28 | @staticmethod | ||
| 29 | def getimage(pix): | ||
| 30 | if pix.colorspace.n != 4: | ||
| 31 | return pix | ||
| 32 | tpix = fitz.Pixmap(fitz.csRGB, pix) | ||
| 33 | return tpix | ||
| 34 | |||
| 35 | def recoverpix(self, doc, item): | ||
| 36 | x = item[0] # xref of PDF image | ||
| 37 | s = item[1] # xref of its /SMask | ||
| 38 | is_rgb = True if item[5] == 'DeviceRGB' else False | ||
| 39 | |||
| 40 | # RGB | ||
| 41 | if is_rgb: | ||
| 42 | if s == 0: | ||
| 43 | return doc.extractImage(x) | ||
| 44 | # we need to reconstruct the alpha channel with the smask | ||
| 45 | pix1 = fitz.Pixmap(doc, x) | ||
| 46 | pix2 = fitz.Pixmap(doc, s) # create pixmap of the /SMask entry | ||
| 47 | |||
| 48 | # sanity check | ||
| 49 | if not (pix1.irect == pix2.irect and pix1.alpha == pix2.alpha == 0 and pix2.n == 1): | ||
| 50 | pix2 = None | ||
| 51 | return self.getimage(pix1) | ||
| 52 | |||
| 53 | pix = fitz.Pixmap(pix1) # copy of pix1, alpha channel added | ||
| 54 | pix.setAlpha(pix2.samples) # treat pix2.samples as alpha value | ||
| 55 | pix1 = pix2 = None # free temp pixmaps | ||
| 56 | return self.getimage(pix) | ||
| 57 | |||
| 58 | # GRAY/CMYK | ||
| 59 | pix1 = fitz.Pixmap(doc, x) | ||
| 60 | pix = fitz.Pixmap(pix1) # copy of pix1, alpha channel added | ||
| 61 | |||
| 62 | if s != 0: | ||
| 63 | pix2 = fitz.Pixmap(doc, s) # create pixmap of the /SMask entry | ||
| 64 | |||
| 65 | # sanity check | ||
| 66 | if not (pix1.irect == pix2.irect and pix1.alpha == pix2.alpha == 0 and pix2.n == 1): | ||
| 67 | pix2 = None | ||
| 68 | return self.getimage(pix1) | ||
| 69 | |||
| 70 | pix.setAlpha(pix2.samples) # treat pix2.samples as alpha value | ||
| 71 | |||
| 72 | pix1 = pix2 = None # free temp pixmaps | ||
| 73 | |||
| 74 | pix = fitz.Pixmap(fitz.csRGB, pix) # GRAY/CMYK to RGB | ||
| 75 | return self.getimage(pix) | ||
| 76 | |||
| 77 | @staticmethod | ||
| 78 | def get_img_data(pix): | ||
| 79 | if type(pix) is dict: # we got a raw image | ||
| 80 | ext = pix["ext"] | ||
| 81 | img_data = pix["image"] | ||
| 82 | else: # we got a pixmap | ||
| 83 | ext = 'png' | ||
| 84 | img_data = pix.getPNGData() | ||
| 85 | return ext, img_data | ||
| 86 | |||
| 87 | @staticmethod | ||
| 88 | def split_il(il): | ||
| 89 | img_il_list = [] | ||
| 90 | start = 0 | ||
| 91 | length = len(il) | ||
| 92 | for i in range(length): | ||
| 93 | if i == start: | ||
| 94 | if i == length - 1: | ||
| 95 | img_il_list.append(il[start: length]) | ||
| 96 | continue | ||
| 97 | elif i == length - 1: | ||
| 98 | img_il_list.append(il[start: length]) | ||
| 99 | continue | ||
| 100 | if il[i][2] != il[i - 1][2]: | ||
| 101 | img_il_list.append(il[start: i]) | ||
| 102 | start = i | ||
| 103 | elif il[i][3] != il[i - 1][3]: | ||
| 104 | img_il_list.append(il[start: i + 1]) | ||
| 105 | start = i + 1 | ||
| 106 | return img_il_list | ||
| 107 | |||
| 108 | def handle(self, *args, **kwargs): | ||
| 109 | pdf_dir = '/Users/clay/Desktop/普通打印-部分无线/竖版-无表格-农业银行' | ||
| 110 | img_dir = '/Users/clay/Desktop/普通打印-部分无线_img/竖版-无表格-农业银行' | ||
| 111 | os.makedirs(img_dir, exist_ok=True) | ||
| 112 | for d in os.listdir(pdf_dir): | ||
| 113 | # if d in ['.DS_Store', 'CH-B008486764.pdf', 'CH-B008003736.pdf', 'CH-B008487476.pdf', 'CH-B006763780.pdf', | ||
| 114 | # 'CH-B009000564.pdf', 'CH-B009020488.pdf']: | ||
| 115 | if d in ['.DS_Store', '1竖版-无表格-农业银行样例.PNG']: | ||
| 116 | continue | ||
| 117 | pdf_path = os.path.join(pdf_dir, d) | ||
| 118 | # pdf_path = '/Users/clay/Desktop/普通打印part2/工商银行(标准版)/CH-B006754676.pdf' | ||
| 119 | if os.path.isfile(pdf_path): | ||
| 120 | img_save_path = os.path.join(img_dir, d) | ||
| 121 | if os.path.exists(img_save_path): | ||
| 122 | continue | ||
| 123 | os.makedirs(img_save_path, exist_ok=True) | ||
| 124 | with fitz.Document(pdf_path) as pdf: | ||
| 125 | self.cronjob_log.info('{0} [pdf_path={1}] [metadata={2}]'.format( | ||
| 126 | self.log_base, pdf_path, pdf.metadata)) | ||
| 127 | # xref_list = [] | ||
| 128 | for pno in range(pdf.pageCount): | ||
| 129 | il = pdf.getPageImageList(pno) | ||
| 130 | il.sort(key=lambda x: x[0]) | ||
| 131 | img_il_list = self.split_il(il) | ||
| 132 | del il | ||
| 133 | |||
| 134 | print(img_il_list) | ||
| 135 | if len(img_il_list) > 3: # 单页无规律小图过多时,使用页面转图片 | ||
| 136 | page = pdf.loadPage(pno) | ||
| 137 | pm = page.getPixmap(matrix=self.trans, alpha=False) | ||
| 138 | save_path = os.path.join(img_save_path, 'page_{0}_img_0.png'.format(page.number)) | ||
| 139 | pm.writePNG(save_path) | ||
| 140 | # img_path_list.append(save_path) | ||
| 141 | # self.cronjob_log.info('{0} [page to img success] [doc_id={1}] [pdf_path={2}] ' | ||
| 142 | # '[page={3}]'.format(self.log_base, doc_id, pdf_path, page.number)) | ||
| 143 | else: # 提取图片 | ||
| 144 | for img_index, img_il in enumerate(img_il_list): | ||
| 145 | if len(img_il) == 1: # 当只有一张图片时, 简化处理 | ||
| 146 | pix = self.recoverpix(pdf, img_il[0]) | ||
| 147 | ext, img_data = self.get_img_data(pix) | ||
| 148 | save_path = os.path.join(img_save_path, 'page_{0}_img_{1}.{2}'.format( | ||
| 149 | pno, img_index, ext)) | ||
| 150 | with open(save_path, "wb") as f: | ||
| 151 | f.write(img_data) | ||
| 152 | # img_path_list.append(save_path) | ||
| 153 | # self.cronjob_log.info( | ||
| 154 | # '{0} [extract img success] [doc_id={1}] [pdf_path={2}] [page={3}] ' | ||
| 155 | # '[img_index={4}]'.format(self.log_base, doc_id, pdf_path, pno, img_index)) | ||
| 156 | else: # 多张图片,竖向拼接 | ||
| 157 | height_sum = 0 | ||
| 158 | im_list = [] | ||
| 159 | width = img_il[0][2] | ||
| 160 | for img in img_il: | ||
| 161 | # xref = img[0] | ||
| 162 | # if xref in xref_list: | ||
| 163 | # continue | ||
| 164 | height = img[3] | ||
| 165 | pix = self.recoverpix(pdf, img) | ||
| 166 | ext, img_data = self.get_img_data(pix) | ||
| 167 | |||
| 168 | # xref_list.append(xref) | ||
| 169 | |||
| 170 | im = Image.open(BytesIO(img_data)) | ||
| 171 | im_list.append((height, im, ext)) | ||
| 172 | height_sum += height | ||
| 173 | |||
| 174 | save_path = os.path.join(img_save_path, 'page_{0}_img_{1}.{2}'.format( | ||
| 175 | pno, img_index, im_list[0][2])) | ||
| 176 | res = Image.new(im_list[0][1].mode, (width, height_sum)) | ||
| 177 | h_now = 0 | ||
| 178 | for h, m, _ in im_list: | ||
| 179 | res.paste(m, box=(0, h_now)) | ||
| 180 | h_now += h | ||
| 181 | res.save(save_path) | ||
| 182 | # else: | ||
| 183 | # img_dir_path = os.path.join(img_dir, d) | ||
| 184 | # os.makedirs(img_dir_path, exist_ok=True) | 
| ... | @@ -5,6 +5,7 @@ import datetime | ... | @@ -5,6 +5,7 @@ import datetime | 
| 5 | from django.utils import timezone | 5 | from django.utils import timezone | 
| 6 | from django.db.utils import IntegrityError | 6 | from django.db.utils import IntegrityError | 
| 7 | from django.db.models import Q | 7 | from django.db.models import Q | 
| 8 | from rest_framework.permissions import IsAuthenticated | ||
| 8 | from webargs import fields, validate | 9 | from webargs import fields, validate | 
| 9 | from webargs.djangoparser import use_args, parser | 10 | from webargs.djangoparser import use_args, parser | 
| 10 | from settings import conf | 11 | from settings import conf | 
| ... | @@ -15,6 +16,7 @@ from common.redis_cache import redis_handler as rh | ... | @@ -15,6 +16,7 @@ from common.redis_cache import redis_handler as rh | 
| 15 | from .models import UploadDocRecords, DocStatus, PriorityApplication, GCAPRecords | 16 | from .models import UploadDocRecords, DocStatus, PriorityApplication, GCAPRecords | 
| 16 | from .mixins import DocHandler | 17 | from .mixins import DocHandler | 
| 17 | from . import consts | 18 | from . import consts | 
| 19 | from apps.account.authentication import OAuth2AuthenticationWithUser | ||
| 18 | 20 | ||
| 19 | 21 | ||
| 20 | # restframework将request.body封装至request.data, webargs从request.data中获取参数 | 22 | # restframework将request.body封装至request.data, webargs从request.data中获取参数 | 
| ... | @@ -86,7 +88,9 @@ priority_doc_args = { | ... | @@ -86,7 +88,9 @@ priority_doc_args = { | 
| 86 | 88 | ||
| 87 | 89 | ||
| 88 | class UploadDocView(GenericView, DocHandler): | 90 | class UploadDocView(GenericView, DocHandler): | 
| 89 | permission_classes = [] | 91 | permission_classes = [IsAuthenticated] | 
| 92 | authentication_classes = [OAuth2AuthenticationWithUser] | ||
| 93 | # required_scopes = ['write'] | ||
| 90 | 94 | ||
| 91 | # 上传(接收)文件接口 | 95 | # 上传(接收)文件接口 | 
| 92 | @use_args(doc_upload_args, location='data') | 96 | @use_args(doc_upload_args, location='data') | 
| ... | @@ -134,8 +138,8 @@ class UploadDocView(GenericView, DocHandler): | ... | @@ -134,8 +138,8 @@ class UploadDocView(GenericView, DocHandler): | 
| 134 | is_priority = PriorityApplication.objects.filter(application_id=application_id, on_off=True).exists() | 138 | is_priority = PriorityApplication.objects.filter(application_id=application_id, on_off=True).exists() | 
| 135 | value = ['{0}_{1}'.format(prefix, doc.id)] | 139 | value = ['{0}_{1}'.format(prefix, doc.id)] | 
| 136 | redis_res = rh.enqueue(value, is_priority) | 140 | redis_res = rh.enqueue(value, is_priority) | 
| 137 | self.running_log.info('[doc upload success] [args={0}] [record_id={1}] [is_hil={2}] [doc_id={3}] ' | 141 | self.running_log.info('[doc upload success] [args={0}] [record_id={1}] [prefix={2}] [doc_id={3}] ' | 
| 138 | '[is_priority={4}] [enqueue_res={5}]'.format(args, record.id, is_hil, doc.id, | 142 | '[is_priority={4}] [enqueue_res={5}]'.format(args, record.id, prefix, doc.id, | 
| 139 | is_priority, redis_res)) | 143 | is_priority, redis_res)) | 
| 140 | return response.ok() | 144 | return response.ok() | 
| 141 | 145 | ||
| ... | @@ -160,7 +164,8 @@ class UploadDocView(GenericView, DocHandler): | ... | @@ -160,7 +164,8 @@ class UploadDocView(GenericView, DocHandler): | 
| 160 | 164 | ||
| 161 | 165 | ||
| 162 | class PriorityDocView(GenericView, DocHandler): | 166 | class PriorityDocView(GenericView, DocHandler): | 
| 163 | permission_classes = [] | 167 | permission_classes = [IsAuthenticated] | 
| 168 | authentication_classes = [OAuth2AuthenticationWithUser] | ||
| 164 | 169 | ||
| 165 | # 优先级订单接口 | 170 | # 优先级订单接口 | 
| 166 | @use_args(priority_doc_args, location='data') | 171 | @use_args(priority_doc_args, location='data') | 
| ... | @@ -195,6 +200,25 @@ class PriorityDocView(GenericView, DocHandler): | ... | @@ -195,6 +200,25 @@ class PriorityDocView(GenericView, DocHandler): | 
| 195 | args, task_str_list, enqueue_res)) | 200 | args, task_str_list, enqueue_res)) | 
| 196 | return response.ok() | 201 | return response.ok() | 
| 197 | 202 | ||
| 203 | post.openapi_doc = ''' | ||
| 204 | tags: [doc] | ||
| 205 | summary: GCAP提高申请单对应文件优先级 | ||
| 206 | consumes: [application/json] | ||
| 207 | produces: [application/json] | ||
| 208 | parameters: | ||
| 209 | - in: body | ||
| 210 | name: body | ||
| 211 | required: true | ||
| 212 | schema: | ||
| 213 | $ref: "#/definitions/Application" | ||
| 214 | |||
| 215 | responses: | ||
| 216 | 200: | ||
| 217 | description: ok | ||
| 218 | schema: | ||
| 219 | $ref: '#/definitions/ApiResponse' | ||
| 220 | ''' | ||
| 221 | |||
| 198 | 222 | ||
| 199 | class DocView(GenericView, DocHandler): | 223 | class DocView(GenericView, DocHandler): | 
| 200 | 224 | ... | ... | 
| ... | @@ -22,4 +22,5 @@ urlpatterns = [ | ... | @@ -22,4 +22,5 @@ urlpatterns = [ | 
| 22 | path(r'api/create/', include('apps.doc.create_urls')), | 22 | path(r'api/create/', include('apps.doc.create_urls')), | 
| 23 | path(r'api/priority/', include('apps.doc.priority_urls')), | 23 | path(r'api/priority/', include('apps.doc.priority_urls')), | 
| 24 | path(r'api/doc/', include('apps.doc.internal_urls')), | 24 | path(r'api/doc/', include('apps.doc.internal_urls')), | 
| 25 | path('api/oauth/', include('oauth2_provider.urls', namespace='oauth2_provider')), | ||
| 25 | ] | 26 | ] | ... | ... | 
| ... | @@ -12,10 +12,26 @@ tags: | ... | @@ -12,10 +12,26 @@ tags: | 
| 12 | schemes: | 12 | schemes: | 
| 13 | - "https" | 13 | - "https" | 
| 14 | - "http" | 14 | - "http" | 
| 15 | security: | ||
| 16 | - OAuth2: [] | ||
| 15 | ''' | 17 | ''' | 
| 16 | 18 | ||
| 17 | # scheme: bearer | 19 | # scheme: oauth | 
| 18 | security_definitions = ''' | 20 | security_definitions = ''' | 
| 21 | OAuth2: | ||
| 22 | type: oauth2 | ||
| 23 | flow: application | ||
| 24 | description: > | ||
| 25 | This API uses OAuth 2 with the application(clientCredentials) grant flow. | ||
| 26 | |||
| 27 | client_id=sMlciTkppsMzARwHpCVarm5q7DP2Vucj3ny8JFhw | ||
| 28 | |||
| 29 | client_secret=WNoOilDx140ZLcenDKfsnikv7S2LIFs60DciYoqnrZaYLqYsKpcmt7mJIL69o9AEf84uQvRnS3K2UioxfjNyImjR4UOyXbDcF6qYgTLC4KDVByKFdVhKfrn2Lc4q4BNW | ||
| 30 | |||
| 31 | scopes=write | ||
| 32 | tokenUrl: https://staging-bmw-ocr.situdata.com/api/oauth/token/ | ||
| 33 | scopes: | ||
| 34 | write: Grants write access | ||
| 19 | ''' | 35 | ''' | 
| 20 | 36 | ||
| 21 | responses = ''' | 37 | responses = ''' | 
| ... | @@ -99,6 +115,46 @@ Doc: | ... | @@ -99,6 +115,46 @@ Doc: | 
| 99 | type: string | 115 | type: string | 
| 100 | example: '8410480' | 116 | example: '8410480' | 
| 101 | 117 | ||
| 118 | Application: | ||
| 119 | type: object | ||
| 120 | required: [APPLICATION_INFORMATION] | ||
| 121 | properties: | ||
| 122 | APPLICATION_INFORMATION: | ||
| 123 | description: 申请单信息 | ||
| 124 | type: object | ||
| 125 | required: [SUBMIT_DATETIME, STATUS, ENTITY, RATING, APPLICATION_ID, APPLICATION_VERSION, INTERMEDIATE_DECISION] | ||
| 126 | properties: | ||
| 127 | SUBMIT_DATETIME: | ||
| 128 | description: 提交时间 | ||
| 129 | type: string | ||
| 130 | example: 2020-07-08T18:33:31.000+08:00 | ||
| 131 | STATUS: | ||
| 132 | description: 状态 | ||
| 133 | type: integer | ||
| 134 | example: 42 | ||
| 135 | ENTITY: | ||
| 136 | description: 业务类型 | ||
| 137 | type: string | ||
| 138 | example: CO00001 | ||
| 139 | enum: [CO00001, CO00002] | ||
| 140 | RATING: | ||
| 141 | description: 排名 | ||
| 142 | type: integer | ||
| 143 | example: 4 | ||
| 144 | APPLICATION_ID: | ||
| 145 | description: 申请id | ||
| 146 | type: string | ||
| 147 | example: CH-B0011010101 | ||
| 148 | APPLICATION_VERSION: | ||
| 149 | description: 申请版本 | ||
| 150 | type: integer | ||
| 151 | example: 1 | ||
| 152 | INTERMEDIATE_DECISION: | ||
| 153 | description: '' | ||
| 154 | type: string | ||
| 155 | example: MUW | ||
| 156 | |||
| 157 | |||
| 102 | ApiResponse: | 158 | ApiResponse: | 
| 103 | description: 响应对象,code字段用于表示响应的状态; data字段用于存放响应内容 | 159 | description: 响应对象,code字段用于表示响应的状态; data字段用于存放响应内容 | 
| 104 | type: object | 160 | type: object | ... | ... | 
| ... | @@ -4,6 +4,7 @@ from django.core.exceptions import PermissionDenied | ... | @@ -4,6 +4,7 @@ from django.core.exceptions import PermissionDenied | 
| 4 | from django.utils.translation import ugettext_lazy as _ | 4 | from django.utils.translation import ugettext_lazy as _ | 
| 5 | from django.http import Http404 | 5 | from django.http import Http404 | 
| 6 | from rest_framework import exceptions, status | 6 | from rest_framework import exceptions, status | 
| 7 | from rest_framework.exceptions import NotAuthenticated, PermissionDenied | ||
| 7 | from rest_framework.response import Response | 8 | from rest_framework.response import Response | 
| 8 | from marshmallow.exceptions import ValidationError | 9 | from marshmallow.exceptions import ValidationError | 
| 9 | 10 | ||
| ... | @@ -29,7 +30,9 @@ def exception_handler(exc, context): | ... | @@ -29,7 +30,9 @@ def exception_handler(exc, context): | 
| 29 | if getattr(exc, 'wait', None): | 30 | if getattr(exc, 'wait', None): | 
| 30 | headers['Retry-After'] = '%d' % exc.wait | 31 | headers['Retry-After'] = '%d' % exc.wait | 
| 31 | 32 | ||
| 32 | if exc.status_code == 403: | 33 | if isinstance(exc, NotAuthenticated) or isinstance(exc, PermissionDenied): | 
| 34 | data = res_content(MetaStatus.NO_PERMISSION.value, MetaStatus.NO_PERMISSION.verbose_name) | ||
| 35 | elif exc.status_code == 403: | ||
| 33 | data = res_content(MetaStatus.NEED_LOGIN.value, MetaStatus.NEED_LOGIN.verbose_name) | 36 | data = res_content(MetaStatus.NEED_LOGIN.value, MetaStatus.NEED_LOGIN.verbose_name) | 
| 34 | else: | 37 | else: | 
| 35 | data = res_content(MetaStatus.INTERNAL_ERROR.value, exc.detail) | 38 | data = res_content(MetaStatus.INTERNAL_ERROR.value, exc.detail) | ... | ... | 
| ... | @@ -48,7 +48,7 @@ class Command(BaseCommand): | ... | @@ -48,7 +48,7 @@ class Command(BaseCommand): | 
| 48 | view_class = view.view_class | 48 | view_class = view.view_class | 
| 49 | url_path, path_parameters = pattern[0][0] | 49 | url_path, path_parameters = pattern[0][0] | 
| 50 | url_path = unify_url_path_format(url_path) | 50 | url_path = unify_url_path_format(url_path) | 
| 51 | if url_path != '/api/create/v1': | 51 | if url_path not in ['/api/create/v1', '/api/priority/v1']: | 
| 52 | continue | 52 | continue | 
| 53 | url_path_paramters = getattr(view, 'parameters_doc', None) | 53 | url_path_paramters = getattr(view, 'parameters_doc', None) | 
| 54 | if url_path_paramters: | 54 | if url_path_paramters: | 
| ... | @@ -82,7 +82,7 @@ class Command(BaseCommand): | ... | @@ -82,7 +82,7 @@ class Command(BaseCommand): | 
| 82 | api_doc_dct[url_path][method] = doc | 82 | api_doc_dct[url_path][method] = doc | 
| 83 | doc_dct = yaml.load(base_part) | 83 | doc_dct = yaml.load(base_part) | 
| 84 | doc_dct['paths'] = api_doc_dct | 84 | doc_dct['paths'] = api_doc_dct | 
| 85 | # doc_dct['securityDefinitions'] = yaml.load(security_definitions) | 85 | doc_dct['securityDefinitions'] = yaml.load(security_definitions) | 
| 86 | doc_dct['responses'] = yaml.load(responses) | 86 | doc_dct['responses'] = yaml.load(responses) | 
| 87 | doc_dct['definitions'] = yaml.load(definitions) | 87 | doc_dct['definitions'] = yaml.load(definitions) | 
| 88 | 88 | ... | ... | 
| ... | @@ -42,6 +42,7 @@ INSTALLED_APPS = [ | ... | @@ -42,6 +42,7 @@ INSTALLED_APPS = [ | 
| 42 | 'django.contrib.messages', | 42 | 'django.contrib.messages', | 
| 43 | 'django.contrib.staticfiles', | 43 | 'django.contrib.staticfiles', | 
| 44 | # 'corsheaders', | 44 | # 'corsheaders', | 
| 45 | 'oauth2_provider', | ||
| 45 | 'rest_framework', | 46 | 'rest_framework', | 
| 46 | 'common', | 47 | 'common', | 
| 47 | 'apps.account', | 48 | 'apps.account', | 
| ... | @@ -145,6 +146,7 @@ REST_FRAMEWORK = { | ... | @@ -145,6 +146,7 @@ REST_FRAMEWORK = { | 
| 145 | 'DEFAULT_AUTHENTICATION_CLASSES': ( | 146 | 'DEFAULT_AUTHENTICATION_CLASSES': ( | 
| 146 | 'rest_framework.authentication.BasicAuthentication', | 147 | 'rest_framework.authentication.BasicAuthentication', | 
| 147 | 'rest_framework_jwt.authentication.JSONWebTokenAuthentication', | 148 | 'rest_framework_jwt.authentication.JSONWebTokenAuthentication', | 
| 149 | # 'oauth2_provider.contrib.rest_framework.OAuth2Authentication', | ||
| 148 | ), | 150 | ), | 
| 149 | 'EXCEPTION_HANDLER': 'common.exceptions.exception_handler' | 151 | 'EXCEPTION_HANDLER': 'common.exceptions.exception_handler' | 
| 150 | } | 152 | } | 
| ... | @@ -173,3 +175,8 @@ JWT_AUTH = { | ... | @@ -173,3 +175,8 @@ JWT_AUTH = { | 
| 173 | # 跨域设置 | 175 | # 跨域设置 | 
| 174 | # CORS_ORIGIN_ALLOW_ALL = True | 176 | # CORS_ORIGIN_ALLOW_ALL = True | 
| 175 | # CORS_ALLOW_CREDENTIALS = True | 177 | # CORS_ALLOW_CREDENTIALS = True | 
| 178 | |||
| 179 | OAUTH2_PROVIDER = { | ||
| 180 | # this is the list of available scopes | ||
| 181 | 'SCOPES': {'read': 'Read scope', 'write': 'Write scope'} | ||
| 182 | } | ... | ... | 
wsdl/DocumentFinder.wsdl
0 → 100644
This diff could not be displayed because it is too large.
- 
Please register or sign in to post a comment