Pārlūkot izejas kodu

Merge branch 'develop5.0-tmd' of http://106.12.23.251:10000/TEAMMODEL/TEAMModelOS into develop5.0-tmd

XW 4 gadi atpakaļ
vecāks
revīzija
c12b0e964f

+ 3 - 3
TEAMModelOS/Filter/ApiTokenAttribute.cs

@@ -48,9 +48,9 @@ namespace TEAMModelOS.Filter
                     jti = jwt.Payload.Jti;
                     name = jwt.Claims.FirstOrDefault(claim => claim.Type == "name")?.Value;
                     //处理限流问题
-                    if (string.IsNullOrEmpty(id) || string.IsNullOrEmpty(school) || string.IsNullOrEmpty(name) || string.IsNullOrEmpty(jti))
+                    if (!string.IsNullOrEmpty(id) && !string.IsNullOrEmpty(school) && !string.IsNullOrEmpty(name)&& !string.IsNullOrEmpty(jti))
                     {
-                        context.Result = new BadRequestResult();
+                        pass = true;
                     }
                     else { 
                         
@@ -64,7 +64,7 @@ namespace TEAMModelOS.Filter
                     context.HttpContext.Items.Add("School", school);
                 }
                 else
-                    context.Result = new BadRequestResult();
+                    context.Result = new UnauthorizedResult();
             }
 
             public void OnResourceExecuted(ResourceExecutedContext context)

+ 38 - 0
TEAMModelAPI/Startup.cs

@@ -10,7 +10,11 @@ using System;
 using System.Collections.Generic;
 using System.Linq;
 using System.Threading.Tasks;
+using TEAMModelOS.Models;
 using TEAMModelOS.SDK.DI;
+using System.IdentityModel.Tokens.Jwt;
+using Microsoft.AspNetCore.Authentication.JwtBearer;
+using Microsoft.IdentityModel.Tokens;
 
 namespace TEAMModelAPI
 {
@@ -27,6 +31,37 @@ namespace TEAMModelAPI
         // This method gets called by the runtime. Use this method to add services to the container.
         public void ConfigureServices(IServiceCollection services)
         {
+           
+            JwtSecurityTokenHandler.DefaultMapInboundClaims = false;
+            services.AddAuthentication(options => options.DefaultScheme = JwtBearerDefaults.AuthenticationScheme)
+                .AddJwtBearer(options => //AzureADJwtBearer
+                {
+                    //options.SaveToken = true; //驗證令牌由服務器生成才有效,不適用於服務重啟或分布式架構
+                    options.Authority = Configuration["Option:Authority"];
+                    options.Audience = Configuration["Option:Audience"];
+                    options.RequireHttpsMetadata = true;
+                    options.TokenValidationParameters = new TokenValidationParameters
+                    {
+                        RoleClaimType = "roles",
+                        ValidAudiences = new string[] { Configuration["Option:Audience"], $"api://{Configuration["Option:Audience"]}" }
+                    };
+                    options.Events = new JwtBearerEvents();
+                    //下列事件有需要紀錄則打開
+                    //options.Events.OnMessageReceived = async context => { await Task.FromResult(0); };
+                    //options.Events.OnForbidden = async context => { await Task.FromResult(0); };
+                    //options.Events.OnChallenge = async context => { await Task.FromResult(0); };
+                    //options.Events.OnAuthenticationFailed = async context => { await Task.FromResult(0); };
+                    options.Events.OnTokenValidated = async context =>
+                    {
+                        if (!context.Principal.Claims.Any(x => x.Type == "http://schemas.microsoft.com/identity/claims/scope") //ClaimConstants.Scope
+                        && !context.Principal.Claims.Any(y => y.Type == "roles")) //ClaimConstants.Roles //http://schemas.microsoft.com/ws/2008/06/identity/claims/role
+                        {
+                            //TODO 需處理額外授權非角色及範圍的訪問異常紀錄
+                            throw new UnauthorizedAccessException("Neither scope or roles claim was found in the bearer token.");
+                        }
+                        await Task.FromResult(0);
+                    };
+                });
             //設定跨域請求
             services.AddCors(options =>
             {
@@ -50,6 +85,9 @@ namespace TEAMModelAPI
             services.AddHttpClient();
             services.AddHttpClient<DingDing>();
             services.AddAzureServiceBus(Configuration.GetValue<string>("Azure:ServiceBus:ConnectionString"));
+            //HttpContextAccessor,并用来访问HttpContext。(提供組件或非控制器服務存取HttpContext)
+            services.AddHttpContextAccessor();
+            services.Configure<Option>(options => Configuration.GetSection("Option").Bind(options));
         }
 
         // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.

+ 1 - 2
TEAMModelAPI/TEAMModelAPI.csproj

@@ -5,7 +5,6 @@
   </PropertyGroup>
 
   <ItemGroup>
-    <ProjectReference Include="..\TEAMModelOS\TEAMModelOS.csproj" />
+    <ProjectReference Include="..\TEAMModelOS.SDK\TEAMModelOS.SDK.csproj" />
   </ItemGroup>
-
 </Project>

+ 13 - 1
TEAMModelAPI/appsettings.json

@@ -6,5 +6,17 @@
       "Microsoft.Hosting.Lifetime": "Information"
     }
   },
-  "AllowedHosts": "*"
+  "AllowedHosts": "*",
+  "Option": {
+    "Location": "China",
+    "LocationNum": "8",
+    "HostName": "localhost:5001",
+    "AllowedHosts": [ "localhost", "*.teammodel.cn", "*.teammodel.net", "*.habookaclass.biz", "test" ],
+    "Authority": "https://login.chinacloudapi.cn/4807e9cf-87b8-4174-aa5b-e76497d7392b/v2.0", //China:"https://login.chinacloudapi.cn/4807e9cf-87b8-4174-aa5b-e76497d7392b/v2.0", //Global:"https://login.microsoftonline.com/73a2bcc5-fe99-4566-aa8a-07e7bb287df1/v2.0"
+    "Audience": "72643704-b2e7-4b26-b881-bd5865e7a7a5", //China:"72643704-b2e7-4b26-b881-bd5865e7a7a5",Global:"8768b06f-c5c5-4b0c-abfb-d7ded354626d"
+    "Issuer": "www.teammodel.cn",
+    "JwtSecretKey": "fXO6ko/qyXeYrkecPeKdgXnuLXf9vMEtnBC9OB3s+aA=",
+    "Exp": 86400,
+    "IdTokenSalt": "8263692E2213497BB55E74792B7900B4"
+  }
 }

