using Azure.Cosmos;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using System;
using System.Collections.Generic;
using System.IdentityModel.Tokens.Jwt;
using System.Text;
using System.Text.Json;
using System.Threading.Tasks;
using TEAMModelOS.Models.Dto;
using TEAMModelOS.SDK.Models;
using TEAMModelOS.SDK;
using TEAMModelOS.SDK.Context.Constant.Common;
using TEAMModelOS.SDK.DI;
using TEAMModelOS.SDK.DI.AzureCosmos.Inner;
using TEAMModelOS.SDK.Extension;
using TEAMModelOS.SDK.Helper.Common.CollectionHelper;
using TEAMModelOS.Models;
using Microsoft.Extensions.Options;
using TEAMModelOS.Filter;
using TEAMModelOS.Services.Common;
using Azure.Storage.Blobs.Models;
using TEAMModelOS.SDK.Models.Cosmos.Common.Inner;
using TEAMModelOS.SDK.Module.AzureBlob.Configuration;
using System.Net.Http;
using TEAMModelOS.SDK.Models.Cosmos;
using Azure.Messaging.ServiceBus;
using Azure.Storage.Sas;
namespace TEAMModelOS.Controllers
{
///
/// 投票活动
///
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status400BadRequest)]
//[Authorize(Roles = "IES5")]
[Route("common/survey")]
[ApiController]
public class SurveyController : ControllerBase
{
private readonly AzureRedisFactory _azureRedis;
private readonly AzureCosmosFactory _azureCosmos;
private readonly SnowflakeId _snowflakeId;
private readonly AzureServiceBusFactory _serviceBus;
private readonly DingDing _dingDing;
private readonly Option _option;
private readonly AzureStorageFactory _azureStorage;
private readonly IHttpClientFactory _clientFactory;
public SurveyController(AzureCosmosFactory azureCosmos, AzureServiceBusFactory serviceBus, SnowflakeId snowflakeId, DingDing dingDing, IOptionsSnapshot option,
AzureRedisFactory azureRedis, AzureStorageFactory azureStorage, IHttpClientFactory clientFactory)
{
_snowflakeId= snowflakeId;
_serviceBus = serviceBus;
_azureCosmos = azureCosmos;
_dingDing = dingDing;
_option = option?.Value;
_azureRedis = azureRedis;
_azureStorage = azureStorage;
_clientFactory = clientFactory;
}
///
/// 新增 或 修改投票活动
///
///
///
[ProducesDefaultResponseType]
[HttpPost("upsert")]
public async Task Upsert(Survey request) {
try {
var client = _azureCosmos.GetCosmosClient();
request.code = request.pk + "-" + request.code;
long now = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds();
request.createTime = now;
if (string.IsNullOrEmpty(request.id))
{
request.id = Guid.NewGuid().ToString();
if (request.startTime > now)
{
request.progress = "pending";
}
else
{
request.progress = "going";
}
request = await client.GetContainer("TEAMModelOS", "Common").CreateItemAsync(request, new PartitionKey($"{request.code}"));
}
else {
var response = await client.GetContainer("TEAMModelOS", "Common").ReadItemStreamAsync(request.id, new PartitionKey($"{request.code}"));
if (response.Status == 200)
{
using var json = await JsonDocument.ParseAsync(response.ContentStream);
var info = json.ToObject();
if (info.progress.Equals("going"))
{
return Ok(new { v = "活动正在进行中" });
}
if (request.startTime > now)
{
request.progress = "pending";
}
else
{
request.progress = "going";
}
request.progress = info.progress;
request = await client.GetContainer("TEAMModelOS", "Common").ReplaceItemAsync(request, info.id, new PartitionKey($"{info.code}"));
}
else {
if (request.startTime > now)
{
request.progress = "pending";
}
else
{
request.progress = "going";
}
request = await client.GetContainer("TEAMModelOS", "Common").CreateItemAsync(request, new PartitionKey($"{request.code}"));
}
}
return Ok(new { survey = request});
} catch (Exception ex) {
await _dingDing.SendBotMsg($"OS,{_option.Location},common/survey/save()\n{ex.Message}", GroupNames.醍摩豆服務運維群組);
return BadRequest(ex.StackTrace);
}
}
///
/// 查询问卷调查,用于列表,编辑,查看
///
///
///Survey-学校/教师编码 活动分区 !"code":"hbcn"/1606285227
///时间筛选范围开始时间 默认30天之前 ?"stime":1608274766154
///时间筛选范围结束时间 默认当前时间 ?"etime":1608274766666
///每页大小 ?"count":10/null/Undefined
///分页Token ?"continuationToken":Undefined/null/"[{\"token\":\"+RID:~omxMAP3ipcSEEwAAAAAAAA==#RT:2#TRC:20#ISV:2#IEO:65551#QCF:1#FPC:AYQTAAAAAAAAiRMAAAAAAAA=\",\"range\":{\"min\":\"\",\"max\":\"FF\"}}]"
/// 当前状态 ?"progress":Undefined/null/"" 表示两种状态都要查询/ "going"/"finish" 表示查询进行中/ 或者已完成 学生端只能查询正在进行或已经结束 going 已发布|finish 已结束
///
///
///
[ProducesDefaultResponseType]
[HttpPost("find")]
public async Task Find(JsonElement requert)
{
try {
//必须有学校或者教师编码
if (!requert.TryGetProperty("code", out JsonElement code)) return BadRequest();
//开始时间,默认最近三十天
var stimestamp = DateTimeOffset.UtcNow.AddDays(-30).ToUnixTimeMilliseconds();
if (requert.TryGetProperty("stime", out JsonElement stime))
{
if (!stime.ValueKind.Equals(JsonValueKind.Undefined)&& !stime.ValueKind.Equals(JsonValueKind.Null) && stime.TryGetInt64(out long data))
{
stimestamp = data;
};
};
//默认当前时间
var etimestamp = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds();
if (requert.TryGetProperty("etime", out JsonElement etime))
{
if (!etime.ValueKind.Equals(JsonValueKind.Null)&&!etime.ValueKind.Equals(JsonValueKind.Undefined) && etime.TryGetInt64(out long data))
{
etimestamp = data;
};
};
var progresssql = "";
if (requert.TryGetProperty("progress", out JsonElement progress))
{
if (!progress.ValueKind.Equals(JsonValueKind.Undefined) && !progress.ValueKind.Equals(JsonValueKind.Null) && progress.ValueKind.Equals(JsonValueKind.String))
{
progresssql = $" and c.progress='{progresssql}' ";
}
}
string continuationToken = null;
//默认不指定返回大小
int? topcout = null;
if (requert.TryGetProperty("count", out JsonElement jcount))
{
if (!jcount.ValueKind.Equals(JsonValueKind.Undefined) && !jcount.ValueKind.Equals(JsonValueKind.Null) && jcount.TryGetInt32(out int data))
{
topcout = data;
}
};
//是否需要进行分页查询,默认不分页
bool iscontinuation = false;
//如果指定了返回大小
if (requert.TryGetProperty("continuationToken", out JsonElement continuation))
{
//指定了cancellationToken 表示需要进行分页
if (!continuation.ValueKind.Equals(JsonValueKind.Null) && !continuation.ValueKind.Equals(JsonValueKind.Undefined))
{
continuationToken = continuation.GetString();
iscontinuation = true;
}
};
List surveys = new List();
var client = _azureCosmos.GetCosmosClient();
var query = $"select c.id,c.name,c.code,c.startTime,c.endTime,c.progress from c where c.createTime >= {stimestamp} and c.createTime <= {etimestamp} {progresssql } ";
await foreach (var item in client.GetContainer("TEAMModelOS", "Common").GetItemQueryStreamIterator(queryText: query,
requestOptions: new QueryRequestOptions() { MaxItemCount = topcout, PartitionKey = new PartitionKey($"Survey-{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())
{
surveys.Add(obj.ToObject());
}
//如果需要分页则跳出
if (iscontinuation)
{
continuationToken = item.GetContinuationToken();
break;
}
}
}
return Ok(new { surveys, continuationToken });
} catch (Exception ex) {
await _dingDing.SendBotMsg($"OS,{_option.Location},common/survey/find()\n{ex.StackTrace}", GroupNames.醍摩豆服務運維群組);
return BadRequest(ex.StackTrace);
}
}
///
/// 查询问卷调查,用于创建者列表,编辑,查看,作答人员查看
///
///
/// ! "id":"3c075347-75ef-4bcb-ae03-68678d02d5ef",
/// ! "code":"Survey-hbcn"/"code":"Survey-1606285227"
///
///
///
[ProducesDefaultResponseType]
[HttpPost("find-id")]
public async Task FindById(JsonElement requert)
{
try
{
var client = _azureCosmos.GetCosmosClient();
//活动id
if (!requert.TryGetProperty("id", out JsonElement id)) return BadRequest();
//活动分区
if (!requert.TryGetProperty("code", out JsonElement code)) return BadRequest();
Survey survey = await client.GetContainer("TEAMModelOS", "Common").ReadItemAsync(id.GetString(), new PartitionKey($"{code}"));
if (survey != null)
{
return Ok(new { survey });
}
else
{
return BadRequest("id,code不存在!");
}
}
catch (Exception ex)
{
await _dingDing.SendBotMsg($"OS,{_option.Location},common/survey/find-id()\n{ex.Message}{requert.ToJsonString()}", GroupNames.醍摩豆服務運維群組);
return BadRequest(ex.StackTrace);
}
}
///
/// 删除问卷调查 TODO 使用ttl删除,并处理相关事务逻辑
///
///
///
[ProducesDefaultResponseType]
[HttpPost("delete")]
[AuthToken(Roles = "admin,teacher")]
public async Task Delete(JsonElement request)
{
try
{
var (userid, _, _, school) = HttpContext.GetAuthTokenInfo();
if (!request.TryGetProperty("id", out JsonElement id)) return BadRequest();
if (!request.TryGetProperty("code", out JsonElement code)) return BadRequest();
var client = _azureCosmos.GetCosmosClient();
Survey survey = await client.GetContainer("TEAMModelOS", "Common").ReadItemAsync(id.GetString(), new PartitionKey($"{code}"));
bool flag = false;
//必须是本人或者这个学校的管理者才能删除
if (survey.creatorId == userid)
{
flag = true;
}
else
{
if (survey.scope == "school" && survey.owner.Equals(school))
{
flag = true;
}
}
if (flag)
{
//使用ttl删除,并处理相关事务逻辑
survey.ttl = 5;
survey = await client.GetContainer("TEAMModelOS", "Common").UpsertItemAsync(survey, new PartitionKey($"{survey.code}"));
return Ok(new { flag });
}
else
{
return Ok(new { flag });
}
}
catch (Exception e)
{
return BadRequest(e.StackTrace);
}
}
///
/// 问卷答案提交
///
///
/// Survey:Record:e6b887f8-adb5-3677-bcc7-3b36450909df_Survey-1595321354 {"C":2,"A":2,"other":2}
///
///
/// !"id":"aaaa"
/// !"code":"Survey-hbcn"/"code":"Survey-1606285227"
/// !"record":[["A","B"],["A"],["D"],[],["建议提升服务质量"]]
///
///
/// msgid=0投票失败,1提交成功,2不在时间范围内,3不在发布范围内,6未设置投票项
///
[ProducesDefaultResponseType]
[HttpPost("answer")]
//[AuthToken(Roles = "teacher,student")]
public async Task Answer(JsonElement request)
{
// var (userid, _, _, _) = HttpContext.GetAuthTokenInfo();
if (request.TryGetProperty("userid", out JsonElement userid)) {
int msgid = await ActivityStudentService.Answer(request, _azureCosmos, _azureRedis, $"{userid}", _azureStorage);
return Ok(new { msgid });
}
else { return Ok(new { msgid = 0 }); }
}
///
/// 问卷答案提交
///
///
/// Survey:Record:e6b887f8-adb5-3677-bcc7-3b36450909df_Survey-1595321354 {"C":2,"A":2,"other":2}
///
///
/// !"id":"aaaa"
/// !"code":"Survey-hbcn"/"code":"Survey-1606285227"
///
///
/// msgid=0投票失败,1提交成功,2不在时间范围内,3不在发布范围内,6未设置投票项
///
[ProducesDefaultResponseType]
[HttpPost("answered-list")]
//[AuthToken(Roles = "teacher,student")]
public async Task AnsweredList(JsonElement request)
{
// var (userid, _, _, _) = HttpContext.GetAuthTokenInfo();
if (!request.TryGetProperty("id", out JsonElement id))
{
return BadRequest();
}
//活动分区
if (!request.TryGetProperty("code", out JsonElement code))
{
return BadRequest();
}
List userids = new List();
var values= await _azureRedis.GetRedisClient(8).SetMembersAsync($"Survey:Submit:{id}");
if (values != default && values.Length>0) {
foreach(var val in values) {
userids.Add(val);
}
}
return Ok(new { userids = userids });
}
///
/// 问卷答案提交
///
///
/// Survey:Record:e6b887f8-adb5-3677-bcc7-3b36450909df_Survey-1595321354 {"C":2,"A":2,"other":2}
///
///
/// !"id":"aaaa"
/// !"code":"Survey-hbcn"/"code":"Survey-1606285227"
///
///
/// msgid=0投票失败,1提交成功,2不在时间范围内,3不在发布范围内,6未设置投票项
///
[ProducesDefaultResponseType]
[HttpPost("answered")]
[AuthToken(Roles = "teacher,student")]
public async Task Answered(JsonElement request)
{
var (userid, _, _, _) = HttpContext.GetAuthTokenInfo();
if (!request.TryGetProperty("id", out JsonElement id))
{
return BadRequest();
}
//活动分区
if (!request.TryGetProperty("code", out JsonElement code))
{
return BadRequest();
}
List userids = new List();
var answered = await _azureRedis.GetRedisClient(8).SetContainsAsync($"Survey:Submit:{id}",userid);
return Ok(new { answered = answered });
}
///
/// 问卷记录 当活动没结算且没有BlobUrl时则调用此接口
///
///
/// {"C":2,"A":2,"other":2}
///
///
/// !"id":"aaaa"
/// !"code":"Survey-hbcn"/"code":"Survey-1606285227"
///
///
///
[ProducesDefaultResponseType]
[HttpPost("record")]
//[AuthToken(Roles = "teacher,student")]
public async Task Record(JsonElement request)
{
if (!request.TryGetProperty("id", out JsonElement id))
{
return BadRequest();
}
//活动分区
if (!request.TryGetProperty("code", out JsonElement code))
{
return BadRequest();
}
//获取问卷记录
var records = await _azureRedis.GetRedisClient(8).HashGetAllAsync($"Survey:Record:{id}");
List res = new List();
foreach (var rcd in records)
{
var value = rcd.Value.ToString().ToObject();
res.Add(new { index = rcd.Name.ToString(), ans = value }) ;
}
return Ok(new {records = res});
}
///
/// 问卷记录 当活动没结算且没有BlobUrl时则调用此接口
///
///
/// {"C":2,"A":2,"other":2}
///
///
/// !"id":"aaaa"
/// !"code":"Survey-hbcn"/"code":"Survey-1606285227"
///
///
///
[ProducesDefaultResponseType]
[HttpPost("settlement")]
//[AuthToken(Roles = "teacher,student")]
public async Task Settlement(JsonElement request)
{
try
{
var client = _azureCosmos.GetCosmosClient();
//活动id
if (!request.TryGetProperty("id", out JsonElement id)) return BadRequest();
//活动分区
if (!request.TryGetProperty("code", out JsonElement code)) return BadRequest();
Survey survey = await client.GetContainer("TEAMModelOS", "Common").ReadItemAsync(id.GetString(), new PartitionKey($"{code}"));
List changeRecords = await _azureStorage.FindListByDict(new Dictionary() { { "RowKey", $"{id}" }, { "PartitionKey", survey.progress } });
ActivityData data = null;
if (survey != null)
{
var adid = survey.id;
var adcode = $"Activity-{survey.owner}";
try {
if (survey.scope == "school")
{
data = await client.GetContainer("TEAMModelOS", "School").ReadItemAsync(adid, new Azure.Cosmos.PartitionKey($"{adcode}"));
}
else if (survey.scope == "private")
{
data = await client.GetContainer("TEAMModelOS", "Teacher").ReadItemAsync(adid, new Azure.Cosmos.PartitionKey($"{adcode}"));
}
} catch {
data = null;
}
if (survey.ttl >= 1)
{
_azureRedis.GetRedisClient(8).KeyDelete($"Survey:Record:{survey.id}");
_azureRedis.GetRedisClient(8).KeyDelete($"Survey:Submit:{survey.id}");
if (data != null)
{
data.ttl = 1;
if (survey.scope == "school")
{
data = await client.GetContainer("TEAMModelOS", "School").ReplaceItemAsync(data, adid, new Azure.Cosmos.PartitionKey($"{adcode}"));
}
else if (survey.scope == "private")
{
data = await client.GetContainer("TEAMModelOS", "Teacher").ReplaceItemAsync(data, adid, new Azure.Cosmos.PartitionKey($"{adcode}"));
}
}
await _dingDing.SendBotMsg($"问卷调查【{survey.name}-{survey.id}】被删除", GroupNames.醍摩豆服務運維群組);
return Ok();
}
else
{
switch (survey.progress)
{
case "finish":
var records = await _azureRedis.GetRedisClient(8).HashGetAllAsync($"Survey:Record:{survey.id}");
List recs = new List();
foreach (var rcd in records)
{
var value = rcd.Value.ToString().ToObject();
recs.Add(new { index = rcd.Name.ToString(), ans = value });
}
var cods = new { records = recs };
//问卷整体情况
await _azureStorage.UploadFileByContainer(survey.owner, cods.ToJsonString(), "survey", $"{survey.id}/record.json");
//结算每道题的答题情况
var ContainerClient = _azureStorage.GetBlobContainerClient(survey.owner);
var route = ContainerClient.Uri.ToString();
//获取
try
{
List items = await ContainerClient.List($"survey/{survey.id}/urecord");
List surveyRecords = new List();
(string uri, string sas) blobAuth = _azureStorage.GetBlobContainerSAS(survey.owner, BlobContainerSasPermissions.Read);
string sas = blobAuth.sas;
var rcode = await _clientFactory.CreateClient().GetAsync(new Uri($"{route}/survey/{survey.id}/record.json?{sas}"));
var jsonc = await JsonDocument.ParseAsync(await rcode.Content.ReadAsStreamAsync());
var Recordc = jsonc.RootElement.ToObject();
HttpClient httpClient = _clientFactory.CreateClient();
await _dingDing.SendBotMsg($"问卷调查问题结算数据11111--->>{Recordc.ToJsonString()}", GroupNames.成都开发測試群組);
foreach (string item in items)
{
var url = $"{route}/{item}?{sas}";
var response = await httpClient.GetAsync(new Uri(url));
var json = await JsonDocument.ParseAsync(await response.Content.ReadAsStreamAsync());
var Record = json.RootElement.ToObject();
surveyRecords.Add(Record);
}
await _dingDing.SendBotMsg($"问卷调查问题结算数据{surveyRecords.ToJsonString()}", GroupNames.成都开发測試群組);
for (int index = 0; index < survey.ans.Count; index++)
{
string url = $"{survey.id}/qrecord/{index}.json";
QuestionRecord question = new QuestionRecord() { index = index };
foreach (SurveyRecord record in surveyRecords)
{
if (record.ans.Count == survey.ans.Count)
{
foreach (var an in record.ans[index])
{
//
if (question.opt.ContainsKey(an))
{
if (question.opt[an] != null)
{
question.opt[an].Add(record.userid);
}
else
{
question.opt[an] = new HashSet() { record.userid };
}
}
else
{
if (survey.ans[index].Contains(an))
{
//如果是客观题code
question.opt.Add(an, new HashSet { record.userid });
}
else
{
//如果不是客观code
question.other[record.userid] = an;
}
}
}
}
}
await _azureStorage.UploadFileByContainer(survey.owner, question.ToJsonString(), "survey", url);
}
}
catch (Exception ex)
{
await _dingDing.SendBotMsg($"问卷调查问题结算异常{ex.Message}\n{ex.StackTrace}", GroupNames.成都开发測試群組);
}
if (string.IsNullOrEmpty(survey.recordUrl))
{
survey.recordUrl = $"/survey/{survey.id}/record.json";
await client.GetContainer("TEAMModelOS", "Common").ReplaceItemAsync(survey, survey.id, new Azure.Cosmos.PartitionKey(survey.code));
}
else
{
//异动,且已经有结算记录则不必再继续。
//break;
}
// await Task.WhenAll(tasks);
//更新结束状态
data.progress = "finish";
if (survey.scope == "school")
{
await client.GetContainer("TEAMModelOS", "School").ReplaceItemAsync(data, data.id, new Azure.Cosmos.PartitionKey(data.code));
}
else if (survey.scope == "private")
{
await client.GetContainer("TEAMModelOS", "Teacher").ReplaceItemAsync(data, data.id, new Azure.Cosmos.PartitionKey(data.code));
}
break;
}
}
}
return Ok();
}
catch (Exception ex)
{
await _dingDing.SendBotMsg($"OS,{_option.Location},common/survey/find-id()\n{ex.Message}", GroupNames.醍摩豆服務運維群組);
return BadRequest(ex.StackTrace);
}
}
}
public class QuestionRecord
{
public int index { get; set; }
public Dictionary> opt { get; set; } = new Dictionary>();
public Dictionary other { get; set; } = new Dictionary();
}
}