diff --git a/server/apps/__init__.py b/server/apps/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/server/apps/ability/migrations/0025_qaction_qactionitem_qorg_qtask_quali_qualilib.py b/server/apps/ability/migrations/0025_qaction_qactionitem_qorg_qtask_quali_qualilib.py new file mode 100644 index 0000000..11f175a --- /dev/null +++ b/server/apps/ability/migrations/0025_qaction_qactionitem_qorg_qtask_quali_qualilib.py @@ -0,0 +1,138 @@ +# Generated by Django 3.0.5 on 2022-05-16 02:44 + +from django.conf import settings +import django.contrib.postgres.fields.jsonb +from django.db import migrations, models +import django.db.models.deletion +import django.utils.timezone + + +class Migration(migrations.Migration): + + dependencies = [ + ('system', '0020_auto_20220513_0926'), + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ('ability', '0024_auto_20220316_0858'), + ] + + operations = [ + migrations.CreateModel( + name='QualiLib', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('create_time', models.DateTimeField(default=django.utils.timezone.now, help_text='创建时间', verbose_name='创建时间')), + ('update_time', models.DateTimeField(auto_now=True, help_text='修改时间', verbose_name='修改时间')), + ('is_deleted', models.BooleanField(default=False, help_text='删除标记', verbose_name='删除标记')), + ('name', models.CharField(max_length=20, verbose_name='名称')), + ('levels', django.contrib.postgres.fields.jsonb.JSONField(blank=True, default=list, null=True, verbose_name='等级')), + ('scopes', django.contrib.postgres.fields.jsonb.JSONField(blank=True, default=list, null=True, verbose_name='范围')), + ], + options={ + 'abstract': False, + }, + ), + migrations.CreateModel( + name='Quali', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('create_time', models.DateTimeField(default=django.utils.timezone.now, help_text='创建时间', verbose_name='创建时间')), + ('update_time', models.DateTimeField(auto_now=True, help_text='修改时间', verbose_name='修改时间')), + ('is_deleted', models.BooleanField(default=False, help_text='删除标记', verbose_name='删除标记')), + ('name', models.CharField(max_length=20, verbose_name='资质名称')), + ('type', models.PositiveSmallIntegerField(choices=[('CMA', 'CMA'), ('CNAS', 'CNAS'), ('OTHER', 'OTHER')], verbose_name='资质类型')), + ('grade', models.PositiveSmallIntegerField(verbose_name='等级')), + ('scope', models.TextField(blank=True, null=True, verbose_name='范围')), + ('level', models.CharField(max_length=10, verbose_name='等级')), + ('description', models.TextField(blank=True, null=True, verbose_name='描述')), + ('end_date', models.DateField(blank=True, null=True, verbose_name='截至日期')), + ('city', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='quali_city', to='system.City')), + ('citys', models.ManyToManyField(related_name='quali_citys', to='system.City', verbose_name='备案城市')), + ('create_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='quali_create_by', to=settings.AUTH_USER_MODEL, verbose_name='创建人')), + ('org', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='system.Organization', verbose_name='所属单位')), + ('province', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='system.Province')), + ('qualilib', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='ability.QualiLib', verbose_name='关联资质库')), + ('update_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='quali_update_by', to=settings.AUTH_USER_MODEL, verbose_name='最后编辑人')), + ], + options={ + 'abstract': False, + }, + ), + migrations.CreateModel( + name='QTask', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('create_time', models.DateTimeField(default=django.utils.timezone.now, help_text='创建时间', verbose_name='创建时间')), + ('update_time', models.DateTimeField(auto_now=True, help_text='修改时间', verbose_name='修改时间')), + ('is_deleted', models.BooleanField(default=False, help_text='删除标记', verbose_name='删除标记')), + ('name', models.CharField(max_length=100, verbose_name='名称')), + ('end_date', models.DateField(blank=True, null=True, verbose_name='截止时间')), + ('state', models.CharField(choices=[('待发布', '待发布'), ('进行中', '进行中'), ('已关闭', '已关闭')], default='待发布', max_length=50, verbose_name='任务状态')), + ('belong_dept', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='qtask_belong_dept', to='system.Organization', verbose_name='所属部门')), + ('create_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='qtask_create_by', to=settings.AUTH_USER_MODEL, verbose_name='创建人')), + ('update_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='qtask_update_by', to=settings.AUTH_USER_MODEL, verbose_name='最后编辑人')), + ], + options={ + 'verbose_name': '资质报送任务', + 'verbose_name_plural': '资质报送任务', + }, + ), + migrations.CreateModel( + name='QOrg', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('create_time', models.DateTimeField(default=django.utils.timezone.now, help_text='创建时间', verbose_name='创建时间')), + ('update_time', models.DateTimeField(auto_now=True, help_text='修改时间', verbose_name='修改时间')), + ('is_deleted', models.BooleanField(default=False, help_text='删除标记', verbose_name='删除标记')), + ('count', models.PositiveIntegerField(default=0)), + ('count_confirmed', models.PositiveIntegerField(default=0)), + ('org', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='qorg_org', to='system.Organization', verbose_name='关联公司')), + ('qtask', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='qorg_qtask', to='ability.QTask', verbose_name='关联任务')), + ], + options={ + 'verbose_name': '资质报送任务部门', + 'verbose_name_plural': '资质报送任务部门', + }, + ), + migrations.CreateModel( + name='QActionItem', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('create_time', models.DateTimeField(default=django.utils.timezone.now, help_text='创建时间', verbose_name='创建时间')), + ('update_time', models.DateTimeField(auto_now=True, help_text='修改时间', verbose_name='修改时间')), + ('is_deleted', models.BooleanField(default=False, help_text='删除标记', verbose_name='删除标记')), + ('action', models.PositiveSmallIntegerField(blank=True, choices=[('update', '更新'), ('citys:add', '新增备案城市'), ('citys:remove', '移除备案城市')], null=True, verbose_name='操作类型')), + ('field', models.CharField(max_length=20, verbose_name='变动字段')), + ('value1', django.contrib.postgres.fields.jsonb.JSONField(blank=True, default=dict, null=True, verbose_name='原值')), + ('value2', django.contrib.postgres.fields.jsonb.JSONField(blank=True, default=dict, null=True, verbose_name='新值')), + ('city', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='system.City')), + ], + options={ + 'abstract': False, + }, + ), + migrations.CreateModel( + name='QAction', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('create_time', models.DateTimeField(default=django.utils.timezone.now, help_text='创建时间', verbose_name='创建时间')), + ('update_time', models.DateTimeField(auto_now=True, help_text='修改时间', verbose_name='修改时间')), + ('is_deleted', models.BooleanField(default=False, help_text='删除标记', verbose_name='删除标记')), + ('action', models.CharField(choices=[('service:update', '更新服务'), ('quali:create', '新增资质'), ('quali:update', '更新资质'), ('ablity:create', '新增能力')], max_length=20, verbose_name='操作类型')), + ('num', models.PositiveIntegerField(blank=True, null=True, verbose_name='新增能力数量')), + ('value1', django.contrib.postgres.fields.jsonb.JSONField(blank=True, default=dict, null=True, verbose_name='值1')), + ('value2', django.contrib.postgres.fields.jsonb.JSONField(blank=True, default=dict, null=True, verbose_name='值2')), + ('confirmed', models.BooleanField(default=False, verbose_name='是否确认')), + ('afield', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='quali_afield', to='system.Dict', verbose_name='所属领域')), + ('atype', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='quali_atype', to='system.Dict', verbose_name='能力类型')), + ('belong_dept', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='qaction_belong_dept', to='system.Organization', verbose_name='所属部门')), + ('create_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='qaction_create_by', to=settings.AUTH_USER_MODEL, verbose_name='创建人')), + ('file', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='system.File', verbose_name='能力文件')), + ('qtask', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='ability.QOrg')), + ('quali', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='ability.Quali', verbose_name='操作资质')), + ('update_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='qaction_update_by', to=settings.AUTH_USER_MODEL, verbose_name='最后编辑人')), + ], + options={ + 'abstract': False, + }, + ), + ] diff --git a/server/apps/ability/migrations/0026_qactionitem_qaction.py b/server/apps/ability/migrations/0026_qactionitem_qaction.py new file mode 100644 index 0000000..8b6b963 --- /dev/null +++ b/server/apps/ability/migrations/0026_qactionitem_qaction.py @@ -0,0 +1,19 @@ +# Generated by Django 3.0.5 on 2022-05-16 03:35 + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('ability', '0025_qaction_qactionitem_qorg_qtask_quali_qualilib'), + ] + + operations = [ + migrations.AddField( + model_name='qactionitem', + name='qaction', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='items_qaction', to='ability.QAction', verbose_name='关联操作'), + ), + ] diff --git a/server/apps/ability/migrations/0027_auto_20220519_0811.py b/server/apps/ability/migrations/0027_auto_20220519_0811.py new file mode 100644 index 0000000..2c85af1 --- /dev/null +++ b/server/apps/ability/migrations/0027_auto_20220519_0811.py @@ -0,0 +1,19 @@ +# Generated by Django 3.0.5 on 2022-05-19 00:11 + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('ability', '0026_qactionitem_qaction'), + ] + + operations = [ + migrations.AlterField( + model_name='qaction', + name='qtask', + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='ability.QTask'), + ), + ] diff --git a/server/apps/ability/migrations/0028_auto_20220519_0832.py b/server/apps/ability/migrations/0028_auto_20220519_0832.py new file mode 100644 index 0000000..514530a --- /dev/null +++ b/server/apps/ability/migrations/0028_auto_20220519_0832.py @@ -0,0 +1,28 @@ +# Generated by Django 3.0.5 on 2022-05-19 00:32 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('ability', '0027_auto_20220519_0811'), + ] + + operations = [ + migrations.AlterField( + model_name='quali', + name='grade', + field=models.PositiveSmallIntegerField(blank=True, null=True, verbose_name='等级'), + ), + migrations.AlterField( + model_name='quali', + name='level', + field=models.CharField(blank=True, max_length=10, null=True, verbose_name='等级'), + ), + migrations.AlterField( + model_name='quali', + name='name', + field=models.CharField(blank=True, max_length=20, null=True, verbose_name='资质名称'), + ), + ] diff --git a/server/apps/ability/migrations/0029_auto_20220519_0833.py b/server/apps/ability/migrations/0029_auto_20220519_0833.py new file mode 100644 index 0000000..f5c671a --- /dev/null +++ b/server/apps/ability/migrations/0029_auto_20220519_0833.py @@ -0,0 +1,19 @@ +# Generated by Django 3.0.5 on 2022-05-19 00:33 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('system', '0020_auto_20220513_0926'), + ('ability', '0028_auto_20220519_0832'), + ] + + operations = [ + migrations.AlterField( + model_name='quali', + name='citys', + field=models.ManyToManyField(blank=True, null=True, related_name='quali_citys', to='system.City', verbose_name='备案城市'), + ), + ] diff --git a/server/apps/ability/migrations/0030_auto_20220519_0834.py b/server/apps/ability/migrations/0030_auto_20220519_0834.py new file mode 100644 index 0000000..4ce05ef --- /dev/null +++ b/server/apps/ability/migrations/0030_auto_20220519_0834.py @@ -0,0 +1,19 @@ +# Generated by Django 3.0.5 on 2022-05-19 00:34 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('system', '0020_auto_20220513_0926'), + ('ability', '0029_auto_20220519_0833'), + ] + + operations = [ + migrations.AlterField( + model_name='quali', + name='citys', + field=models.ManyToManyField(blank=True, related_name='quali_citys', to='system.City', verbose_name='备案城市'), + ), + ] diff --git a/server/apps/ability/migrations/0031_auto_20220519_0903.py b/server/apps/ability/migrations/0031_auto_20220519_0903.py new file mode 100644 index 0000000..1827238 --- /dev/null +++ b/server/apps/ability/migrations/0031_auto_20220519_0903.py @@ -0,0 +1,28 @@ +# Generated by Django 3.0.5 on 2022-05-19 01:03 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('ability', '0030_auto_20220519_0834'), + ] + + operations = [ + migrations.AlterField( + model_name='quali', + name='grade', + field=models.PositiveSmallIntegerField(blank=True, null=True, verbose_name='等级1'), + ), + migrations.AlterField( + model_name='quali', + name='level', + field=models.CharField(blank=True, max_length=10, null=True, verbose_name='等级2'), + ), + migrations.AlterField( + model_name='quali', + name='type', + field=models.CharField(choices=[('CMA', 'CMA'), ('CNAS', 'CNAS'), ('OTHER', 'OTHER')], max_length=10, verbose_name='资质类型'), + ), + ] diff --git a/server/apps/ability/migrations/0032_auto_20220519_0924.py b/server/apps/ability/migrations/0032_auto_20220519_0924.py new file mode 100644 index 0000000..968757a --- /dev/null +++ b/server/apps/ability/migrations/0032_auto_20220519_0924.py @@ -0,0 +1,19 @@ +# Generated by Django 3.0.5 on 2022-05-19 01:24 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('ability', '0031_auto_20220519_0903'), + ] + + operations = [ + migrations.AlterField( + model_name='qactionitem', + name='action', + field=models.CharField(choices=[('update', '更新'), ('citys:add', '新增备案城市'), ('citys:remove', '移除备案城市')], default='update', max_length=20, verbose_name='操作类型'), + preserve_default=False, + ), + ] diff --git a/server/apps/ability/models.py b/server/apps/ability/models.py index e0c2f87..fce4ce5 100644 --- a/server/apps/ability/models.py +++ b/server/apps/ability/models.py @@ -1,8 +1,8 @@ -from datetime import MAXYEAR + +from apps.system.models import City, Dict, Province from django.db import models -from django.db.models.fields import related from utils.model import BaseModel -from apps.system.models import Organization, User +from apps.system.models import CommonAModel, CommonBModel, File, Organization, User # Create your models here. from django.contrib.postgres.fields import JSONField @@ -121,3 +121,108 @@ class Qualificationother(BaseModel): qualification = models.ForeignKey(Qualification, on_delete=models.CASCADE, related_name='other_qualification') name = models.TextField('其他资质', null=True, blank=True) description = models.TextField('资质范围', null=True, blank=True) + +class QualiLib(BaseModel): + """ + 资质库 + """ + name = models.CharField('名称', max_length=20) + levels = JSONField('等级', default=list, null=True, blank=True) + scopes = JSONField('范围', default=list, null=True, blank=True) + + +class Quali(CommonAModel): + """ + 资质 + """ + QUALI_TYPE_CHOICES=( + ('CMA', 'CMA'), + ('CNAS', 'CNAS'), + ('OTHER', 'OTHER') + ) + QUALI_GRADE_CHOICES = ( + (10, '国家级'), + (20, '省级'), + (30, '市级') + ) + org = models.ForeignKey(Organization, on_delete=models.CASCADE, verbose_name='所属单位') + name = models.CharField('资质名称', max_length=20, null=True, blank=True) + type = models.CharField('资质类型', choices=QUALI_TYPE_CHOICES, max_length=10) + grade = models.PositiveSmallIntegerField('等级1', null=True, blank=True) + scope = models.TextField('范围', null=True, blank=True) + level = models.CharField('等级2', max_length=10, null=True, blank=True) + province = models.ForeignKey(Province, on_delete=models.SET_NULL, null=True, blank=True) + city = models.ForeignKey(City, on_delete=models.SET_NULL, null=True, blank=True, related_name='quali_city') + citys = models.ManyToManyField(City, verbose_name='备案城市', related_name='quali_citys', blank=True) + description = models.TextField('描述', null=True, blank=True) + qualilib = models.ForeignKey(QualiLib, verbose_name='关联资质库', + null=True, blank=True, on_delete=models.SET_NULL) + end_date = models.DateField('截至日期', null=True, blank=True) + + +class QTask(CommonBModel): + """ + 资质报送任务 + """ + state_choices = ( + ('待发布', '待发布'), + ('进行中', '进行中'), + ('已关闭', '已关闭'), + ) + name = models.CharField('名称', max_length=100) + end_date = models.DateField('截止时间', null=True, blank=True) + state = models.CharField('任务状态', max_length=50, choices=state_choices, default='待发布') + class Meta: + verbose_name = '资质报送任务' + verbose_name_plural = verbose_name + + +class QOrg(BaseModel): + qtask = models.ForeignKey(QTask, verbose_name='关联任务', on_delete=models.CASCADE, related_name='qorg_qtask') + org = models.ForeignKey(Organization, verbose_name='关联公司', on_delete=models.CASCADE, related_name='qorg_org') + count = models.PositiveIntegerField(default=0) + count_confirmed = models.PositiveIntegerField(default=0) + class Meta: + verbose_name = '资质报送任务部门' + verbose_name_plural = verbose_name + + +class QAction(CommonBModel): + """ + 任务操作 + """ + QACTION_CHOICE = ( + ('service:update', '更新服务'), + ('quali:create', '新增资质'), + ('quali:update', '更新资质'), + ('ablity:create', '新增能力'), + ) + action = models.CharField('操作类型', max_length=20, choices=QACTION_CHOICE) + quali = models.ForeignKey(Quali, null=True, blank=True, verbose_name='操作资质', on_delete=models.CASCADE) + file = models.ForeignKey(File, null=True, blank=True, verbose_name='能力文件', on_delete=models.CASCADE) + atype = models.ForeignKey(Dict, null=True, blank=True, verbose_name='能力类型', + on_delete=models.CASCADE, related_name='quali_atype') + afield = models.ForeignKey(Dict, null=True, blank=True, verbose_name='所属领域', + on_delete=models.CASCADE, related_name='quali_afield') + num = models.PositiveIntegerField('新增能力数量', null=True, blank=True) + qtask = models.ForeignKey(QTask, on_delete=models.CASCADE) + value1 = JSONField('值1', null=True, blank=True, default=dict) + value2 = JSONField('值2', null=True, blank=True, default=dict) + confirmed = models.BooleanField('是否确认',default=False) + + +class QActionItem(BaseModel): + QACTIONITEM_CHOICE = ( + ('update', '更新'), + ('citys:add', '新增备案城市'), + ('citys:remove', '移除备案城市'), + ) + action = models.CharField('操作类型', max_length=20, choices=QACTIONITEM_CHOICE) + field = models.CharField('变动字段', max_length=20) + value1 = JSONField('原值', null=True, blank=True, default=dict) + value2 = JSONField('新值', null=True, blank=True, default=dict) + city = models.ForeignKey(City, on_delete=models.SET_NULL, null=True, blank=True) + qaction = models.ForeignKey(QAction, verbose_name='关联操作', + on_delete=models.CASCADE, related_name='items_qaction', null=True, blank=True) + + diff --git a/server/apps/ability/serializers.py b/server/apps/ability/serializers.py index 7e7f2b5..7fb5cae 100644 --- a/server/apps/ability/serializers.py +++ b/server/apps/ability/serializers.py @@ -80,4 +80,5 @@ class CorrectSerializer(serializers.ModelSerializer): def setup_eager_loading(queryset): """ Perform necessary eager loading of data. """ queryset = queryset.select_related('ssbm') - return queryset \ No newline at end of file + return queryset + diff --git a/server/apps/ability/serializers_qtask.py b/server/apps/ability/serializers_qtask.py new file mode 100644 index 0000000..f574e72 --- /dev/null +++ b/server/apps/ability/serializers_qtask.py @@ -0,0 +1,157 @@ +from rest_framework import serializers + +from apps.system.models import City, Organization +from .models import QAction, QActionItem, QOrg, QTask, Quali, QualiLib +from django.db import transaction +from apps.system.serializers import OrganizationSimpleSerializer, DictSerializer +from rest_framework.exceptions import ParseError + + +class QualiLibListSerializer(serializers.ModelSerializer): + class Meta: + model = QualiLib + fields = '__all__' + +class QualiListSerializer(serializers.ModelSerializer): + province_name = serializers.CharField(source='province.name', read_only=True) + city_name = serializers.CharField(source='city.name', read_only=True) + service = serializers.CharField(source='org.service', read_only=True) + class Meta: + model = Quali + fields = '__all__' + + +class QTaskCreateUpdateSerializer(serializers.ModelSerializer): + orgs = serializers.PrimaryKeyRelatedField(label='上报公司ID列表', + queryset = Organization.objects.all(), many=True, write_only=True) + class Meta: + model = QTask + fields = ['name', 'end_date', 'orgs'] + + def create(self, validated_data): + with transaction.atomic(): + orgs = validated_data.pop('orgs') + validated_data['state'] = '待发布' + instance = super().create(validated_data) + for i in orgs: + QOrg.objects.get_or_create(qtask=instance, org=i, + defaults={'qtask': instance, 'org': i}) + return instance + + def update(self, instance, validated_data): + with transaction.atomic(): + if instance.state == '已关闭': + raise ParseError('任务已关闭,不可更改') + orgs = validated_data.pop('orgs') + instance = super().update(instance, validated_data) + for i in orgs: + QOrg.objects.get_or_create(qtask=instance, org=i, + defaults={'qtask': instance, 'org': i}) + return instance + + +class QTaskListSerializer(serializers.ModelSerializer): + orgs_count = serializers.SerializerMethodField() + + class Meta: + model = QTask + fields = '__all__' + + def get_orgs_count(self, obj): + count = QOrg.objects.filter(qtask=obj).count() + return count + +class QTaskSimpleSerializer(serializers.ModelSerializer): + class Meta: + model = QTask + fields = '__all__' + +class QOrgListSerializer(serializers.ModelSerializer): + org_ = OrganizationSimpleSerializer(source='org', read_only=True) + qtask_ = QTaskSimpleSerializer(source='qtask', read_only=True) + class Meta: + model = QOrg + fields = '__all__' + + +class QActionListSerializer(serializers.ModelSerializer): + quali_name = serializers.CharField(source='quali.name', read_only=True) + atype_name = serializers.CharField(source='atype.name', read_only=True) + afield_name = serializers.CharField(source='afield.name', read_only=True) + class Meta: + model = QAction + fields = '__all__' + + +class QActionServiceSerializer(serializers.ModelSerializer): + class Meta: + model = QAction + fields = ['qtask', 'value2'] + + def create(self, validated_data): + validated_data['action'] = 'service:update' + return super().create(validated_data) + +class QualiCreateSerializer(serializers.ModelSerializer): + citys = serializers.ListField(child=serializers.IntegerField(), label='城市ID列表') + class Meta: + model = Quali + fields = ['name', 'type', 'grade', 'scope', 'level', 'province', 'city', 'description', 'citys'] + + +class QualiUpdateSerializer(serializers.ModelSerializer): + citys = serializers.ListField(child=serializers.IntegerField(), label='城市ID列表') + id = serializers.IntegerField(label='修改资质的ID') + class Meta: + model = Quali + fields = ['scope', 'level', 'description', 'id', 'citys'] + +class QualiSerializer(serializers.ModelSerializer): + class Meta: + model = Quali + fields = '__all__' + +class QActionQualiCreateSerializer(serializers.ModelSerializer): + value2 = QualiCreateSerializer() + class Meta: + model = QAction + fields = ['qtask', 'value2'] + + def create(self, validated_data): + validated_data['action'] = 'quali:create' + if validated_data['value2']['type'] in ['CMA', 'CNAS']: + validated_data['value2']['name'] = validated_data['value2']['type'] + return super().create(validated_data) + +class QActionQualiUpdateSerializer(serializers.ModelSerializer): + value2 = QualiUpdateSerializer() + class Meta: + model = QAction + fields = ['qtask', 'value2'] + + def create(self, validated_data): + validated_data['action'] = 'quali:update' + return super().create(validated_data) + +class QActionACreateSerializer(serializers.ModelSerializer): + class Meta: + model = QAction + fields = ['atype', 'afield', 'file', 'num', 'qtask'] + extra_kwargs = {'atype': {'required': True}, 'afield': {'required': True}, 'file': {'required': True}} + + def create(self, validated_data): + validated_data['action'] = 'ablity:create' + return super().create(validated_data) + + +class QActionItemSerializer(serializers.ModelSerializer): + class Meta: + model = QActionItem + fields = ['action', 'field', 'value1', 'value2', 'city'] + + +class QActionDetailSerializer(serializers.ModelSerializer): + update_detail = QActionItemSerializer(source='items_qaction', many=True, read_only=True) + class Meta: + model = QAction + fields ='__all__' \ No newline at end of file diff --git a/server/apps/ability/urls.py b/server/apps/ability/urls.py index 4786208..0683c7c 100644 --- a/server/apps/ability/urls.py +++ b/server/apps/ability/urls.py @@ -1,6 +1,8 @@ from django.db.models import base from django.urls import path, include from rest_framework import routers + +from apps.ability.views_qtask import QActionViewSet, QOrgViewSet, QTaskViewSet, QualiLibViewSet, QualiViewSet from .views import AbilityContentViewSet, AbilityRecordViewSet, CMAViewSet, CNASViewSet, CorrectViewSet, QualificationViewSet,InspectionViewSet,QualificationotherViewSet, QueryRecordListViewSet, correct_ability, correct_cma, merge_cma, merge_cnas router = routers.DefaultRouter() @@ -13,6 +15,11 @@ router.register('queryrecord', QueryRecordListViewSet, basename="queryrecord") router.register('correct', CorrectViewSet, basename="correct") router.register('content', AbilityContentViewSet, basename="abilitycontent") router.register('record', AbilityRecordViewSet, basename="abilityrecord") +router.register('qualilib', QualiLibViewSet), +router.register('quali', QualiViewSet), +router.register('qorg', QOrgViewSet), +router.register('qtask', QTaskViewSet), +router.register('qaction', QActionViewSet) urlpatterns = [ path('merge/cma/', merge_cma), path('merge/cnas/', merge_cnas), diff --git a/server/apps/ability/views.py b/server/apps/ability/views.py index 0803456..ce3ec75 100644 --- a/server/apps/ability/views.py +++ b/server/apps/ability/views.py @@ -21,6 +21,8 @@ from apps.system.mixins import CreateUpdateCustomMixin from utils.queryset import get_child_queryset2 from django.utils import timezone from apps.supervision.permission import RecordPermission +from django.utils.decorators import method_decorator +from django.views.decorators.cache import cache_page # Create your views here. import json @@ -343,6 +345,11 @@ class QualificationotherViewSet(RecordMixin, PageOrNot,ModelViewSet): filterset_fields = ['qualification__ssbm__name'] ordering_fields = ['qualification__ssbm__name'] ordering = ['create_time'] + + @method_decorator(cache_page(60*60*2)) + def list(self, request, *args, **kwargs): + return super().list(request, *args, **kwargs) + @action(methods=['post'], detail=False, url_path='deletes', url_name='qualificationother_deletes', perms_map = {'post':'qualificationother_deletes'}) def deletes(self, request): diff --git a/server/apps/ability/views_qtask.py b/server/apps/ability/views_qtask.py new file mode 100644 index 0000000..63d7e9b --- /dev/null +++ b/server/apps/ability/views_qtask.py @@ -0,0 +1,253 @@ +from rest_framework.viewsets import GenericViewSet +from rest_framework.mixins import ListModelMixin, CreateModelMixin, UpdateModelMixin, DestroyModelMixin, RetrieveModelMixin +from rest_framework.decorators import action +from apps.ability.models import QAction, QActionItem, QOrg, QTask, Quali, QualiLib +from apps.ability.serializers_qtask import QActionACreateSerializer, QActionDetailSerializer, QActionListSerializer, QActionQualiCreateSerializer, QActionQualiUpdateSerializer, QActionServiceSerializer, QOrgListSerializer, QTaskCreateUpdateSerializer, QTaskListSerializer, QualiCreateSerializer, QualiLibListSerializer, QualiListSerializer, QualiSerializer, QualiUpdateSerializer +from django.db import transaction +from rest_framework.response import Response +from rest_framework import status +from apps.system.mixins import CreateUpdateCustomMixin +from apps.system.models import City +from utils.pagination import PageOrNot +from rest_framework.exceptions import ParseError +from rest_framework import serializers +from rest_framework.exceptions import ParseError + +class QualiLibViewSet(PageOrNot, ListModelMixin, GenericViewSet): + perms_map = {'get': '*'} + queryset = QualiLib.objects.all() + serializer_class = QualiLibListSerializer + search_fields = ['name'] + ordering = ['-create_time'] + +class QualiViewSet(ListModelMixin, GenericViewSet): + perms_map = {'get': '*'} + queryset = Quali.objects.all() + serializer_class = QualiListSerializer + search_fields = ['name', 'type', 'grade'] + ordering = ['org__sort'] + + @action(methods=['get'], detail=False, perms_map = {'get':'*'}) + def my(self, request, *args, **kwargs): + """ + 我的资质 + """ + user = self.request.user + queryset = self.filter_queryset(self.get_queryset().filter(org=user.dept)) + + page = self.paginate_queryset(queryset) + if page is not None: + serializer = self.get_serializer(page, many=True) + return self.get_paginated_response(serializer.data) + + serializer = self.get_serializer(queryset, many=True) + return Response(serializer.data) + +class QTaskViewSet(CreateUpdateCustomMixin, CreateModelMixin, ListModelMixin, UpdateModelMixin, GenericViewSet): + perms_map = {'get': 'qtask_view', 'post': 'qtask_create', 'put': 'qtask_update'} + queryset = QTask.objects.all() + serializer_class = QTaskListSerializer + ordering = ['-create_time'] + + def get_serializer_class(self): + if self.action in ['create', 'update']: + return QTaskCreateUpdateSerializer + return super().get_serializer_class() + + @action(methods=['put'], detail=True, perms_map = {'put':'qtask_start'}, serializer_class=serializers.Serializer) + @transaction.atomic + def start(self, request, *args, **kwargs): + """ + 发布任务 + """ + obj = self.get_object() + if obj.state == '待发布': + obj.state = '进行中' + obj.save() + return Response() + return Response('任务状态错误', status=status.HTTP_400_BAD_REQUEST) + +class QOrgViewSet(ListModelMixin, GenericViewSet): + perms_map = {'get': 'qtask_view'} + queryset = QOrg.objects.select_related('qtask', 'org') + filterset_fields = ['qtask', 'org', 'qtask__state'] + serializer_class = QOrgListSerializer + ordering = ['-create_time'] + + @action(methods=['get'], detail=False, perms_map = {'get':'qtask_my'}) + def my(self, request, *args, **kwargs): + """ + 我的报送任务 + """ + user = self.request.user + queryset = self.filter_queryset(self.get_queryset().filter(org=user.dept).exclude(qtask__state='待发布')) + + page = self.paginate_queryset(queryset) + if page is not None: + serializer = self.get_serializer(page, many=True) + return self.get_paginated_response(serializer.data) + + serializer = self.get_serializer(queryset, many=True) + return Response(serializer.data) + +def cal_count(qtask, org): + qs = QAction.objects.filter(qtask=qtask, belong_dept=org) + qorg = QOrg.objects.get(qtask=qtask, org=org) + qorg.count = qs.count() + qorg.count_confirmed = qs.filter(confirmed=True).count() + qorg.save() + +class QActionViewSet(PageOrNot, ListModelMixin, DestroyModelMixin, RetrieveModelMixin,GenericViewSet): + perms_map = {'get': 'qtask_view'} + queryset = QAction.objects.select_related('file', 'atype', 'afield', 'qtask', 'belong_dept') + filterset_fields = ['qtask', 'belong_dept', 'atype', 'afield'] + serializer_class = QActionListSerializer + + def get_serializer_class(self): + if self.action == 'list': + return QActionListSerializer + elif self.action == 'retrieve': + return QActionDetailSerializer + return super().get_serializer_class() + + @action(methods=['get'], detail=False, perms_map = {'get':'qaction_my'}) + def my(self, request, *args, **kwargs): + """ + 我的报送操作 + """ + user = self.request.user + queryset = self.filter_queryset(self.get_queryset().filter(belong_dept=user.dept)) + + page = self.paginate_queryset(queryset) + if page is not None: + serializer = self.get_serializer(page, many=True) + return self.get_paginated_response(serializer.data) + + serializer = self.get_serializer(queryset, many=True) + return Response(serializer.data) + + def perform_destroy(self, instance): + if not instance.confirmed: + instance.delete(soft=False) + raise ParseError('报送已确认, 不可删除') + + @action(methods=['post'], detail=False, + perms_map = {'post':'qaction_create'}, serializer_class=QActionServiceSerializer) + @transaction.atomic + def service_update(self, request, *args, **kwargs): + """ + 更新提供服务 + """ + user = request.user + serializer = self.get_serializer(data=request.data) + serializer.is_valid(raise_exception=True) + serializer.save(create_by=user, belong_dept=user.dept) + vdata = serializer.validated_data + cal_count(vdata['qtask'], user.dept) + return Response() + + @action(methods=['post'], detail=False, + perms_map = {'post':'qaction_create'}, serializer_class=QActionQualiCreateSerializer) + @transaction.atomic + def quali_create(self, request, *args, **kwargs): + """ + 新增资质 + """ + user = request.user + serializer = self.get_serializer(data=request.data) + serializer.is_valid(raise_exception=True) + serializer.save(create_by=user, belong_dept=user.dept) + vdata = serializer.validated_data + cal_count(vdata['qtask'], user.dept) + return Response() + + @action(methods=['post'], detail=False, + perms_map = {'post':'qaction_update'}, serializer_class=QActionQualiUpdateSerializer) + @transaction.atomic + def quali_update(self, request, *args, **kwargs): + """ + 修改资质 + """ + user = request.user + serializer = self.get_serializer(data=request.data) + serializer.is_valid(raise_exception=True) + obj = serializer.save(create_by=user, belong_dept=user.dept) + vdata = serializer.validated_data + # 比较差别 + quali = Quali.objects.get(id=obj.value2.get('id')) + old_data = QualiSerializer(instance=quali).data + obj.value1 = old_data + for k, v in obj.value2.items(): + if v != old_data[k]: + QActionItem.objects.create(action='update', field=k, value1=old_data[k], value2=v, qaction=obj) + if k == 'citys': + old_citys = set(old_data['citys']) + new_citys = set(v) + removes = old_citys.difference(new_citys) + adds = new_citys.difference(old_citys) + for i in removes: + QActionItem.objects.create(action='city:remove', field='citys', city=City.objects.get(id=i), qaction=obj) + for i in adds: + QActionItem.objects.create(action='city:add', field='citys', city=City.objects.get(id=i), qaction=obj) + + cal_count(vdata['qtask'], user.dept) + return Response() + + @action(methods=['post'], detail=False, + perms_map = {'post':'ability_create'}, serializer_class=QActionACreateSerializer) + @transaction.atomic + def ability_create(self, request, *args, **kwargs): + """ + 新增能力 + """ + user = request.user + serializer = self.get_serializer(data=request.data) + serializer.is_valid(raise_exception=True) + serializer.save(create_by=user, belong_dept=user.dept) + vdata = serializer.validated_data + cal_count(vdata['qtask'], user.dept) + return Response() + + @action(methods=['put'], detail=True, perms_map = {'put':'qaction_confirm'}, + serializer_class=serializers.Serializer) + @transaction.atomic + def confirm(self, request, *args, **kwargs): + """ + 确认 + """ + obj = self.get_object() + if obj.confirmed: + raise ParseError('该动作已确认') + if obj.action == 'service:update': + org = obj.belong_dept + org.service = obj.value2 + org.save() + elif obj.action == 'quali:create': + serializer = QualiCreateSerializer(data=obj.value2) + serializer.is_valid(raise_exception=True) + instance = serializer.save(org=obj.belong_dept, create_by=obj.create_by) + if instance.type == 'OTHER': + qualiLib, _ = QualiLib.objects.get_or_create(name=instance.name) + levels = qualiLib.levels + levels.append(instance.level) + le = list(set(levels)) + qualiLib.levels = le + qualiLib.save() + instance.qualilib = qualiLib + instance.save() + elif obj.action == 'quali:update': + quali = Quali.objects.get(id=obj.value2.get('id')) + s = QualiUpdateSerializer(instance=quali, data=obj.value2) + s.is_valid(raise_exception=True) + s.save(update_by=obj.create_by) + elif obj.action == 'ability:create': + pass + obj.confirmed = True + obj.save() + cal_count(obj.qtask, obj.belong_dept) + return Response(status=status.HTTP_200_OK) + + + + + \ No newline at end of file diff --git a/server/apps/system/migrations/0019_auto_20220513_0905.py b/server/apps/system/migrations/0019_auto_20220513_0905.py new file mode 100644 index 0000000..69d4133 --- /dev/null +++ b/server/apps/system/migrations/0019_auto_20220513_0905.py @@ -0,0 +1,34 @@ +# Generated by Django 3.0.5 on 2022-05-13 01:05 + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('system', '0018_auto_20210430_1156'), + ] + + operations = [ + migrations.CreateModel( + name='Province', + fields=[ + ('id', models.PositiveSmallIntegerField(primary_key=True, serialize=False, verbose_name='id')), + ('name', models.CharField(max_length=20)), + ], + ), + migrations.AddField( + model_name='organization', + name='service', + field=models.TextField(blank=True, null=True, verbose_name='提供服务'), + ), + migrations.CreateModel( + name='City', + fields=[ + ('id', models.PositiveSmallIntegerField(primary_key=True, serialize=False, verbose_name='id')), + ('name', models.CharField(max_length=20)), + ('parent', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='system.Province')), + ], + ), + ] diff --git a/server/apps/system/migrations/0020_auto_20220513_0926.py b/server/apps/system/migrations/0020_auto_20220513_0926.py new file mode 100644 index 0000000..82d7e2c --- /dev/null +++ b/server/apps/system/migrations/0020_auto_20220513_0926.py @@ -0,0 +1,23 @@ +# Generated by Django 3.0.5 on 2022-05-13 01:26 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('system', '0019_auto_20220513_0905'), + ] + + operations = [ + migrations.AlterField( + model_name='city', + name='id', + field=models.PositiveIntegerField(primary_key=True, serialize=False, verbose_name='id'), + ), + migrations.AlterField( + model_name='province', + name='id', + field=models.PositiveIntegerField(primary_key=True, serialize=False, verbose_name='id'), + ), + ] diff --git a/server/apps/system/models.py b/server/apps/system/models.py index 5713fe8..42cf25f 100644 --- a/server/apps/system/models.py +++ b/server/apps/system/models.py @@ -6,7 +6,14 @@ from django.db.models.query import QuerySet from utils.model import SoftModel, BaseModel from simple_history.models import HistoricalRecords +class Province(models.Model): + id = models.PositiveIntegerField('id', primary_key=True) + name = models.CharField(max_length=20) +class City(models.Model): + id = models.PositiveIntegerField('id', primary_key=True) + name = models.CharField(max_length=20) + parent = models.ForeignKey(Province, on_delete=models.CASCADE) class Position(BaseModel): """ @@ -61,6 +68,7 @@ class Organization(SoftModel): on_delete=models.SET_NULL, verbose_name='父') sort = models.CharField('排序', null=True, blank=True, max_length=100) can_supervision = models.BooleanField('是否可监督', default=False) + service = models.TextField('提供服务', null=True, blank=True) class Meta: verbose_name = '组织架构' verbose_name_plural = verbose_name diff --git a/server/apps/system/serializers.py b/server/apps/system/serializers.py index 888c9ae..b5170cb 100644 --- a/server/apps/system/serializers.py +++ b/server/apps/system/serializers.py @@ -2,7 +2,7 @@ import re from rest_framework import serializers -from .models import Organization, Permission, Role, User, Position, DictType, Dict, File +from .models import City, Organization, Permission, Province, Role, User, Position, DictType, Dict, File class FileSerializer(serializers.ModelSerializer): @@ -152,4 +152,16 @@ class OrganizationSimpleSerializer(serializers.ModelSerializer): class FileSimpleSerializer(serializers.ModelSerializer): class Meta: model = File - fields = ['id', 'name', 'path', 'file'] \ No newline at end of file + fields = ['id', 'name', 'path', 'file'] + + +class ProvinceSerializer(serializers.ModelSerializer): + class Meta: + model = Province + fields = '__all__' + + +class CitySerializer(serializers.ModelSerializer): + class Meta: + model = City + fields = '__all__' \ No newline at end of file diff --git a/server/apps/system/urls.py b/server/apps/system/urls.py index 225b722..44fd8b0 100644 --- a/server/apps/system/urls.py +++ b/server/apps/system/urls.py @@ -1,5 +1,6 @@ from django.urls import path, include -from .views import UserViewSet, OrganizationViewSet, PermissionViewSet, RoleViewSet, PositionViewSet, TestView, DictTypeViewSet, DictViewSet, sendMsg + +from .views import CityViewSet, ProviceViewSet, UserViewSet, OrganizationViewSet, PermissionViewSet, RoleViewSet, PositionViewSet, TestView, DictTypeViewSet, DictViewSet, sendMsg from rest_framework import routers @@ -11,6 +12,8 @@ router.register('role', RoleViewSet, basename="role") router.register('position', PositionViewSet, basename="position") router.register('dicttype', DictTypeViewSet, basename="dicttype") router.register('dict', DictViewSet, basename="dict") +router.register('province', ProviceViewSet, basename="province") +router.register('city', CityViewSet, basename="city") urlpatterns = [ path('', include(router.urls)), path('sendmsg/', sendMsg.as_view()), diff --git a/server/apps/system/views.py b/server/apps/system/views.py index a0b353d..8eabccd 100644 --- a/server/apps/system/views.py +++ b/server/apps/system/views.py @@ -27,13 +27,13 @@ from utils.pagination import PageOrNot from utils.queryset import get_child_queryset2 from .filters import UserFilter -from .models import (Dict, DictType, File, Message, Organization, Permission, - Position, Role, User, UserThird) +from .models import (City, Dict, DictType, File, Message, Organization, Permission, + Position, Province, Role, User, UserThird) from .permission import RbacPermission, get_permission_list from .permission_data import RbacFilterSet -from .serializers import (DictSerializer, DictTypeSerializer, FileSerializer, +from .serializers import (CitySerializer, DictSerializer, DictTypeSerializer, FileSerializer, OrganizationSerializer, PermissionSerializer, - PositionSerializer, RoleSerializer, + PositionSerializer, ProvinceSerializer, RoleSerializer, UserCreateSerializer, UserListSerializer, UserModifySerializer) import requests @@ -385,9 +385,19 @@ class WXMPlogin(APIView): +class ProviceViewSet(PageOrNot, ListModelMixin, GenericViewSet): + queryset = Province.objects.all() + serializer_class = ProvinceSerializer + ordering = 'id' +class CityViewSet(PageOrNot, ListModelMixin, GenericViewSet): + queryset = City.objects.all() + serializer_class = CitySerializer + ordeing = 'id' + + class FileViewSet(ModelViewSet): """ 文件:增删改查 diff --git a/server/apps/vod/views.py b/server/apps/vod/views.py index 706f324..ee11e4c 100644 --- a/server/apps/vod/views.py +++ b/server/apps/vod/views.py @@ -116,9 +116,9 @@ class MyViewRecordAPIView(APIView): return Response('视频不存在', status=HTTP_400_BAD_REQUEST) record = ViewRecord.objects.filter(video=video, user=request.user).first() - fcreated = False + fcreated = True if record: - fcreated = True + fcreated = False else: record = ViewRecord.objects.create(video=video, user=request.user) diff --git a/server/server/settings.py b/server/server/settings.py index 8ef3c8a..8d83b08 100644 --- a/server/server/settings.py +++ b/server/server/settings.py @@ -38,6 +38,7 @@ INSTALLED_APPS = [ 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', + 'drf_yasg', 'rest_framework', 'corsheaders', "django_filters", @@ -67,7 +68,7 @@ ROOT_URLCONF = 'server.urls' TEMPLATES = [ { 'BACKEND': 'django.template.backends.django.DjangoTemplates', - 'DIRS': ['dist'], + 'DIRS': ['vuedist'], 'APP_DIRS': True, 'OPTIONS': { 'context_processors': [ @@ -129,10 +130,19 @@ CORS_ORIGIN_ALLOW_ALL = True STATIC_URL = '/static/' STATIC_ROOT = os.path.join(BASE_DIR, 'static') +STATICFILES_DIRS = ( + os.path.join(BASE_DIR, 'vuedist/static'), +) MEDIA_URL = '/media/' MEDIA_ROOT = os.path.join(BASE_DIR, 'media') +# swagger配置 +SWAGGER_SETTINGS = { + 'LOGIN_URL':'/api/admin/login/', + 'LOGOUT_URL':'/api/admin/logout/' +} + # restframework配置 REST_FRAMEWORK = { 'DEFAULT_AUTHENTICATION_CLASSES': [ diff --git a/server/server/settings_dev.py b/server/server/settings_dev.py index 1aa5ba8..1e913d9 100644 --- a/server/server/settings_dev.py +++ b/server/server/settings_dev.py @@ -1,20 +1,21 @@ from .settings import * DEBUG = True DATABASES = { - # 'default': { - # 'ENGINE': 'django.db.backends.postgresql', - # 'NAME': 'cma', - # 'USER': 'postgres', - # 'PASSWORD': 'zctest1234', - # 'HOST': '47.95.0.242', - # 'PORT': '5432', - # } - 'default': { - 'ENGINE': 'django.db.backends.postgresql', - 'NAME': 'cma', - 'USER': 'cma', - 'PASSWORD': 'cma123', - 'HOST': '172.16.80.102', - 'PORT': '5432', - } + 'default': { + 'ENGINE': 'django.db.backends.postgresql', + 'NAME': 'cma', + 'USER': 'postgres', + 'PASSWORD': 'zctest1234', + 'HOST': '47.95.0.242', + 'PORT': '5432', + } +# 'default': { +# 'ENGINE': 'django.db.backends.postgresql', +# 'NAME': 'cma', +# 'USER': 'cma', +# 'PASSWORD': 'cma123', +# # 'HOST': '172.16.80.102', +# 'HOST': '1.203.161.102', +# 'PORT': '5432', +# } } diff --git a/server/server/urls.py b/server/server/urls.py index 3140f0b..7a4d726 100644 --- a/server/server/urls.py +++ b/server/server/urls.py @@ -31,11 +31,26 @@ from django.conf.urls import url from rest_framework_simplejwt.serializers import TokenObtainPairSerializer from rest_framework_simplejwt.views import TokenViewBase from apps.system.views import WXMPlogin,mediaauth +from drf_yasg import openapi +from drf_yasg.views import get_schema_view +import os +schema_dict = dict( + info=openapi.Info( + title="CMA API", + default_version='v1', + contact=openapi.Contact(email="caoqianming@foxmail.com"), + license=openapi.License(name="MIT License"), + ), + public=True, + permission_classes=[],) +if os.getenv('DJANGO_SETTINGS_MODULE') != 'server.settings_dev': + schema_dict['url'] = "https://testsearch.ctc.ac.cn/" + +schema_view = get_schema_view(**schema_dict) urlpatterns = [ - path('', TemplateView.as_view(template_name="index.html")), path('api/admin/', admin.site.urls), path('api/mediaauth/',mediaauth), path('api/wxmplogin/',WXMPlogin.as_view()), @@ -51,5 +66,9 @@ urlpatterns = [ path('api/consulting/', include('apps.consulting.urls')), path('api/docs/', include_docs_urls(title="接口文档",authentication_classes=[], permission_classes=[])), + url(r'^api/swagger(?P\.json|\.yaml)$', schema_view.without_ui(cache_timeout=0), name='schema-json'), + path('api/swagger/', schema_view.with_ui('swagger', cache_timeout=0), name='schema-swagger-ui'), + path('api/redoc/', schema_view.with_ui('redoc', cache_timeout=0), name='schema-redoc'), path('api/', include(router.urls)), + path('', TemplateView.as_view(template_name="index.html")), ] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT) + static(settings.STATIC_URL, document_root=settings.STATIC_ROOT) diff --git a/server/utils/pagination.py b/server/utils/pagination.py index 8f18c67..e0fe3ea 100644 --- a/server/utils/pagination.py +++ b/server/utils/pagination.py @@ -10,8 +10,8 @@ class PageOrNot: def paginate_queryset(self, queryset): if (self.paginator is None): return None - elif self.request.query_params.get('pageoff', None) and queryset.count()<500: + elif (self.request.query_params.get('pageoff', None)) and queryset.count()<500: return None - elif self.request.query_params.get('pageoff', None) and queryset.count()>=500: + elif (self.request.query_params.get('pageoff', None)) and queryset.count()>=500: raise ParseError('单次请求数据量大,请求中止') return self.paginator.paginate_queryset(queryset, self.request, view=self) \ No newline at end of file diff --git a/ssl/testsearch.ctc.ac.cn.csr b/ssl/testsearch.ctc.ac.cn.csr new file mode 100644 index 0000000..a4b4e3f --- /dev/null +++ b/ssl/testsearch.ctc.ac.cn.csr @@ -0,0 +1,17 @@ +-----BEGIN CERTIFICATE REQUEST----- +MIICpjCCAY4CAQAwYTEdMBsGA1UEAwwUdGVzdHNlYXJjaC5jdGMuYWMuY24xDzAN +BgNVBAoMBnFjbG91ZDEQMA4GA1UEBwwHQmVpamluZzEQMA4GA1UECAwHQmVpamlu +ZzELMAkGA1UEBhMCQ04wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC7 +ntPf0oN5RpbUorSglOLiAZal1SI3BoEh6Fmk1NzLUvT0DDTmKaFz4waxTwAglk3Y +pI0TGl+9G5UrmwLia9O17sm0KfHqLe3rEE4EsUD3Uk2CBPVnTMgPS79dAPv04Y3H +H1395h5XSSpzKPzyeQZf3FsyQiAyA9ij77t7jLdPPcHrsgI0adBW8bejF4KQQfRe +25g3nO498GEi76OAaPC2fb48j3ZJ7s8xRcQSt78Ut8rGqaB4Kw8MdxH7yBUooHkx +E7xtv/a86x9c8+cYeYhlLoKhn7n3vxehRM8xv5SI2eZuTfLqTjgvdKbYLztqvxFq +1O+/SksqGrRq2IIV9kcnAgMBAAGgADANBgkqhkiG9w0BAQsFAAOCAQEAmRAftF9Y +O3l/XX2UBzVEy4KKdddRQxlIEmuSTOAq2JaUwgCSGFSl5ue3ZpjW3rOMwAYjHPl3 +N3DVFMqBJnI8vbLCJK43idTm1pE6Ikv2urPoFJyL2+CyyyeJpv+NiEzQOVHnomlY +xqYjePtp9V/H2W1U+JRz4P3ZD/jOLDEsGutE545UZA9cUo3JfJz/uYkzd1kRfoP/ +wqsfreMoMzxLhfWxf/4woQf2e2neixR/JKnTg4duSt86FCHxGuMlJ7x8qLB+N6cK +eW4i+/m6FeFeCI4FvIABYq9bk5/QGNfXd2BluU+s6BfAfhMVPeuwzIVcPdQmplC9 +i9qPUhGJ3IDELQ== +-----END CERTIFICATE REQUEST----- \ No newline at end of file diff --git a/ssl/testsearch.ctc.ac.cn.key b/ssl/testsearch.ctc.ac.cn.key index df3f286..8a6f130 100644 --- a/ssl/testsearch.ctc.ac.cn.key +++ b/ssl/testsearch.ctc.ac.cn.key @@ -1,28 +1,27 @@ ------BEGIN PRIVATE KEY----- -MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCqBDfLPIyYIee9 -M7LjCzdRRP5PHezjaks360V5AnK+oJO7HMgdH7z4QQG8AjKNbLOSFmVaH0R5YTJ3 -XmOGgrdnmb+mCUx3G5wdO9/UXpP4ZA0Gx0S7nqmNPWR03wENoQQjcfMpkBFxMlwC -opS/EeBmQXaKIcg6B4hw3JLObdlr3f1eHccPZchH8Bwho4UjFO7rYVX8jfshV5iC -99KV650jv9uQ3OKno3moDPk9JRnozBpyUwRJ9SFFCZ1lOO625M+dPG13hZcGxMSy -T9wXzcij2luRHXxTSky952ciN3nTomKY00WcOCj0ZCGdHQV/6CzPALdL64TtN5uq -FLG0IoLxAgMBAAECggEAfZ6GNwVzAEk098gGKdm0srieioia6mE0WInemA2mCJGO -9hbLCTHVJzyo8mhRP8uMVqlzk4Y8ys51Qlucf9t/de3U+/Is7GibDcKanEiRXltW -gKalc1dFAdXVrsDC/3X0H9hnCVOof5HtCAlmjFLCEevWkTNqxO2h83oWgq4JkreL -NxyGmRLQAedqaLGcXbPemFSorsNcdQnoUOtJ/7GPl1MjMzt4dx1ysNlV8blNp4VL -BCteRZRdNz6F5paMcbtDKFDLgOdspJofRSsyMCLGktSUw9++F2PM2uavDAw84Pdg -5BtKRvd1P9Esn+TXBtPy1rQoBkBbGKt61Xev0gojvQKBgQDel2xDOVXJkYPIp4V7 -lVwxZYyCzei5YDKTiRGIQu2QS6//r3CSpU6+NTn6RRNTPWvp6PeQSOiMd1gxqgdb -88WXPaIRCb4XDoADyRsB5gDCapetuVJCyUmgw5amkdJ5ktr1ql2dNJokodop40vx -WWNXe0ojEcM2pM7PeMzypUsl3wKBgQDDiLfhuxprhUPHx461RUrA2jTZFdROxgsi -N9NGO3qxuOc/p8MnePikuXs8s7c/x3LZVaVDquy6zoIy6KF+VS4tT36YlT7GyRyv -ndH/t9SiKzks9zBrI3uPlDhkIyctnhVY+2aNM/5cglblOM1FzilijbreNSzh3Lcg -7xp0CQVRLwKBgDiZGBYfxghyz6d9sRszZzXINGouITbBlxqch7C2E+HU3POOkHk5 -P0RuFEfmuHs56u6XJhux7i+JSQuXyDdBTMSgD011xLfoH/TWdd+NtDO7FsY9kQUa -WXZfRTclbPcsuDAvGY6XiXo3DVoJSY4cxH3CA5/XLGQAk/V9Kd+o1+rRAoGBAKvz -sklnQe+mDRpGCuCsY/W+rtTtVnxDuwzHbRuJOPfLdElNXdh7kKVDm/Wg0Zjb68rm -f2RHjtEkw+jDHSm8/NPJ4bmLHd6wg3KI5mDsJ6jJPAmoA8NkO8fi/8hIBa8fIwTS -aLfqLljqIkKINjSZ/Vj27It21dZ2Q/FJc8jxGeTvAoGBALA91l1PnTsUUd3lHj0V -H0uUZD8qIan3WjzKbuJUnvYSI2GgKMPiSX5r4E18+7xgSG2lHRIEN5+FA6T/v9n/ -HbP6e4FGhAaR7KrcxId55pfWPksYPHCAOZFSiKQwVkPy1sJTMKqDZULROQUwjV69 -MjzYAERmsYQA2CkkSLCFhQU2 ------END PRIVATE KEY----- +-----BEGIN RSA PRIVATE KEY----- +MIIEogIBAAKCAQEAu57T39KDeUaW1KK0oJTi4gGWpdUiNwaBIehZpNTcy1L09Aw0 +5imhc+MGsU8AIJZN2KSNExpfvRuVK5sC4mvTte7JtCnx6i3t6xBOBLFA91JNggT1 +Z0zID0u/XQD79OGNxx9d/eYeV0kqcyj88nkGX9xbMkIgMgPYo++7e4y3Tz3B67IC +NGnQVvG3oxeCkEH0XtuYN5zuPfBhIu+jgGjwtn2+PI92Se7PMUXEEre/FLfKxqmg +eCsPDHcR+8gVKKB5MRO8bb/2vOsfXPPnGHmIZS6CoZ+5978XoUTPMb+UiNnmbk3y +6k44L3Sm2C87ar8RatTvv0pLKhq0atiCFfZHJwIDAQABAoIBAB/wwRcoinNZ/hGD +BYcU8a8SIChpKWL+u3sfSCuUhWYj4Emvzk2kprTI4HnM/jOOAwCvusiWw9e422NK +B2queqNNXI9MWL/KQ+expeaMmofAPiu1VmXYn3JjLdfSdBJTV8SfZWv1AhNQBGcI +gk9xJRGqvOfIdByvpPD7vgohgY9+pF7Up37lvMVroJtDpZF2/bk8iz1gzha8jzB5 +SHcCDKnOhe6++cYFa5WA3jcSqDhC/UQFOZBnd+R2ziSEFnGz0CmjG4fXTVyOkqNJ +QNCw/pnnsjG4OAxz6Hr8cmhxq9Tv+TtwSBGf8w1Jen5mHIxyFEYb90SPYRaGOHN2 +2eJIEykCgYEA4ak5G/O2Na1ejvyCN4lhWtzjStA4hrXUce8ciZgY3Rv2xqEa0pTq +Xigyx2hQaS/WWBCHXbqaE3A3j3heKyEK8kVI6Wxq9ytzhTCMCIPIrnZ75kFDMxBn +5mg88CsAT+n8qydDzox++3Cd/PSKoly530qFyHuZlK6WAA3QfAvtg+sCgYEA1NhT +uHy+cSC+RbOt2SuH71cxoa769dk6hadR8aHEcH0+rDnZQ+8KmZTYnumqpm8HdMyb +4UcTjrDcHr11u10kFsEhger8uSzsNJkfbdRGxM1Z+JtSOtkGFRgm4lU9sKH9PHvw +hgYFR95UhfW1vToDzXYMz19Bb76aaUs4CjwxhrUCgYBGz4g5KjeyDk4OxlPCQ5zG +G2xDbKVgOCyK+AJXdt/OeljsqV82Vz5X/3s3sZcR+s3i4oTnt4djtCHrJlU+aWb6 +8RzZColiOENOtxYqEdhmTo3AihghLPO9jFYa8xNtADqmJnMTnGi4U/Vvi/j4y+oT +lFn4uDhQPJybNbqHQmLsswKBgDa1J8e6oISZYu6tgVjZnIYDRmmFfVHltOoXmLNf +3gr/1jUUZWjVr0bMgGVQMCG5VhRKZyKfT0KU6O8pyXIQPa9vkro++RhrmIboeLCV +KF97XM3OtnMTx0FyxMPWHxYgfOOoA6mfMIpJdjY8cqshl0qfNimzFTGwryWzRMM0 +t5IlAoGAUrV59ohoDwUKTkLd2BXEJfFLrCmhtPStUGiaurdKDYKwQrcGwus4nfQT +bmNrRhNR8XR8rTn6D2iJIH0RUk29ETDs0kV1oCUY9JoI5wYWzjVbKOzJi4eg2KQ6 +KgRoppnlmY8sqQ2PCjDNBevL3CHnI623bbVOlNN8kpysGH/Eeng= +-----END RSA PRIVATE KEY----- \ No newline at end of file diff --git a/ssl/testsearch.ctc.ac.cn.pem b/ssl/testsearch.ctc.ac.cn.pem deleted file mode 100644 index dea4367..0000000 --- a/ssl/testsearch.ctc.ac.cn.pem +++ /dev/null @@ -1,128 +0,0 @@ ------BEGIN CERTIFICATE----- -MIIGTDCCBTSgAwIBAgIQPS0W9BEZigBFmUThrWpjwTANBgkqhkiG9w0BAQsFADCB -jzELMAkGA1UEBhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4G -A1UEBxMHU2FsZm9yZDEYMBYGA1UEChMPU2VjdGlnbyBMaW1pdGVkMTcwNQYDVQQD -Ey5TZWN0aWdvIFJTQSBEb21haW4gVmFsaWRhdGlvbiBTZWN1cmUgU2VydmVyIENB -MB4XDTIxMDQyNTAwMDAwMFoXDTIyMDQyNTIzNTk1OVowHzEdMBsGA1UEAxMUdGVz -dHNlYXJjaC5jdGMuYWMuY24wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIB -AQCqBDfLPIyYIee9M7LjCzdRRP5PHezjaks360V5AnK+oJO7HMgdH7z4QQG8AjKN -bLOSFmVaH0R5YTJ3XmOGgrdnmb+mCUx3G5wdO9/UXpP4ZA0Gx0S7nqmNPWR03wEN -oQQjcfMpkBFxMlwCopS/EeBmQXaKIcg6B4hw3JLObdlr3f1eHccPZchH8Bwho4Uj -FO7rYVX8jfshV5iC99KV650jv9uQ3OKno3moDPk9JRnozBpyUwRJ9SFFCZ1lOO62 -5M+dPG13hZcGxMSyT9wXzcij2luRHXxTSky952ciN3nTomKY00WcOCj0ZCGdHQV/ -6CzPALdL64TtN5uqFLG0IoLxAgMBAAGjggMRMIIDDTAfBgNVHSMEGDAWgBSNjF7E -VK2K4Xfpm/mbBeG4AY1h4TAdBgNVHQ4EFgQUr4UA+Awov3oaqRuAMgP3UbKkxF0w -DgYDVR0PAQH/BAQDAgWgMAwGA1UdEwEB/wQCMAAwHQYDVR0lBBYwFAYIKwYBBQUH -AwEGCCsGAQUFBwMCMEkGA1UdIARCMEAwNAYLKwYBBAGyMQECAgcwJTAjBggrBgEF -BQcCARYXaHR0cHM6Ly9zZWN0aWdvLmNvbS9DUFMwCAYGZ4EMAQIBMIGEBggrBgEF -BQcBAQR4MHYwTwYIKwYBBQUHMAKGQ2h0dHA6Ly9jcnQuc2VjdGlnby5jb20vU2Vj -dGlnb1JTQURvbWFpblZhbGlkYXRpb25TZWN1cmVTZXJ2ZXJDQS5jcnQwIwYIKwYB -BQUHMAGGF2h0dHA6Ly9vY3NwLnNlY3RpZ28uY29tMDkGA1UdEQQyMDCCFHRlc3Rz -ZWFyY2guY3RjLmFjLmNughh3d3cudGVzdHNlYXJjaC5jdGMuYWMuY24wggF/Bgor -BgEEAdZ5AgQCBIIBbwSCAWsBaQB3AEalVet1+pEgMLWiiWn0830RLEF0vv1JuIWr -8vxw/m1HAAABeQalozkAAAQDAEgwRgIhAISF+Qpq5bQHPbWpjW8XGdvm6sxf4HKu -vOrk4NTSX1zBAiEAzzOX6eWf6b8eyBWUPQpaEcEr/wYWLjj+84/FMhO1UnEAdQDf -pV6raIJPH2yt7rhfTj5a6s2iEqRqXo47EsAgRFwqcwAAAXkGpaLUAAAEAwBGMEQC -IE+Nd7R7KnkKQwESXlUM8CMoU2ubZRKleyGodJpVK8O8AiAqPBhS1AXPZ/ZIrCg4 -Fg8pqoLMcxxRmsfAewI3OpbUWAB3AFWB1MIWkDYBSuoLm1c8U/DA5Dh4cCUIFy+j -qh0HE9MMAAABeQalos0AAAQDAEgwRgIhAOkGSJnkhA9GxnVL7h85Q59b84cJOjtj -r3ThnHypBamEAiEA096UyGiIKNIVChALqjv8lQh1rywKba0UiI0lLrh7DHwwDQYJ -KoZIhvcNAQELBQADggEBAH8N8GxC+04Pt3XJZD/UoUWIcIJ2uHOhtVVe/pebctMk -8VjD1BF4uKJOGpGRQ80cYB/DWScJL6x0TyTvLyTfeR26tndWDZvNk+L3GokwptRp -XCgNmSUHOhS7wnKCXKqRZZ0QkR32HpNknv36qn9fhe/6wcnUyQeYYCc9AUKyGoKY -EwnS0sL0HLLIDGiewXtR/mSeLt7lbx7+kffxIvRvQvjBV/m+4bHYJHLC/RvwTrWW -+fZcAg595PypE6mZrV9Hb9Vuh5mHRUioPYRT+pEBiih4qzZTHn7c4rQC1c8URuWm -8Ima8Y+4fi3Iwly+JHNv2LaYQlNdtM8iWoIWfwlTzFo= ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIGEzCCA/ugAwIBAgIQfVtRJrR2uhHbdBYLvFMNpzANBgkqhkiG9w0BAQwFADCB -iDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0pl -cnNleSBDaXR5MR4wHAYDVQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNV -BAMTJVVTRVJUcnVzdCBSU0EgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMTgx -MTAyMDAwMDAwWhcNMzAxMjMxMjM1OTU5WjCBjzELMAkGA1UEBhMCR0IxGzAZBgNV -BAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UEBxMHU2FsZm9yZDEYMBYGA1UE -ChMPU2VjdGlnbyBMaW1pdGVkMTcwNQYDVQQDEy5TZWN0aWdvIFJTQSBEb21haW4g -VmFsaWRhdGlvbiBTZWN1cmUgU2VydmVyIENBMIIBIjANBgkqhkiG9w0BAQEFAAOC -AQ8AMIIBCgKCAQEA1nMz1tc8INAA0hdFuNY+B6I/x0HuMjDJsGz99J/LEpgPLT+N -TQEMgg8Xf2Iu6bhIefsWg06t1zIlk7cHv7lQP6lMw0Aq6Tn/2YHKHxYyQdqAJrkj -eocgHuP/IJo8lURvh3UGkEC0MpMWCRAIIz7S3YcPb11RFGoKacVPAXJpz9OTTG0E -oKMbgn6xmrntxZ7FN3ifmgg0+1YuWMQJDgZkW7w33PGfKGioVrCSo1yfu4iYCBsk -Haswha6vsC6eep3BwEIc4gLw6uBK0u+QDrTBQBbwb4VCSmT3pDCg/r8uoydajotY -uK3DGReEY+1vVv2Dy2A0xHS+5p3b4eTlygxfFQIDAQABo4IBbjCCAWowHwYDVR0j -BBgwFoAUU3m/WqorSs9UgOHYm8Cd8rIDZsswHQYDVR0OBBYEFI2MXsRUrYrhd+mb -+ZsF4bgBjWHhMA4GA1UdDwEB/wQEAwIBhjASBgNVHRMBAf8ECDAGAQH/AgEAMB0G -A1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjAbBgNVHSAEFDASMAYGBFUdIAAw -CAYGZ4EMAQIBMFAGA1UdHwRJMEcwRaBDoEGGP2h0dHA6Ly9jcmwudXNlcnRydXN0 -LmNvbS9VU0VSVHJ1c3RSU0FDZXJ0aWZpY2F0aW9uQXV0aG9yaXR5LmNybDB2Bggr -BgEFBQcBAQRqMGgwPwYIKwYBBQUHMAKGM2h0dHA6Ly9jcnQudXNlcnRydXN0LmNv -bS9VU0VSVHJ1c3RSU0FBZGRUcnVzdENBLmNydDAlBggrBgEFBQcwAYYZaHR0cDov -L29jc3AudXNlcnRydXN0LmNvbTANBgkqhkiG9w0BAQwFAAOCAgEAMr9hvQ5Iw0/H -ukdN+Jx4GQHcEx2Ab/zDcLRSmjEzmldS+zGea6TvVKqJjUAXaPgREHzSyrHxVYbH -7rM2kYb2OVG/Rr8PoLq0935JxCo2F57kaDl6r5ROVm+yezu/Coa9zcV3HAO4OLGi -H19+24rcRki2aArPsrW04jTkZ6k4Zgle0rj8nSg6F0AnwnJOKf0hPHzPE/uWLMUx -RP0T7dWbqWlod3zu4f+k+TY4CFM5ooQ0nBnzvg6s1SQ36yOoeNDT5++SR2RiOSLv -xvcRviKFxmZEJCaOEDKNyJOuB56DPi/Z+fVGjmO+wea03KbNIaiGCpXZLoUmGv38 -sbZXQm2V0TP2ORQGgkE49Y9Y3IBbpNV9lXj9p5v//cWoaasm56ekBYdbqbe4oyAL -l6lFhd2zi+WJN44pDfwGF/Y4QA5C5BIG+3vzxhFoYt/jmPQT2BVPi7Fp2RBgvGQq -6jG35LWjOhSbJuMLe/0CjraZwTiXWTb2qHSihrZe68Zk6s+go/lunrotEbaGmAhY -LcmsJWTyXnW0OMGuf1pGg+pRyrbxmRE1a6Vqe8YAsOf4vmSyrcjC8azjUeqkk+B5 -yOGBQMkKW+ESPMFgKuOXwIlCypTPRpgSabuY0MLTDXJLR27lk8QyKGOHQ+SwMj4K -00u/I5sUKUErmgQfky3xxzlIPK1aEn8= ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIFgTCCBGmgAwIBAgIQOXJEOvkit1HX02wQ3TE1lTANBgkqhkiG9w0BAQwFADB7 -MQswCQYDVQQGEwJHQjEbMBkGA1UECAwSR3JlYXRlciBNYW5jaGVzdGVyMRAwDgYD -VQQHDAdTYWxmb3JkMRowGAYDVQQKDBFDb21vZG8gQ0EgTGltaXRlZDEhMB8GA1UE -AwwYQUFBIENlcnRpZmljYXRlIFNlcnZpY2VzMB4XDTE5MDMxMjAwMDAwMFoXDTI4 -MTIzMTIzNTk1OVowgYgxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpOZXcgSmVyc2V5 -MRQwEgYDVQQHEwtKZXJzZXkgQ2l0eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBO -ZXR3b3JrMS4wLAYDVQQDEyVVU0VSVHJ1c3QgUlNBIENlcnRpZmljYXRpb24gQXV0 -aG9yaXR5MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAgBJlFzYOw9sI -s9CsVw127c0n00ytUINh4qogTQktZAnczomfzD2p7PbPwdzx07HWezcoEStH2jnG -vDoZtF+mvX2do2NCtnbyqTsrkfjib9DsFiCQCT7i6HTJGLSR1GJk23+jBvGIGGqQ -Ijy8/hPwhxR79uQfjtTkUcYRZ0YIUcuGFFQ/vDP+fmyc/xadGL1RjjWmp2bIcmfb -IWax1Jt4A8BQOujM8Ny8nkz+rwWWNR9XWrf/zvk9tyy29lTdyOcSOk2uTIq3XJq0 -tyA9yn8iNK5+O2hmAUTnAU5GU5szYPeUvlM3kHND8zLDU+/bqv50TmnHa4xgk97E -xwzf4TKuzJM7UXiVZ4vuPVb+DNBpDxsP8yUmazNt925H+nND5X4OpWaxKXwyhGNV -icQNwZNUMBkTrNN9N6frXTpsNVzbQdcS2qlJC9/YgIoJk2KOtWbPJYjNhLixP6Q5 -D9kCnusSTJV882sFqV4Wg8y4Z+LoE53MW4LTTLPtW//e5XOsIzstAL81VXQJSdhJ -WBp/kjbmUZIO8yZ9HE0XvMnsQybQv0FfQKlERPSZ51eHnlAfV1SoPv10Yy+xUGUJ -5lhCLkMaTLTwJUdZ+gQek9QmRkpQgbLevni3/GcV4clXhB4PY9bpYrrWX1Uu6lzG -KAgEJTm4Diup8kyXHAc/DVL17e8vgg8CAwEAAaOB8jCB7zAfBgNVHSMEGDAWgBSg -EQojPpbxB+zirynvgqV/0DCktDAdBgNVHQ4EFgQUU3m/WqorSs9UgOHYm8Cd8rID -ZsswDgYDVR0PAQH/BAQDAgGGMA8GA1UdEwEB/wQFMAMBAf8wEQYDVR0gBAowCDAG -BgRVHSAAMEMGA1UdHwQ8MDowOKA2oDSGMmh0dHA6Ly9jcmwuY29tb2RvY2EuY29t -L0FBQUNlcnRpZmljYXRlU2VydmljZXMuY3JsMDQGCCsGAQUFBwEBBCgwJjAkBggr -BgEFBQcwAYYYaHR0cDovL29jc3AuY29tb2RvY2EuY29tMA0GCSqGSIb3DQEBDAUA -A4IBAQAYh1HcdCE9nIrgJ7cz0C7M7PDmy14R3iJvm3WOnnL+5Nb+qh+cli3vA0p+ -rvSNb3I8QzvAP+u431yqqcau8vzY7qN7Q/aGNnwU4M309z/+3ri0ivCRlv79Q2R+ -/czSAaF9ffgZGclCKxO/WIu6pKJmBHaIkU4MiRTOok3JMrO66BQavHHxW/BBC5gA -CiIDEOUMsfnNkjcZ7Tvx5Dq2+UUTJnWvu6rvP3t3O9LEApE9GQDTF1w52z97GA1F -zZOFli9d31kWTz9RvdVFGD/tSo7oBmF0Ixa1DVBzJ0RHfxBdiSprhTEUxOipakyA -vGp4z7h/jnZymQyd/teRCBaho1+V ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIEMjCCAxqgAwIBAgIBATANBgkqhkiG9w0BAQUFADB7MQswCQYDVQQGEwJHQjEb -MBkGA1UECAwSR3JlYXRlciBNYW5jaGVzdGVyMRAwDgYDVQQHDAdTYWxmb3JkMRow -GAYDVQQKDBFDb21vZG8gQ0EgTGltaXRlZDEhMB8GA1UEAwwYQUFBIENlcnRpZmlj -YXRlIFNlcnZpY2VzMB4XDTA0MDEwMTAwMDAwMFoXDTI4MTIzMTIzNTk1OVowezEL -MAkGA1UEBhMCR0IxGzAZBgNVBAgMEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UE -BwwHU2FsZm9yZDEaMBgGA1UECgwRQ29tb2RvIENBIExpbWl0ZWQxITAfBgNVBAMM -GEFBQSBDZXJ0aWZpY2F0ZSBTZXJ2aWNlczCCASIwDQYJKoZIhvcNAQEBBQADggEP -ADCCAQoCggEBAL5AnfRu4ep2hxxNRUSOvkbIgwadwSr+GB+O5AL686tdUIoWMQua -BtDFcCLNSS1UY8y2bmhGC1Pqy0wkwLxyTurxFa70VJoSCsN6sjNg4tqJVfMiWPPe -3M/vg4aijJRPn2jymJBGhCfHdr/jzDUsi14HZGWCwEiwqJH5YZ92IFCokcdmtet4 -YgNW8IoaE+oxox6gmf049vYnMlhvB/VruPsUK6+3qszWY19zjNoFmag4qMsXeDZR -rOme9Hg6jc8P2ULimAyrL58OAd7vn5lJ8S3frHRNG5i1R8XlKdH5kBjHYpy+g8cm -ez6KJcfA3Z3mNWgQIJ2P2N7Sw4ScDV7oL8kCAwEAAaOBwDCBvTAdBgNVHQ4EFgQU -oBEKIz6W8Qfs4q8p74Klf9AwpLQwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQF -MAMBAf8wewYDVR0fBHQwcjA4oDagNIYyaHR0cDovL2NybC5jb21vZG9jYS5jb20v -QUFBQ2VydGlmaWNhdGVTZXJ2aWNlcy5jcmwwNqA0oDKGMGh0dHA6Ly9jcmwuY29t -b2RvLm5ldC9BQUFDZXJ0aWZpY2F0ZVNlcnZpY2VzLmNybDANBgkqhkiG9w0BAQUF -AAOCAQEACFb8AvCb6P+k+tZ7xkSAzk/ExfYAWMymtrwUSWgEdujm7l3sAg9g1o1Q -GE8mTgHj5rCl7r+8dFRBv/38ErjHT1r0iWAFf2C3BUrz9vHCv8S5dIa2LX1rzNLz -Rt0vxuBqw8M0Ayx9lt1awg6nCpnBBYurDC/zXDrPbDdVCYfeU0BsWO/8tqtlbgT2 -G9w84FoVxp7Z8VlIMCFlA2zs6SFz7JsDoeA3raAVGI/6ugLOpyypEBMs1OUIJqsi -l2D4kF501KKaU73yqWjgom7C12yxow+ev+to51byrvLjKzg6CYG1a4XXvi3tPxq3 -smPi9WIsgtRqAEFQ8TmDn5XpNpaYbg== ------END CERTIFICATE----- \ No newline at end of file diff --git a/ssl/testsearch.ctc.ac.cn_bundle.crt b/ssl/testsearch.ctc.ac.cn_bundle.crt new file mode 100644 index 0000000..d37a817 --- /dev/null +++ b/ssl/testsearch.ctc.ac.cn_bundle.crt @@ -0,0 +1,66 @@ +-----BEGIN CERTIFICATE----- +MIIGczCCBNugAwIBAgIRAOYohHXv8FLXo4baCaGGuZswDQYJKoZIhvcNAQEMBQAw +WTELMAkGA1UEBhMCQ04xJTAjBgNVBAoTHFRydXN0QXNpYSBUZWNobm9sb2dpZXMs +IEluYy4xIzAhBgNVBAMTGlRydXN0QXNpYSBSU0EgRFYgVExTIENBIEcyMB4XDTIy +MDQyNjAwMDAwMFoXDTIzMDQyNjIzNTk1OVowHzEdMBsGA1UEAxMUdGVzdHNlYXJj +aC5jdGMuYWMuY24wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC7ntPf +0oN5RpbUorSglOLiAZal1SI3BoEh6Fmk1NzLUvT0DDTmKaFz4waxTwAglk3YpI0T +Gl+9G5UrmwLia9O17sm0KfHqLe3rEE4EsUD3Uk2CBPVnTMgPS79dAPv04Y3HH139 +5h5XSSpzKPzyeQZf3FsyQiAyA9ij77t7jLdPPcHrsgI0adBW8bejF4KQQfRe25g3 +nO498GEi76OAaPC2fb48j3ZJ7s8xRcQSt78Ut8rGqaB4Kw8MdxH7yBUooHkxE7xt +v/a86x9c8+cYeYhlLoKhn7n3vxehRM8xv5SI2eZuTfLqTjgvdKbYLztqvxFq1O+/ +SksqGrRq2IIV9kcnAgMBAAGjggLuMIIC6jAfBgNVHSMEGDAWgBRfOnwREH4MZ3Fh +3IujtQADZ/VXHDAdBgNVHQ4EFgQUprxC4BrX8XvDT1n1xTS7U31JYW4wDgYDVR0P +AQH/BAQDAgWgMAwGA1UdEwEB/wQCMAAwHQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsG +AQUFBwMCMEkGA1UdIARCMEAwNAYLKwYBBAGyMQECAjEwJTAjBggrBgEFBQcCARYX +aHR0cHM6Ly9zZWN0aWdvLmNvbS9DUFMwCAYGZ4EMAQIBMH0GCCsGAQUFBwEBBHEw +bzBCBggrBgEFBQcwAoY2aHR0cDovL2NydC50cnVzdC1wcm92aWRlci5jbi9UcnVz +dEFzaWFSU0FEVlRMU0NBRzIuY3J0MCkGCCsGAQUFBzABhh1odHRwOi8vb2NzcC50 +cnVzdC1wcm92aWRlci5jbjAfBgNVHREEGDAWghR0ZXN0c2VhcmNoLmN0Yy5hYy5j +bjCCAX4GCisGAQQB1nkCBAIEggFuBIIBagFoAHYArfe++nz/EMiLnT2cHj4YarRn +KV3PsQwkyoWGNOvcgooAAAGAY3BYXgAABAMARzBFAiAeB3GNy4ySrz7YlvJUQVRe +6rWMWOIHLcfSkLIWo/VzYgIhAPvcJV/9eRM83a6iEf11p36MJ3jPvwGtWr2LrlCK ++InIAHYAejKMVNi3LbYg6jjgUh7phBZwMhOFTTvSK8E6V6NS61IAAAGAY3BYEwAA +BAMARzBFAiAQkq1NFojQbL/SyeClv7UkFXyB6UCZlWHjFvhUS/ODOgIhAJHNkEpo +g7NodBVkS6t3pO9pGRFNXn63PEdcob6RUCoXAHYA6D7Q2j71BjUy51covIlryQPT +y9ERa+zraeF3fW0GvW4AAAGAY3BX9QAABAMARzBFAiAJr+d2ycuSAreIgSPM+Qe+ +I4ajUeAftxWte8gaf2SaOwIhAPWx4260Egud1QrPULoLtNy7hWFNNnfkeiTK3Nmd +EqttMA0GCSqGSIb3DQEBDAUAA4IBgQBRgUlvliFI/KpbWyjUnR5YPpDEylYhXm/3 +GM/XVlXtJDNcpyLyK6SAMri8wxv245Ts7wU+YI2FYlkLzArPiJD85YE+SSu4v0Ea +ZSdj1hPuxFRgidQON7pRS0y5ORgZ2ZDQZMufbEK6l4BmchdGDYtuSTA8iZVFDTIP +H3TlQCza7piHljOY7vRJQcn4l3krIOq6G3uruy+XdywQlfXB1hhRrve340ZFGAiK +4xK9v/gkOt4k4PJD+OzJoJKiezaVIWrYkx86me4O6rU8f/FAYYhONUVh8iIcYMeQ +tJ4gmxUxEc0EUW9kZbuVi7nAzChuhfZebPMI8KQyi7fLsuuzjxzEwqHcSDu7H1AP +GyqJos8AbILID2o2u91aLIBDuMCzSWzq0xu/JqczcmnpEbNHqRRUeTVHiMFgejXQ +lN2wDMOoMQFPTnIs+EvlnguidkC8OjNONQSveG4OAwgiquYbD6WRl/VT9wFeyTmS +gAhJb/H+IjuKr3JHDXtZophtqUu1ZKc= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIFBzCCA++gAwIBAgIRALIM7VUuMaC/NDp1KHQ76aswDQYJKoZIhvcNAQELBQAw +ezELMAkGA1UEBhMCR0IxGzAZBgNVBAgMEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4G +A1UEBwwHU2FsZm9yZDEaMBgGA1UECgwRQ29tb2RvIENBIExpbWl0ZWQxITAfBgNV +BAMMGEFBQSBDZXJ0aWZpY2F0ZSBTZXJ2aWNlczAeFw0yMjAxMTAwMDAwMDBaFw0y +ODEyMzEyMzU5NTlaMFkxCzAJBgNVBAYTAkNOMSUwIwYDVQQKExxUcnVzdEFzaWEg +VGVjaG5vbG9naWVzLCBJbmMuMSMwIQYDVQQDExpUcnVzdEFzaWEgUlNBIERWIFRM +UyBDQSBHMjCCAaIwDQYJKoZIhvcNAQEBBQADggGPADCCAYoCggGBAKjGDe0GSaBs +Yl/VhMaTM6GhfR1TAt4mrhN8zfAMwEfLZth+N2ie5ULbW8YvSGzhqkDhGgSBlafm +qq05oeESrIJQyz24j7icGeGyIZ/jIChOOvjt4M8EVi3O0Se7E6RAgVYcX+QWVp5c +Sy+l7XrrtL/pDDL9Bngnq/DVfjCzm5ZYUb1PpyvYTP7trsV+yYOCNmmwQvB4yVjf +IIpHC1OcsPBntMUGeH1Eja4D+qJYhGOxX9kpa+2wTCW06L8T6OhkpJWYn5JYiht5 +8exjAR7b8Zi3DeG9oZO5o6Qvhl3f8uGU8lK1j9jCUN/18mI/5vZJ76i+hsgdlfZB +Rh5lmAQjD80M9TY+oD4MYUqB5XrigPfFAUwXFGehhlwCVw7y6+5kpbq/NpvM5Ba8 +SeQYUUuMA8RXpTtGlrrTPqJryfa55hTuX/ThhX4gcCVkbyujo0CYr+Uuc14IOyNY +1fD0/qORbllbgV41wiy/2ZUWZQUodqHWkjT1CwIMbQOY5jmrSYGBwwIDAQABo4IB +JjCCASIwHwYDVR0jBBgwFoAUoBEKIz6W8Qfs4q8p74Klf9AwpLQwHQYDVR0OBBYE +FF86fBEQfgxncWHci6O1AANn9VccMA4GA1UdDwEB/wQEAwIBhjASBgNVHRMBAf8E +CDAGAQH/AgEAMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjAiBgNVHSAE +GzAZMA0GCysGAQQBsjEBAgIxMAgGBmeBDAECATBDBgNVHR8EPDA6MDigNqA0hjJo +dHRwOi8vY3JsLmNvbW9kb2NhLmNvbS9BQUFDZXJ0aWZpY2F0ZVNlcnZpY2VzLmNy +bDA0BggrBgEFBQcBAQQoMCYwJAYIKwYBBQUHMAGGGGh0dHA6Ly9vY3NwLmNvbW9k +b2NhLmNvbTANBgkqhkiG9w0BAQsFAAOCAQEAHMUom5cxIje2IiFU7mOCsBr2F6CY +eU5cyfQ/Aep9kAXYUDuWsaT85721JxeXFYkf4D/cgNd9+hxT8ZeDOJrn+ysqR7NO +2K9AdqTdIY2uZPKmvgHOkvH2gQD6jc05eSPOwdY/10IPvmpgUKaGOa/tyygL8Og4 +3tYyoHipMMnS4OiYKakDJny0XVuchIP7ZMKiP07Q3FIuSS4omzR77kmc75/6Q9dP +v4wa90UCOn1j6r7WhMmX3eT3Gsdj3WMe9bYD0AFuqa6MDyjIeXq08mVGraXiw73s +Zale8OMckn/BU3O/3aFNLHLfET2H2hT6Wb3nwxjpLIfXmSVcVd8A58XH0g== +-----END CERTIFICATE----- \ No newline at end of file diff --git a/ssl/testsearch.ctc.ac.cn_bundle.pem b/ssl/testsearch.ctc.ac.cn_bundle.pem new file mode 100644 index 0000000..d37a817 --- /dev/null +++ b/ssl/testsearch.ctc.ac.cn_bundle.pem @@ -0,0 +1,66 @@ +-----BEGIN CERTIFICATE----- +MIIGczCCBNugAwIBAgIRAOYohHXv8FLXo4baCaGGuZswDQYJKoZIhvcNAQEMBQAw +WTELMAkGA1UEBhMCQ04xJTAjBgNVBAoTHFRydXN0QXNpYSBUZWNobm9sb2dpZXMs +IEluYy4xIzAhBgNVBAMTGlRydXN0QXNpYSBSU0EgRFYgVExTIENBIEcyMB4XDTIy +MDQyNjAwMDAwMFoXDTIzMDQyNjIzNTk1OVowHzEdMBsGA1UEAxMUdGVzdHNlYXJj +aC5jdGMuYWMuY24wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC7ntPf +0oN5RpbUorSglOLiAZal1SI3BoEh6Fmk1NzLUvT0DDTmKaFz4waxTwAglk3YpI0T +Gl+9G5UrmwLia9O17sm0KfHqLe3rEE4EsUD3Uk2CBPVnTMgPS79dAPv04Y3HH139 +5h5XSSpzKPzyeQZf3FsyQiAyA9ij77t7jLdPPcHrsgI0adBW8bejF4KQQfRe25g3 +nO498GEi76OAaPC2fb48j3ZJ7s8xRcQSt78Ut8rGqaB4Kw8MdxH7yBUooHkxE7xt +v/a86x9c8+cYeYhlLoKhn7n3vxehRM8xv5SI2eZuTfLqTjgvdKbYLztqvxFq1O+/ +SksqGrRq2IIV9kcnAgMBAAGjggLuMIIC6jAfBgNVHSMEGDAWgBRfOnwREH4MZ3Fh +3IujtQADZ/VXHDAdBgNVHQ4EFgQUprxC4BrX8XvDT1n1xTS7U31JYW4wDgYDVR0P +AQH/BAQDAgWgMAwGA1UdEwEB/wQCMAAwHQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsG +AQUFBwMCMEkGA1UdIARCMEAwNAYLKwYBBAGyMQECAjEwJTAjBggrBgEFBQcCARYX +aHR0cHM6Ly9zZWN0aWdvLmNvbS9DUFMwCAYGZ4EMAQIBMH0GCCsGAQUFBwEBBHEw +bzBCBggrBgEFBQcwAoY2aHR0cDovL2NydC50cnVzdC1wcm92aWRlci5jbi9UcnVz +dEFzaWFSU0FEVlRMU0NBRzIuY3J0MCkGCCsGAQUFBzABhh1odHRwOi8vb2NzcC50 +cnVzdC1wcm92aWRlci5jbjAfBgNVHREEGDAWghR0ZXN0c2VhcmNoLmN0Yy5hYy5j +bjCCAX4GCisGAQQB1nkCBAIEggFuBIIBagFoAHYArfe++nz/EMiLnT2cHj4YarRn +KV3PsQwkyoWGNOvcgooAAAGAY3BYXgAABAMARzBFAiAeB3GNy4ySrz7YlvJUQVRe +6rWMWOIHLcfSkLIWo/VzYgIhAPvcJV/9eRM83a6iEf11p36MJ3jPvwGtWr2LrlCK ++InIAHYAejKMVNi3LbYg6jjgUh7phBZwMhOFTTvSK8E6V6NS61IAAAGAY3BYEwAA +BAMARzBFAiAQkq1NFojQbL/SyeClv7UkFXyB6UCZlWHjFvhUS/ODOgIhAJHNkEpo +g7NodBVkS6t3pO9pGRFNXn63PEdcob6RUCoXAHYA6D7Q2j71BjUy51covIlryQPT +y9ERa+zraeF3fW0GvW4AAAGAY3BX9QAABAMARzBFAiAJr+d2ycuSAreIgSPM+Qe+ +I4ajUeAftxWte8gaf2SaOwIhAPWx4260Egud1QrPULoLtNy7hWFNNnfkeiTK3Nmd +EqttMA0GCSqGSIb3DQEBDAUAA4IBgQBRgUlvliFI/KpbWyjUnR5YPpDEylYhXm/3 +GM/XVlXtJDNcpyLyK6SAMri8wxv245Ts7wU+YI2FYlkLzArPiJD85YE+SSu4v0Ea +ZSdj1hPuxFRgidQON7pRS0y5ORgZ2ZDQZMufbEK6l4BmchdGDYtuSTA8iZVFDTIP +H3TlQCza7piHljOY7vRJQcn4l3krIOq6G3uruy+XdywQlfXB1hhRrve340ZFGAiK +4xK9v/gkOt4k4PJD+OzJoJKiezaVIWrYkx86me4O6rU8f/FAYYhONUVh8iIcYMeQ +tJ4gmxUxEc0EUW9kZbuVi7nAzChuhfZebPMI8KQyi7fLsuuzjxzEwqHcSDu7H1AP +GyqJos8AbILID2o2u91aLIBDuMCzSWzq0xu/JqczcmnpEbNHqRRUeTVHiMFgejXQ +lN2wDMOoMQFPTnIs+EvlnguidkC8OjNONQSveG4OAwgiquYbD6WRl/VT9wFeyTmS +gAhJb/H+IjuKr3JHDXtZophtqUu1ZKc= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIFBzCCA++gAwIBAgIRALIM7VUuMaC/NDp1KHQ76aswDQYJKoZIhvcNAQELBQAw +ezELMAkGA1UEBhMCR0IxGzAZBgNVBAgMEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4G +A1UEBwwHU2FsZm9yZDEaMBgGA1UECgwRQ29tb2RvIENBIExpbWl0ZWQxITAfBgNV +BAMMGEFBQSBDZXJ0aWZpY2F0ZSBTZXJ2aWNlczAeFw0yMjAxMTAwMDAwMDBaFw0y +ODEyMzEyMzU5NTlaMFkxCzAJBgNVBAYTAkNOMSUwIwYDVQQKExxUcnVzdEFzaWEg +VGVjaG5vbG9naWVzLCBJbmMuMSMwIQYDVQQDExpUcnVzdEFzaWEgUlNBIERWIFRM +UyBDQSBHMjCCAaIwDQYJKoZIhvcNAQEBBQADggGPADCCAYoCggGBAKjGDe0GSaBs +Yl/VhMaTM6GhfR1TAt4mrhN8zfAMwEfLZth+N2ie5ULbW8YvSGzhqkDhGgSBlafm +qq05oeESrIJQyz24j7icGeGyIZ/jIChOOvjt4M8EVi3O0Se7E6RAgVYcX+QWVp5c +Sy+l7XrrtL/pDDL9Bngnq/DVfjCzm5ZYUb1PpyvYTP7trsV+yYOCNmmwQvB4yVjf +IIpHC1OcsPBntMUGeH1Eja4D+qJYhGOxX9kpa+2wTCW06L8T6OhkpJWYn5JYiht5 +8exjAR7b8Zi3DeG9oZO5o6Qvhl3f8uGU8lK1j9jCUN/18mI/5vZJ76i+hsgdlfZB +Rh5lmAQjD80M9TY+oD4MYUqB5XrigPfFAUwXFGehhlwCVw7y6+5kpbq/NpvM5Ba8 +SeQYUUuMA8RXpTtGlrrTPqJryfa55hTuX/ThhX4gcCVkbyujo0CYr+Uuc14IOyNY +1fD0/qORbllbgV41wiy/2ZUWZQUodqHWkjT1CwIMbQOY5jmrSYGBwwIDAQABo4IB +JjCCASIwHwYDVR0jBBgwFoAUoBEKIz6W8Qfs4q8p74Klf9AwpLQwHQYDVR0OBBYE +FF86fBEQfgxncWHci6O1AANn9VccMA4GA1UdDwEB/wQEAwIBhjASBgNVHRMBAf8E +CDAGAQH/AgEAMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjAiBgNVHSAE +GzAZMA0GCysGAQQBsjEBAgIxMAgGBmeBDAECATBDBgNVHR8EPDA6MDigNqA0hjJo +dHRwOi8vY3JsLmNvbW9kb2NhLmNvbS9BQUFDZXJ0aWZpY2F0ZVNlcnZpY2VzLmNy +bDA0BggrBgEFBQcBAQQoMCYwJAYIKwYBBQUHMAGGGGh0dHA6Ly9vY3NwLmNvbW9k +b2NhLmNvbTANBgkqhkiG9w0BAQsFAAOCAQEAHMUom5cxIje2IiFU7mOCsBr2F6CY +eU5cyfQ/Aep9kAXYUDuWsaT85721JxeXFYkf4D/cgNd9+hxT8ZeDOJrn+ysqR7NO +2K9AdqTdIY2uZPKmvgHOkvH2gQD6jc05eSPOwdY/10IPvmpgUKaGOa/tyygL8Og4 +3tYyoHipMMnS4OiYKakDJny0XVuchIP7ZMKiP07Q3FIuSS4omzR77kmc75/6Q9dP +v4wa90UCOn1j6r7WhMmX3eT3Gsdj3WMe9bYD0AFuqa6MDyjIeXq08mVGraXiw73s +Zale8OMckn/BU3O/3aFNLHLfET2H2hT6Wb3nwxjpLIfXmSVcVd8A58XH0g== +-----END CERTIFICATE----- \ No newline at end of file