+ 2 - 2
TEAMModelOS.SDK/Extension/JwtAuthExtension.cs

@@ -81,11 +81,11 @@ namespace TEAMModelOS.SDK.Extension
                 var handler = new JwtSecurityTokenHandler();
                 var validationParameters = new TokenValidationParameters
                 {
-                    RequireExpirationTime = true,
+                    RequireExpirationTime = false,
                     ValidateIssuer = false,
                     ValidateAudience = false,
                     IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(salt)),
-                    //ValidateLifetime = false,
+                    ValidateLifetime = false,
                     //LifetimeValidator = LifetimeValidator,
                     ClockSkew = TimeSpan.Zero
                 };

+ 64 - 1
TEAMModelOS.SDK/Models/Cosmos/Api/OpenApi.cs

@@ -28,22 +28,85 @@ namespace TEAMModelOS.SDK.Models
 
             PartitionKey = "IES5-API";
         } 
+        /// <summary>
+        /// 接口名称
+        /// </summary>
         public string name { get; set; }
+        /// <summary>
+        /// 接口url
+        /// </summary>
         public string url { get; set; }
+        /// <summary>
+        /// 请求方法
+        /// </summary>
         public string method { get; set; }
+        /// <summary>
+        /// 开放的api接口
+        /// </summary>
         public string descr { get; set; }
         public int auth { get; set; }
-
     }
