123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317 |
- using Azure.Cosmos;
- using Microsoft.AspNetCore.Http;
- using Microsoft.AspNetCore.Mvc;
- using System;
- using System.Collections.Generic;
- using System.IdentityModel.Tokens.Jwt;
- using System.Linq;
- 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.SDK.Helper.Common.StringHelper;
- using TEAMModelOS.Models;
- using Microsoft.Extensions.Options;
- using TEAMModelOS.SDK.Models.Cosmos;
- using Microsoft.AspNetCore.Authorization;
- using TEAMModelOS.Filter;
- using StackExchange.Redis;
- using TEAMModelOS.SDK.Models.Cosmos.Common.Inner;
- using TEAMModelOS.Services.Common;
- namespace TEAMModelOS.Controllers.Learn
- {
- /// <summary>
- /// 投票活动
- /// </summary>
- [ProducesResponseType(StatusCodes.Status200OK)]
- [ProducesResponseType(StatusCodes.Status400BadRequest)]
- //[Authorize(Roles = "IES5")]
- [Route("common/vote")]
- [ApiController]
- public class VoteController : 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;
- public VoteController(AzureCosmosFactory azureCosmos, AzureServiceBusFactory serviceBus, SnowflakeId snowflakeId, DingDing dingDing, IOptionsSnapshot<Option> option,
- AzureRedisFactory azureRedis)
- {
- _azureCosmos = azureCosmos;
- _serviceBus = serviceBus;
- _snowflakeId = snowflakeId;
- _dingDing = dingDing;
- _option = option?.Value;
- _azureRedis = azureRedis;
- }
- /// <summary>
- /// 新增 或 修改投票活动
- /// </summary>
- /// <param name="request"></param>
- /// <returns></returns>
- [ProducesDefaultResponseType]
- [HttpPost("upsert")]
- public async Task<IActionResult> Upsert(Vote request)
- {
- try
- {
- //新增Vote
- 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
- {
- Vote info = await client.GetContainer("TEAMModelOS", "Common").ReadItemAsync<Vote>(request.id, new PartitionKey($"{request.code}"));
- if (info.progress.Equals("going"))
- {
- return Ok(new { v = "活动正在进行中" });
- }
- request.progress = info.progress;
- request = await client.GetContainer("TEAMModelOS", "Common").ReplaceItemAsync(request, info.id, new PartitionKey($"{info.code}"));
- }
- return Ok(new { vote = request });
- }
- catch (Exception e)
- {
- await _dingDing.SendBotMsg($"OS,{_option.Location},common/vote/save()\n{e.Message}", GroupNames.醍摩豆服務運維群組);
- return BadRequest(e.StackTrace);
- }
- }
- /// <summary>
- /// 查询投票活动,用于列表,编辑,查看
- /// </summary>
- /// <data>
- ///Vote-学校/教师编码 活动分区 !"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 已结束
- /// </data>
- /// <param name="request"></param>
- /// <returns></returns>
- [ProducesDefaultResponseType]
- [HttpPost("find")]
- public async Task<IActionResult> 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.TryGetInt64(out long data))
- {
- stimestamp = data;
- };
- };
- //默认当前时间
- var etimestamp = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds();
- if (requert.TryGetProperty("etime", out JsonElement etime))
- {
- if (!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.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<object> votes = new List<object>();
- 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($"Vote-{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())
- {
- votes.Add(obj.ToObject<JsonElement>());
- }
- //如果需要分页则跳出
- if (iscontinuation) {
- continuationToken = item.GetContinuationToken();
- break;
- }
- }
- }
- return Ok(new { votes, continuationToken });
- }
- catch (Exception ex)
- {
- await _dingDing.SendBotMsg($"OS,{_option.Location},common/vote/find()\n{ex.StackTrace}", GroupNames.醍摩豆服務運維群組);
- return BadRequest(ex.StackTrace);
- }
- }
- ///<summary>
- /// 查询投票活动,用于创建者列表,编辑,查看,投票人员查看
- /// </summary>
- /// <data>
- /// ! "id":"3c075347-75ef-4bcb-ae03-68678d02d5ef",
- /// ! "code":"Vote-hbcn"/"code":"Vote-1606285227"
- /// </data>
- /// <param name="request"></param>
- /// <returns></returns>
- [ProducesDefaultResponseType]
- [HttpPost("find-id")]
- public async Task<IActionResult> 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();
- Vote vote = await client.GetContainer("TEAMModelOS", "Common").ReadItemAsync<Vote>(id.GetString(), new PartitionKey($"{code}"));
- if (vote != null)
- {
-
- return Ok(new { vote });
- }
- else
- {
- return BadRequest("id,code不存在!");
- }
- }
- catch (Exception ex)
- {
- await _dingDing.SendBotMsg($"OS,{_option.Location},common/vote/find-id()\n{ex.Message}", GroupNames.醍摩豆服務運維群組);
- return BadRequest(ex.StackTrace);
- }
- }
- /// <summary>
- /// 删除投票活动 TODO 使用ttl删除,并处理相关事务逻辑
- /// </summary>
- /// <param name="request"></param>
- /// <returns></returns>
- [ProducesDefaultResponseType]
- [HttpPost("delete")]
- [AuthToken(Roles = "admin,teacher")]
- public async Task<IActionResult> 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();
-
- Vote vote =await client.GetContainer("TEAMModelOS", "Common").ReadItemAsync<Vote>(id.GetString(), new PartitionKey($"{code}") );
- bool flag = false;
- //必须是本人或者这个学校的管理者才能删除
- if (vote.creatorId == userid)
- {
- flag = true;
- }
- else {
- if (vote.scope == "school"&& vote.owner.Equals(school)) {
- flag = true;
- }
- }
- if (flag)
- {
- //使用ttl删除,并处理相关事务逻辑
- vote.ttl = 1;
- vote = await client.GetContainer("TEAMModelOS", "Common").ReplaceItemAsync(vote, vote.id, new PartitionKey($"{vote.code}"));
- return Ok(new { flag });
- }
- else {
- return Ok(new { flag });
- }
- //var response = await client.GetContainer("TEAMModelOS", "Common").DeleteItemStreamAsync(id.ToString(), new PartitionKey($"{code}"));
- // return Ok(new { code = response.Status });
- }
- catch (Exception e)
- {
- return BadRequest(e.StackTrace);
- }
- }
- /// <summary>
- /// 投票
- /// </summary>
- /// <redis>
- /// 投票活动选项计数器 使用SortedSet(有序集合)ZSET 数据集合 使用命令 ZINCRBY key:"Vote:Count:AAA",value:"A",score:1
- /// 投票活动 投票记录 使用Hash(哈希表)使用命令 key:"Vote:Record:AAA",feild:15283771540-20210105,value:"{"opt":["A","C","A"],"time":1608274766154}"
- /// </redis>
- /// <param name="request">
- /// !"id":"aaaa"
- /// !"code":"Vote-hbcn"/"code":"Vote-1606285227"
- /// !"option":["A","B","B"]/["1","2","3"]
- /// </param>
- /// <returns>
- /// msgid=0投票失败,1投票成功,2不在时间范围内,3不在发布范围内,4投票周期内重复投票,5周期内的可投票数不足,6未设置投票项
- /// </returns>
- [ProducesDefaultResponseType]
- [HttpPost("decide")]
- [AuthToken(Roles = "teacher,student")]
- public async Task<IActionResult> UpsertRecord(JsonElement request)
- {
- var (userid, _, _, _) = HttpContext.GetAuthTokenInfo();
- int msgid = await ActivityStudentService.Decide(request, _azureCosmos, _azureRedis, userid);
- return Ok(new { msgid });
- }
- }
- }
|