+    [TableName(Name = "OpenApi")]
+    public class Webhook : TableEntity
+    {
+        public Webhook()
+        {
 
+            PartitionKey = "IES5-WEBHOOK";
+        }
+        /// <summary>
+        /// 接口名称
+        /// </summary>
+        public string name { get; set; }
+        /// <summary>
+        /// 接口url
+        /// </summary>
+        public string url { get; set; }
+        /// <summary>
+        /// 请求方法
+        /// </summary>
+        public string method { get; set; }
+        /// <summary>
+        /// 开放的api接口
+        /// </summary>
+        public string descr { get; set; }
+        public int auth { get; set; }
+    }
     public class OpenApp : CosmosEntity {
+        /// <summary>
+        /// 图标
+        /// </summary>
         public string icon { get; set; }
+        /// <summary>
+        /// 应用名称
+        /// </summary>
         public string name { get; set; }
+        /// <summary>
+        /// 应用描述
+        /// </summary>
         public string descr { get; set; }
+        /// <summary>
+        /// 授权信息
+        /// </summary>
         public List<int> auths { get; set; } = new List<int>();
+        public List<int> webhooks { get; set; } = new List<int>();
+        /// <summary>
+        /// 学校编码
+        /// </summary>
         public string school { get; set; }
+        /// <summary>
+        /// 生成的token
+        /// </summary>
         public string token { get; set; }
         /// <summary>
+        /// domain的域名
+        /// </summary>
+        public string domain { get; set; }
+        /// <summary>
+        ///webhook
+        /// </summary>
+        public string webhookToken { get; set; }
+        /// <summary>
         /// 0禁用,1正常,2 token封禁
         /// </summary>
         public int status { get; set; }

+ 4 - 0
TEAMModelOS/ClientApp/src/api/service.js

@@ -4,4 +4,8 @@ export default {
     getNotification: function (data) {
         return post('https://api2.teammodel.net/service/getnotification', data)
     },
+    /* 获取id详细信息 */
+    getIdProfile: function (host,data) {
+        return post(`${host}/oauth2/profile`, data)
+    },
 }

+ 2 - 2
TEAMModelOS/ClientApp/src/static/Global.js

@@ -2,8 +2,8 @@ import i18n from '../locale/index.js'
 import Vue from 'vue'
 import VueI18n from 'vue-i18n'
 
-const PRIVATE_SPACE = 1024 * 1024 * 1024 * 1 //教师Blob个人空间
-const SCHOOL_SPACE = 1024 * 1024 * 1024 * 10 //学校Blob空间
+var PRIVATE_SPACE = 1024 * 1024 * 1024 * 1 //教师Blob个人空间
+var SCHOOL_SPACE = 1024 * 1024 * 1024 * 10 //学校Blob空间
 const DEFAULT_SCHOOL_CODE = 'SYSTEM_NO_SCHOOL' //尚未归属学校的默认学校编码
 
 //文件类型,对应内容模块Blob目录

+ 42 - 6
TEAMModelOS/ClientApp/src/view/homepage/HomePage.vue

@@ -7,17 +7,16 @@
         </p>
         <div class="verify-status">
             <!-- 如果是大陆站需要验证是否完成手机号认证 -->
-            <div class="verify-status-box" v-if="$store.state.userInfo.hasVerify">
+            <div v-show="srvAdr == 'China'" class="verify-status-box" v-if="!hasVerify">
                 <Icon custom="iconfont icon-phone-unverify" class="tips-icon" />
                 <b class="verify-title">{{$t('home.verifyPh')}}</b>
                 <router-link to="/regist" class="to-verify">{{$t('home.toPhone')}}</router-link>
             </div>
-            <div class="verify-status-box" v-else>
+            <div v-show="srvAdr == 'China'" class="verify-status-box" v-else>
                 <Icon type="md-checkmark-circle-outline" class="tips-icon" color="#19be6b" />
                 <p class="phone-tips">
                     <span style="font-size:16px;color:white">{{$t('home.phoneSuccess')}}</span>
                     <br />
-                    <span style="font-size:12px">(暂未对接API)</span>
                 </p>
                 <span class="has-verify">{{$t('home.hasBanding')}}</span>
             </div>
@@ -323,6 +322,7 @@ import AcCountPie from "./AcCountPie.vue"
 import TechScore from "./TechScore.vue"
 import TeachScore from "./TeachScore.vue"
 import MinTable from "./MinTable.vue"
+import jwtDecode from 'jwt-decode'
 export default {
     components: {
         AcCountPie, TechScore, TeachScore, MinTable
@@ -333,7 +333,9 @@ export default {
             split2: 0.5,
             split3: 0.5,
             itemCount: 10,
-            tmwCus: []
+            tmwCus: [],
+            srvAdr:'China',
+            hasVerify: false, //是否完成手机号验证
         }
     },
     methods: {
@@ -375,15 +377,49 @@ export default {
             this.$router.push({
                 path: '/home/settings'
             })
+        },
+        // 获取账号详细信息,用来验证大陆站用户是否完成手机号绑定
+        getIdInfo() {
+            let host = this.$store.state.config.China.coreAPIUrl
+            let clientId = this.$store.state.config.China.clientID
+            let idToken = localStorage.getItem('id_token')
+            let tokenData = jwtDecode(idToken)
+            let nonce = tokenData ? tokenData.nonce : ''
+            let params = {
+                "grant_type": "get",
+                "nonce": nonce,
+                "client_id": clientId,
+                "id_token": idToken
+            }
+            this.$api.service.getIdProfile(host, params).then(
+                res => {
+                    console.log(res)
+                    if(!res.error){
+                        if(res.mobile) this.hasVerify = true
+                    }else{
+                        this.$Message.error('API Error')
+                    }
+                },
+                err => {
+                    console.log(err)
+                }
+            )
+
         }
     },
     created() {
+        this.srvAdr = this.$store.state.config.srvAdr
+        //只有大陆站才验证手机号
+        if (this.srvAdr == 'China'){
+            this.getIdInfo()
+        }else{
+            this.hasVerify = true
+        }
     },
     computed: {
         //暂时只验证加入学校, 手机号需要对接API
         isComplete() {
-            // return this.$store.state.userInfo.hasSchool && this.$store.state.userInfo.hasVerify
-            return this.$store.state.userInfo.hasSchool
+            return this.$store.state.userInfo.hasSchool && this.hasVerify
         }
     }
 }

+ 0 - 1
TEAMModelOS/ClientApp/src/view/homepage/MinTable.vue

@@ -285,7 +285,6 @@ export default {
         },
         getNextDay() {
             let today = new Date().getDay()
-            console.log('今天是',today)
             let tomorrow
             if (today < 7) {
                 tomorrow = ++today

+ 68 - 0
TEAMModelOS/Controllers/Common/CommonController.cs

@@ -44,6 +44,74 @@ namespace TEAMModelOS.Controllers.Common
             _clientFactory = clientFactory;
         }
 
+        //立即结束某个活动
+        [ProducesDefaultResponseType]
+       // [AuthToken(Roles = "teacher,admin")]
+        [HttpPost("count-activity")]
+        public async Task<IActionResult> countActivity(JsonElement element)
+        {
+            try
+            {
+                List<string> keys = new List<string> { "Vote","Exam", "Survey","Homework","Learn" };
+                var client = _azureCosmos.GetCosmosClient();
+                element.TryGetProperty("code", out JsonElement code) ;
+                element.TryGetProperty("tmdid", out JsonElement tmdid);
+                Dictionary<string, int> countall = new Dictionary<string, int>();
+                foreach (var key in keys) {
+                    string queryList = $"select  count(1) as countschool  from c where c.pk='{key}' ";
+                    if (code.ValueKind.Equals(JsonValueKind.String)) {
+                        var queryschool = $"select  count(1) as countschool  from c where c.pk='{key}' ";
+                        await foreach (var item in client.GetContainer("TEAMModelOS", "Common").GetItemQueryStreamIterator(
+                           queryText: queryschool, requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"{key}-{code}") }))
+                        {
+                            using var json = await JsonDocument.ParseAsync(item.ContentStream);
+                            if (json.RootElement.TryGetProperty("_count", out JsonElement count) && count.GetUInt16() > 0)
+                            {
+                                foreach (var obj in json.RootElement.GetProperty("Documents").EnumerateArray())
+                                {
+                                    if (countall.ContainsKey(key.ToLower()))
+                                    {
+                                        countall[key.ToLower()] = countall[key.ToLower()] + obj.GetProperty("countprivate").GetInt32();
+                                    }
+                                    else
+                                    {
+                                        countall.Add(key.ToLower(), obj.GetProperty("countschool").GetInt32());
+                                    }
+                                }
+                            }
+                        }
+                    }
+
+                    if (tmdid.ValueKind.Equals(JsonValueKind.String)) {
+                        var queryprivate = $"select  count(1) as countprivate  from c where c.pk='{key}' ";
+                        await foreach (var item in client.GetContainer("TEAMModelOS", "Common").GetItemQueryStreamIterator(
+                           queryText: queryprivate, requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"{key}-{tmdid}") }))
+                        {
+                            using var json = await JsonDocument.ParseAsync(item.ContentStream);
+                            if (json.RootElement.TryGetProperty("_count", out JsonElement count) && count.GetUInt16() > 0)
+                            {
+                                foreach (var obj in json.RootElement.GetProperty("Documents").EnumerateArray())
+                                {
+                                    if (countall.ContainsKey(key.ToLower()))
+                                    {
+                                        countall[key.ToLower()] = countall[key.ToLower()] + obj.GetProperty("countprivate").GetInt32();
+                                    }
+                                    else
+                                    {
+                                        countall.Add(key.ToLower(), obj.GetProperty("countprivate").GetInt32());
+                                    }
+                                }
+                            }
+                        }
+                    }
+                }
+                return Ok(new { countall });
+            } catch (Exception ex) {
+                await _dingDing.SendBotMsg($"OS,{_option.Location},common/count-activity\n{ex.Message}{ex.StackTrace}", GroupNames.醍摩豆服務運維群組);
+                return BadRequest(); 
+            }
+        }
+
         //立即结束某个活动
         [ProducesDefaultResponseType]
         [AuthToken(Roles = "teacher,admin")]

+ 20 - 3
TEAMModelOS/Controllers/Core/OpenApiController.cs

@@ -72,17 +72,34 @@ namespace TEAMModelOS.Controllers.Core
          {}
          */
         /// <summary>
-        /// 获取
+        /// 获取开放api接口
         /// </summary>
         /// <param name="request"></param>
         /// <returns></returns>
         [ProducesDefaultResponseType]
       //  [AuthToken(Roles = "admin")]
-        [HttpPost("get")]
-        public async Task<IActionResult> Get(JsonElement json) {
+        [HttpPost("get-api")]
+        public async Task<IActionResult> GetApi(JsonElement json) {
             List<OpenApi> apis = await _azureStorage.FindListByDict<OpenApi>(new Dictionary<string, object>() { { "PartitionKey", "IES5-API" } });
             return Ok(new { apis });
         }
+        /*
+         数据实例
+         {}
+         */
+        /// <summary>
+        /// 获取webhook 通知接口
+        /// </summary>
+        /// <param name="request"></param>
+        /// <returns></returns>
+        [ProducesDefaultResponseType]
+        //  [AuthToken(Roles = "admin")]
+        [HttpPost("get-webhook")]
+        public async Task<IActionResult> GetWebhook(JsonElement json)
+        {
+            List<Webhook> webhooks = await _azureStorage.FindListByDict<Webhook>(new Dictionary<string, object>() { { "PartitionKey", "IES5-WEBHOOK" } });
+            return Ok(new { webhooks });
+        }
         /*
         {
            "id": "4a54e95e-ef13-46ec-91ac-e55919d09f9e", //新增没有id  ,更新带id  

+ 49 - 32
TEAMModelOS/Controllers/Syllabus/ShareController.cs

@@ -27,7 +27,7 @@ namespace TEAMModelOS.Controllers
     //[Authorize(Roles = "IES5")]
     [Route("teacher/share")]
     [ApiController]
-    public class ShareController: ControllerBase
+    public class ShareController : ControllerBase
     {
         private readonly AzureCosmosFactory _azureCosmos;
         private readonly SnowflakeId _snowflakeId;
@@ -40,7 +40,7 @@ namespace TEAMModelOS.Controllers
             _azureCosmos = azureCosmos;
             _snowflakeId = snowflakeId;
             _dingDing = dingDing;
-            _option = option?.Value; 
+            _option = option?.Value;
             _configuration = configuration;
             _notificationService = notificationService;
         }
@@ -67,7 +67,7 @@ namespace TEAMModelOS.Controllers
         /// <returns></returns>
         [ProducesDefaultResponseType]
         [HttpPost("to")]
-       // [AuthToken(Roles = "Teacher")]
+        // [AuthToken(Roles = "Teacher")]
         public async Task<IActionResult> To(ShareData request) {
             // var (id, _, _, _) = HttpContext.GetAuthTokenInfo();
 
@@ -82,11 +82,11 @@ namespace TEAMModelOS.Controllers
                         if (syllabusD.auth.IsNotEmpty())
                         {
                             List<SyllabusAuth> syllabusAuths = new List<SyllabusAuth>();
-                            syllabusD.auth.ForEach(x=> {
-                                if (request.tmdInfo.Select(tmd=>tmd.tmdid).Contains(x.tmdid)) {
+                            syllabusD.auth.ForEach(x => {
+                                if (request.tmdInfo.Select(tmd => tmd.tmdid).Contains(x.tmdid)) {
                                     syllabusAuths.Add(x);
-                                }   
-                            }) ;
+                                }
+                            });
                             syllabusAuths.ForEach(x => {
                                 syllabusD.auth.Remove(x);
                             });
@@ -94,13 +94,13 @@ namespace TEAMModelOS.Controllers
                             request.tmdInfo.ForEach(async x => {
                                 await client.GetContainer("TEAMModelOS", "Teacher").DeleteItemAsync<Share>(request.syllabusId, new PartitionKey($"Share-{x.tmdid}"));
                             });
-                            
+
                         }
                     }
                     else if (request.opt.Equals("add") || request.opt.Equals("edit"))
                     {
                         (Syllabus syllabus, List<Share> shares) = DoAuth(request, syllabusD);
-                        shares.ForEach(async x=> {
+                        shares.ForEach(async x => {
                             await client.GetContainer("TEAMModelOS", "Teacher").UpsertItemAsync<Share>(x, new PartitionKey($"{x.code}"));
                             //发送共编或分享通知
                             Notification notification = new Notification
@@ -108,9 +108,9 @@ namespace TEAMModelOS.Controllers
                                 hubName = "hita",
                                 type = "msg",
                                 from = $"ies5:{request.school}",
-                                to = new List<string>() { x.code.Replace("Share-","") },
+                                to = new List<string>() { x.code.Replace("Share-", "") },
                                 label = $"{x.type}_syllabus",
-                                body = new { biz = x.type, tmdid = x.issuer,  schoolcode = $"{request.school}",  status = 1, time = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds() }.ToJsonString(),
+                                body = new { biz = x.type, tmdid = x.issuer, schoolcode = $"{request.school}", status = 1, time = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds() }.ToJsonString(),
                                 expires = DateTimeOffset.UtcNow.AddDays(7).ToUnixTimeSeconds()
                             };
                             var url = _configuration.GetValue<string>("HaBookAuth:CoreService:sendnotification");
@@ -121,7 +121,7 @@ namespace TEAMModelOS.Controllers
                         });
                         await client.GetContainer("TEAMModelOS", "School").UpsertItemAsync<Syllabus>(syllabus, new PartitionKey($"Syllabus-{request.volumeId}"));
 
-                        
+
                     }
                 }
                 else if (request.scope.Equals("private"))
@@ -133,7 +133,7 @@ namespace TEAMModelOS.Controllers
                         {
                             List<SyllabusAuth> syllabusAuths = new List<SyllabusAuth>();
                             syllabusD.auth.ForEach(x => {
-                                if (request.tmdInfo.Select(tmd=>x.tmdid).Contains(x.tmdid))
+                                if (request.tmdInfo.Select(tmd => x.tmdid).Contains(x.tmdid))
                                 {
                                     syllabusAuths.Add(x);
                                 }
@@ -156,9 +156,9 @@ namespace TEAMModelOS.Controllers
                         await client.GetContainer("TEAMModelOS", "Teacher").UpsertItemAsync<Syllabus>(syllabusD, new PartitionKey($"Syllabus-{request.volumeId}"));
                     }
                 }
-                return Ok(new { code=200});
+                return Ok(new { code = 200 });
             }
-            catch (Exception ex ) {
+            catch (Exception ex) {
                 await _dingDing.SendBotMsg($"OS,{_option.Location},teacher/share/to\n{ex.Message}{ex.StackTrace}", GroupNames.成都开发測試群組);
             }
             return Ok(new { code = 500 });
@@ -182,12 +182,12 @@ namespace TEAMModelOS.Controllers
                     createTime = now,
                     school = request.school,
                     scope = request.scope,
-                    type =request.type,
+                    type = request.type,
                     agree = request.agree
                 };
                 shares.Add(share);
             });
-            
+
             if (syllabus.auth.IsNotEmpty())
             {
                 request.tmdInfo.ForEach(xmd => {
@@ -196,7 +196,7 @@ namespace TEAMModelOS.Controllers
                     int indx = 0;
                     for (int index = 0; index < syllabus.auth.Count; index++)
                     {
-                        if (syllabus.auth[index].tmdid == xmd.tmdid && request.type== syllabus.auth[index].type)
+                        if (syllabus.auth[index].tmdid == xmd.tmdid && request.type == syllabus.auth[index].type)
                         {
                             flag = true;
                             indx = index;
@@ -273,7 +273,7 @@ namespace TEAMModelOS.Controllers
                 {
                     syllabus.auth.ForEach(x =>
                     {
-                        if (x.tmdid == $"{code}" && x.type==$"{type}")
+                        if (x.tmdid == $"{code}" && x.type == $"{type}")
                         {
                             if ($"{opt}".Equals("ignore"))
                             {
@@ -282,34 +282,51 @@ namespace TEAMModelOS.Controllers
                             else if ($"{opt}".Equals("ignore")) {
                                 x.agree = 1;
                             }
-                          
+
                         }
                     });
                 }
-                if (share.scope == "school")
-                {
-                    syllabus = await client.GetContainer("TEAMModelOS", "School").ReplaceItemAsync<Syllabus>(syllabus, $"{id}", new PartitionKey($"Syllabus-{share.volumeId}"));
-                }
-                else if (share.scope == "private")
-                {
-                    syllabus = await client.GetContainer("TEAMModelOS", "Teacher").ReplaceItemAsync<Syllabus>(syllabus, $"{id}", new PartitionKey($"Syllabus-{share.volumeId}"));
-                }
+
                 if ($"{opt}".Equals("ignore"))
                 {
                     share.agree = 1;
-                    await client.GetContainer("TEAMModelOS", "Teacher").ReplaceItemAsync<Share>(share,$"{id}", new PartitionKey($"Share-{type}-{code}"));
+                    await client.GetContainer("TEAMModelOS", "Teacher").ReplaceItemAsync<Share>(share, $"{id}", new PartitionKey($"Share-{type}-{code}"));
                 }
                 else if ($"{opt}".Equals("ignore"))
                 {
                     await client.GetContainer("TEAMModelOS", "Teacher").DeleteItemAsync<Share>($"{id}", new PartitionKey($"Share-{type}-{code}"));
                 }
+                if (share.scope == "school")
+                {
+                    syllabus = await client.GetContainer("TEAMModelOS", "School").ReplaceItemAsync<Syllabus>(syllabus, $"{id}", new PartitionKey($"Syllabus-{share.volumeId}"));
+                }
+                else if (share.scope == "private")
+                {
+                    syllabus = await client.GetContainer("TEAMModelOS", "Teacher").ReplaceItemAsync<Syllabus>(syllabus, $"{id}", new PartitionKey($"Syllabus-{share.volumeId}"));
+                }
                 return Ok(new { status = 200 });
             } catch (Exception ex) {
                 await _dingDing.SendBotMsg($"OS,{_option.Location},teacher/share/agree-share()\n{ex.Message}{ex.StackTrace}", GroupNames.醍摩豆服務運維群組);
                 return Ok(new { status = 500 });
             }
         }
-
+        [ProducesDefaultResponseType]
+        [HttpPost("del-share")]
+        public async Task<IActionResult> DelShare(JsonElement request) {
+            try
+            {
+                var client = _azureCosmos.GetCosmosClient();
+                if (!request.TryGetProperty("type", out JsonElement type)) { return BadRequest(); }
+                if (!request.TryGetProperty("code", out JsonElement code)) { return BadRequest(); }
+                if (!request.TryGetProperty("id", out JsonElement id)) { return BadRequest(); }
+                await client.GetContainer("TEAMModelOS", "Teacher").DeleteItemAsync<Share>($"{id}", new PartitionKey($"Share-{type}-{code}"));
+                return Ok(new { status = 200 });
+            } catch (Exception ex)
+            {
+                await _dingDing.SendBotMsg($"OS,{_option.Location},teacher/share/del-share()\n{ex.Message}{ex.StackTrace}", GroupNames.醍摩豆服務運維群組);
+                return Ok(new { status = 500 });
+            }
+        }
         /// <summary>
         /// {"code":"教师编码","type":"coedit/share","id":"册别id"} 
         /// 教师拉取自己收到的分享及共编
@@ -339,12 +356,12 @@ namespace TEAMModelOS.Controllers
                     shares.Add(item);
                 }
                 var sharesGp  =  shares.GroupBy(x => new {id= x.volumeId ,code=x.scope=="school"?x.school:x.issuer}).Select(y=>new { id=y.Key.id,code=y.Key.code,list=y.ToList()});
-                return Ok(new { shares = sharesGp });
+                return Ok(new { shares = sharesGp ,status=200});
             }
             catch (Exception ex)
             {
                 await _dingDing.SendBotMsg($"OS,{_option.Location},teacher/share/find()\n{ex.Message}{ex.StackTrace}", GroupNames.醍摩豆服務運維群組);
-                return BadRequest();
+                return Ok(new {  status = 404 });
             }
 
         }