diff --git a/docs/docs.go b/docs/docs.go index df0be5b..5fa93db 100644 --- a/docs/docs.go +++ b/docs/docs.go @@ -279,6 +279,710 @@ const docTemplate = `{ } } }, + "/management/faker/{patientId}": { + "get": { + "produces": [ + "application/json" + ], + "tags": [ + "Management" + ], + "summary": "pull contact from faker", + "parameters": [ + { + "type": "string", + "description": "Token", + "name": "Token", + "in": "header", + "required": true + }, + { + "type": "integer", + "description": "Patient Id", + "name": "patientId", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/utils.GinResponse" + } + } + } + } + }, + "/management/location/": { + "get": { + "produces": [ + "application/json" + ], + "tags": [ + "Management" + ], + "summary": "list locations", + "parameters": [ + { + "type": "string", + "description": "地点的精确地址", + "name": "address", + "in": "query" + }, + { + "type": "string", + "description": "创建时间", + "name": "createTime", + "in": "query" + }, + { + "type": "integer", + "description": "创建者", + "name": "createUser", + "in": "query" + }, + { + "type": "integer", + "description": "ID", + "name": "id", + "in": "query" + }, + { + "type": "integer", + "description": "删除标志", + "name": "isDelete", + "in": "query" + }, + { + "type": "string", + "description": "修改时间", + "name": "modifyTime", + "in": "query" + }, + { + "type": "integer", + "description": "修改者", + "name": "modifyUser", + "in": "query" + }, + { + "type": "string", + "description": "地点名", + "name": "name", + "in": "query" + }, + { + "type": "string", + "description": "负责人姓名", + "name": "principalName", + "in": "query" + }, + { + "type": "string", + "description": "负责人电话", + "name": "principalPhone", + "in": "query" + }, + { + "type": "string", + "description": "地点所在地区", + "name": "region", + "in": "query" + }, + { + "type": "string", + "description": "token", + "name": "Token", + "in": "header", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "allOf": [ + { + "$ref": "#/definitions/utils.GinResponse" + }, + { + "type": "object", + "properties": { + "data": { + "$ref": "#/definitions/models.BackLocation" + } + } + } + ] + } + } + } + }, + "post": { + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "Management" + ], + "summary": "insert location", + "parameters": [ + { + "description": "location", + "name": "Location", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/models.BackLocation" + } + }, + { + "type": "string", + "description": "token", + "name": "Token", + "in": "header", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/utils.GinResponse" + } + } + } + } + }, + "/management/location/{id}": { + "delete": { + "produces": [ + "application/json" + ], + "tags": [ + "Management" + ], + "summary": "delete location", + "parameters": [ + { + "type": "string", + "description": "token", + "name": "Token", + "in": "header", + "required": true + }, + { + "type": "integer", + "description": "Id", + "name": "Id", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/utils.GinResponse" + } + } + } + } + }, + "/management/observation/": { + "get": { + "produces": [ + "application/json" + ], + "tags": [ + "Management" + ], + "summary": "list observations by query", + "parameters": [ + { + "type": "string", + "description": "token", + "name": "Token", + "in": "header", + "required": true + }, + { + "type": "string", + "description": "受观察者所在具体地点", + "name": "address", + "in": "query" + }, + { + "type": "integer", + "description": "年龄", + "name": "age", + "in": "query" + }, + { + "type": "integer", + "description": "接触者id", + "name": "contactPerson", + "in": "query" + }, + { + "type": "string", + "description": "创建时间", + "name": "createTime", + "in": "query" + }, + { + "type": "integer", + "description": "创建者", + "name": "createUser", + "in": "query" + }, + { + "type": "string", + "description": "患者健康状况转化时间", + "name": "healthChangeTime", + "in": "query" + }, + { + "type": "integer", + "description": "被观察者的疫情状况:0- 其他,1-患者,2-密接,3-次密接", + "name": "healthSituation", + "in": "query" + }, + { + "type": "integer", + "description": "ID", + "name": "id", + "in": "query" + }, + { + "type": "string", + "description": "身份证号", + "name": "identification", + "in": "query" + }, + { + "type": "integer", + "description": "删除标志", + "name": "isDelete", + "in": "query" + }, + { + "type": "integer", + "description": "受观察者被采取措施状况 :0-未采取措施,1-解除风险,2-正在治疗,3-集中隔离,4-居家隔离", + "name": "measureSituation", + "in": "query" + }, + { + "type": "string", + "description": "修改时间", + "name": "modifyTime", + "in": "query" + }, + { + "type": "integer", + "description": "修改者", + "name": "modifyUser", + "in": "query" + }, + { + "type": "string", + "description": "姓名", + "name": "name", + "in": "query" + }, + { + "type": "string", + "description": "手机号码", + "name": "phone", + "in": "query" + }, + { + "type": "string", + "description": "受观察者所在区域", + "name": "region", + "in": "query" + }, + { + "type": "integer", + "description": "性别", + "name": "sex", + "in": "query" + }, + { + "type": "string", + "description": "行程轨迹", + "name": "trajectory", + "in": "query" + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "allOf": [ + { + "$ref": "#/definitions/utils.GinResponse" + }, + { + "type": "object", + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/definitions/models.ListObservation" + } + } + } + } + ] + } + } + } + }, + "put": { + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "Management" + ], + "summary": "update observation", + "parameters": [ + { + "description": "observation", + "name": "Observation", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/models.BackObservation" + } + }, + { + "type": "string", + "description": "token", + "name": "Token", + "in": "header", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/utils.GinResponse" + } + } + } + }, + "post": { + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "Management" + ], + "summary": "insert observation", + "parameters": [ + { + "description": "observation", + "name": "Observation", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/models.BackObservation" + } + }, + { + "type": "string", + "description": "token", + "name": "Token", + "in": "header", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/utils.GinResponse" + } + } + } + } + }, + "/management/observation/tree/{id}/{direction}": { + "get": { + "produces": [ + "application/json" + ], + "tags": [ + "Management" + ], + "summary": "get transform chain by user", + "parameters": [ + { + "type": "string", + "description": "token", + "name": "Token", + "in": "header", + "required": true + }, + { + "type": "integer", + "description": "id", + "name": "id", + "in": "path", + "required": true + }, + { + "enum": [ + "up", + "down", + "all" + ], + "type": "string", + "description": "direction", + "name": "direction", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "allOf": [ + { + "$ref": "#/definitions/utils.GinResponse" + }, + { + "type": "object", + "properties": { + "data": { + "$ref": "#/definitions/models.TreeObservation" + } + } + } + ] + } + } + } + } + }, + "/management/observation/{id}": { + "get": { + "produces": [ + "application/json" + ], + "tags": [ + "Management" + ], + "summary": "get observation's info", + "parameters": [ + { + "type": "string", + "description": "token", + "name": "token", + "in": "header", + "required": true + }, + { + "type": "integer", + "description": "id", + "name": "id", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "allOf": [ + { + "$ref": "#/definitions/utils.GinResponse" + }, + { + "type": "object", + "properties": { + "data": { + "$ref": "#/definitions/models.BackObservation" + } + } + } + ] + } + } + } + } + }, + "/management/pcr/": { + "post": { + "produces": [ + "application/json" + ], + "tags": [ + "Management" + ], + "summary": "insert pcr record", + "parameters": [ + { + "description": "Pcr", + "name": "Pcr", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/models.BackPcr" + } + }, + { + "type": "string", + "description": "token", + "name": "Token", + "in": "header", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/utils.GinResponse" + } + } + } + } + }, + "/notify/count/": { + "get": { + "produces": [ + "application/json" + ], + "tags": [ + "Notification" + ], + "summary": "count the notification", + "parameters": [ + { + "type": "string", + "description": "token", + "name": "Token", + "in": "header", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/utils.GinResponse" + } + } + } + } + }, + "/notify/{index}": { + "delete": { + "produces": [ + "application/json" + ], + "tags": [ + "Notification" + ], + "summary": "delete the notify by index, if -1 delete all", + "parameters": [ + { + "type": "string", + "description": "token", + "name": "Token", + "in": "header", + "required": true + }, + { + "type": "integer", + "description": "index", + "name": "index", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/utils.GinResponse" + } + } + } + } + }, + "/notify/{start}/{end}": { + "get": { + "produces": [ + "application/json" + ], + "tags": [ + "Notification" + ], + "summary": "list the notification in the range", + "parameters": [ + { + "type": "string", + "description": "token", + "name": "Token", + "in": "header", + "required": true + }, + { + "type": "integer", + "description": "start", + "name": "start", + "in": "path", + "required": true + }, + { + "type": "integer", + "description": "end", + "name": "end", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "allOf": [ + { + "$ref": "#/definitions/utils.GinResponse" + }, + { + "type": "object", + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/definitions/models.BackNotification" + } + } + } + } + ] + } + } + } + } + }, "/statistics/china": { "get": { "produces": [ @@ -842,6 +1546,10 @@ const docTemplate = `{ "description": "文章创建者id", "type": "integer" }, + "id": { + "description": "文章id", + "type": "integer" + }, "isDelete": { "description": "删除标志", "type": "integer" @@ -872,6 +1580,187 @@ const docTemplate = `{ } } }, + "models.BackLocation": { + "type": "object", + "properties": { + "address": { + "description": "地点的精确地址", + "type": "string" + }, + "createTime": { + "description": "创建时间", + "type": "string" + }, + "createUser": { + "description": "创建者", + "type": "integer" + }, + "id": { + "description": "ID", + "type": "integer" + }, + "isDelete": { + "description": "删除标志", + "type": "integer" + }, + "modifyTime": { + "description": "修改时间", + "type": "string" + }, + "modifyUser": { + "description": "修改者", + "type": "integer" + }, + "name": { + "description": "地点名", + "type": "string" + }, + "principalName": { + "description": "负责人姓名", + "type": "string" + }, + "principalPhone": { + "description": "负责人电话", + "type": "string" + }, + "region": { + "description": "地点所在地区", + "type": "string" + } + } + }, + "models.BackNotification": { + "type": "object", + "properties": { + "content": { + "type": "string" + }, + "kind": { + "type": "string" + }, + "time": { + "type": "string" + } + } + }, + "models.BackObservation": { + "type": "object", + "properties": { + "address": { + "description": "受观察者所在具体地点", + "type": "string" + }, + "age": { + "description": "年龄", + "type": "integer" + }, + "contactPerson": { + "description": "接触者id", + "type": "integer" + }, + "createTime": { + "description": "创建时间", + "type": "string" + }, + "createUser": { + "description": "创建者", + "type": "integer" + }, + "healthChangeTime": { + "description": "患者健康状况转化时间", + "type": "string" + }, + "healthSituation": { + "description": "被观察者的疫情状况:0- 其他,1-患者,2-密接,3-次密接", + "type": "integer" + }, + "id": { + "description": "ID", + "type": "integer" + }, + "identification": { + "description": "身份证号", + "type": "string" + }, + "isDelete": { + "description": "删除标志", + "type": "integer" + }, + "measureSituation": { + "description": "受观察者被采取措施状况 :0-未采取措施,1-解除风险,2-正在治疗,3-集中隔离,4-居家隔离", + "type": "integer" + }, + "modifyTime": { + "description": "修改时间", + "type": "string" + }, + "modifyUser": { + "description": "修改者", + "type": "integer" + }, + "name": { + "description": "姓名", + "type": "string" + }, + "phone": { + "description": "手机号码", + "type": "string" + }, + "region": { + "description": "受观察者所在区域", + "type": "string" + }, + "sex": { + "description": "性别", + "type": "integer" + }, + "trajectory": { + "description": "行程轨迹", + "type": "string" + } + } + }, + "models.BackPcr": { + "type": "object", + "properties": { + "createTime": { + "description": "创建时间", + "type": "string" + }, + "createUser": { + "description": "创建者", + "type": "integer" + }, + "detectResult": { + "description": "核酸检测结果:0-未检测,1-阴性,2-阳性", + "type": "integer" + }, + "detectTime": { + "description": "核酸检测时间", + "type": "string" + }, + "id": { + "description": "ID", + "type": "integer" + }, + "isDelete": { + "description": "删除标志", + "type": "integer" + }, + "modifyTime": { + "description": "修改时间", + "type": "string" + }, + "modifyUser": { + "description": "修改者", + "type": "integer" + }, + "observation": { + "description": "观察对象ID", + "type": "integer" + } + } + }, "models.BackUser": { "type": "object", "properties": { @@ -1140,6 +2029,9 @@ const docTemplate = `{ "createTime": { "type": "string" }, + "id": { + "type": "integer" + }, "modifyTime": { "type": "string" }, @@ -1157,6 +2049,173 @@ const docTemplate = `{ } } }, + "models.ListObservation": { + "type": "object", + "properties": { + "address": { + "description": "受观察者所在具体地点", + "type": "string" + }, + "age": { + "description": "年龄", + "type": "integer" + }, + "contactPerson": { + "description": "接触者id", + "type": "integer" + }, + "createTime": { + "description": "创建时间", + "type": "string" + }, + "createUser": { + "description": "创建者", + "type": "integer" + }, + "healthChangeTime": { + "description": "患者健康状况转化时间", + "type": "string" + }, + "healthSituation": { + "description": "被观察者的疫情状况:0- 其他,1-患者,2-密接,3-次密接", + "type": "integer" + }, + "id": { + "type": "integer" + }, + "identification": { + "description": "身份证号", + "type": "string" + }, + "measureSituation": { + "description": "受观察者被采取措施状况 :0-未采取措施,1-解除风险,2-正在治疗,3-集中隔离,4-居家隔离", + "type": "integer" + }, + "modifyTime": { + "description": "修改时间", + "type": "string" + }, + "modifyUser": { + "description": "修改者", + "type": "integer" + }, + "name": { + "description": "姓名", + "type": "string" + }, + "pcrResult": { + "description": "核酸结果:0-未检测,1-阴性,2-阳性", + "type": "integer" + }, + "pcrTime": { + "description": "核酸时间", + "type": "string" + }, + "phone": { + "description": "手机号码", + "type": "string" + }, + "record": { + "description": "状态转换内容", + "type": "string" + }, + "recordTime": { + "description": "状态转换时间", + "type": "string" + }, + "region": { + "description": "受观察者所在区域", + "type": "string" + }, + "sex": { + "description": "性别", + "type": "integer" + }, + "trajectory": { + "description": "行程轨迹", + "type": "string" + } + } + }, + "models.TreeObservation": { + "type": "object", + "properties": { + "address": { + "description": "受观察者所在具体地点", + "type": "string" + }, + "age": { + "description": "年龄", + "type": "integer" + }, + "children": { + "description": "子结点", + "type": "array", + "items": { + "$ref": "#/definitions/models.TreeObservation" + } + }, + "contactPerson": { + "description": "接触者id", + "type": "integer" + }, + "createTime": { + "description": "创建时间", + "type": "string" + }, + "createUser": { + "description": "创建者", + "type": "integer" + }, + "healthChangeTime": { + "description": "患者健康状况转化时间", + "type": "string" + }, + "healthSituation": { + "description": "被观察者的疫情状况:0- 其他,1-患者,2-密接,3-次密接", + "type": "integer" + }, + "id": { + "type": "integer" + }, + "identification": { + "description": "身份证号", + "type": "string" + }, + "measureSituation": { + "description": "受观察者被采取措施状况 :0-未采取措施,1-解除风险,2-正在治疗,3-集中隔离,4-居家隔离", + "type": "integer" + }, + "modifyTime": { + "description": "修改时间", + "type": "string" + }, + "modifyUser": { + "description": "修改者", + "type": "integer" + }, + "name": { + "description": "姓名", + "type": "string" + }, + "phone": { + "description": "手机号码", + "type": "string" + }, + "region": { + "description": "受观察者所在区域", + "type": "string" + }, + "sex": { + "description": "性别", + "type": "integer" + }, + "trajectory": { + "description": "行程轨迹", + "type": "string" + } + } + }, "models.UserApprove": { "type": "object", "properties": { diff --git a/docs/swagger.json b/docs/swagger.json index ff5d86c..b1b49d1 100644 --- a/docs/swagger.json +++ b/docs/swagger.json @@ -269,6 +269,710 @@ } } }, + "/management/faker/{patientId}": { + "get": { + "produces": [ + "application/json" + ], + "tags": [ + "Management" + ], + "summary": "pull contact from faker", + "parameters": [ + { + "type": "string", + "description": "Token", + "name": "Token", + "in": "header", + "required": true + }, + { + "type": "integer", + "description": "Patient Id", + "name": "patientId", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/utils.GinResponse" + } + } + } + } + }, + "/management/location/": { + "get": { + "produces": [ + "application/json" + ], + "tags": [ + "Management" + ], + "summary": "list locations", + "parameters": [ + { + "type": "string", + "description": "地点的精确地址", + "name": "address", + "in": "query" + }, + { + "type": "string", + "description": "创建时间", + "name": "createTime", + "in": "query" + }, + { + "type": "integer", + "description": "创建者", + "name": "createUser", + "in": "query" + }, + { + "type": "integer", + "description": "ID", + "name": "id", + "in": "query" + }, + { + "type": "integer", + "description": "删除标志", + "name": "isDelete", + "in": "query" + }, + { + "type": "string", + "description": "修改时间", + "name": "modifyTime", + "in": "query" + }, + { + "type": "integer", + "description": "修改者", + "name": "modifyUser", + "in": "query" + }, + { + "type": "string", + "description": "地点名", + "name": "name", + "in": "query" + }, + { + "type": "string", + "description": "负责人姓名", + "name": "principalName", + "in": "query" + }, + { + "type": "string", + "description": "负责人电话", + "name": "principalPhone", + "in": "query" + }, + { + "type": "string", + "description": "地点所在地区", + "name": "region", + "in": "query" + }, + { + "type": "string", + "description": "token", + "name": "Token", + "in": "header", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "allOf": [ + { + "$ref": "#/definitions/utils.GinResponse" + }, + { + "type": "object", + "properties": { + "data": { + "$ref": "#/definitions/models.BackLocation" + } + } + } + ] + } + } + } + }, + "post": { + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "Management" + ], + "summary": "insert location", + "parameters": [ + { + "description": "location", + "name": "Location", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/models.BackLocation" + } + }, + { + "type": "string", + "description": "token", + "name": "Token", + "in": "header", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/utils.GinResponse" + } + } + } + } + }, + "/management/location/{id}": { + "delete": { + "produces": [ + "application/json" + ], + "tags": [ + "Management" + ], + "summary": "delete location", + "parameters": [ + { + "type": "string", + "description": "token", + "name": "Token", + "in": "header", + "required": true + }, + { + "type": "integer", + "description": "Id", + "name": "Id", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/utils.GinResponse" + } + } + } + } + }, + "/management/observation/": { + "get": { + "produces": [ + "application/json" + ], + "tags": [ + "Management" + ], + "summary": "list observations by query", + "parameters": [ + { + "type": "string", + "description": "token", + "name": "Token", + "in": "header", + "required": true + }, + { + "type": "string", + "description": "受观察者所在具体地点", + "name": "address", + "in": "query" + }, + { + "type": "integer", + "description": "年龄", + "name": "age", + "in": "query" + }, + { + "type": "integer", + "description": "接触者id", + "name": "contactPerson", + "in": "query" + }, + { + "type": "string", + "description": "创建时间", + "name": "createTime", + "in": "query" + }, + { + "type": "integer", + "description": "创建者", + "name": "createUser", + "in": "query" + }, + { + "type": "string", + "description": "患者健康状况转化时间", + "name": "healthChangeTime", + "in": "query" + }, + { + "type": "integer", + "description": "被观察者的疫情状况:0- 其他,1-患者,2-密接,3-次密接", + "name": "healthSituation", + "in": "query" + }, + { + "type": "integer", + "description": "ID", + "name": "id", + "in": "query" + }, + { + "type": "string", + "description": "身份证号", + "name": "identification", + "in": "query" + }, + { + "type": "integer", + "description": "删除标志", + "name": "isDelete", + "in": "query" + }, + { + "type": "integer", + "description": "受观察者被采取措施状况 :0-未采取措施,1-解除风险,2-正在治疗,3-集中隔离,4-居家隔离", + "name": "measureSituation", + "in": "query" + }, + { + "type": "string", + "description": "修改时间", + "name": "modifyTime", + "in": "query" + }, + { + "type": "integer", + "description": "修改者", + "name": "modifyUser", + "in": "query" + }, + { + "type": "string", + "description": "姓名", + "name": "name", + "in": "query" + }, + { + "type": "string", + "description": "手机号码", + "name": "phone", + "in": "query" + }, + { + "type": "string", + "description": "受观察者所在区域", + "name": "region", + "in": "query" + }, + { + "type": "integer", + "description": "性别", + "name": "sex", + "in": "query" + }, + { + "type": "string", + "description": "行程轨迹", + "name": "trajectory", + "in": "query" + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "allOf": [ + { + "$ref": "#/definitions/utils.GinResponse" + }, + { + "type": "object", + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/definitions/models.ListObservation" + } + } + } + } + ] + } + } + } + }, + "put": { + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "Management" + ], + "summary": "update observation", + "parameters": [ + { + "description": "observation", + "name": "Observation", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/models.BackObservation" + } + }, + { + "type": "string", + "description": "token", + "name": "Token", + "in": "header", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/utils.GinResponse" + } + } + } + }, + "post": { + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "Management" + ], + "summary": "insert observation", + "parameters": [ + { + "description": "observation", + "name": "Observation", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/models.BackObservation" + } + }, + { + "type": "string", + "description": "token", + "name": "Token", + "in": "header", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/utils.GinResponse" + } + } + } + } + }, + "/management/observation/tree/{id}/{direction}": { + "get": { + "produces": [ + "application/json" + ], + "tags": [ + "Management" + ], + "summary": "get transform chain by user", + "parameters": [ + { + "type": "string", + "description": "token", + "name": "Token", + "in": "header", + "required": true + }, + { + "type": "integer", + "description": "id", + "name": "id", + "in": "path", + "required": true + }, + { + "enum": [ + "up", + "down", + "all" + ], + "type": "string", + "description": "direction", + "name": "direction", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "allOf": [ + { + "$ref": "#/definitions/utils.GinResponse" + }, + { + "type": "object", + "properties": { + "data": { + "$ref": "#/definitions/models.TreeObservation" + } + } + } + ] + } + } + } + } + }, + "/management/observation/{id}": { + "get": { + "produces": [ + "application/json" + ], + "tags": [ + "Management" + ], + "summary": "get observation's info", + "parameters": [ + { + "type": "string", + "description": "token", + "name": "token", + "in": "header", + "required": true + }, + { + "type": "integer", + "description": "id", + "name": "id", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "allOf": [ + { + "$ref": "#/definitions/utils.GinResponse" + }, + { + "type": "object", + "properties": { + "data": { + "$ref": "#/definitions/models.BackObservation" + } + } + } + ] + } + } + } + } + }, + "/management/pcr/": { + "post": { + "produces": [ + "application/json" + ], + "tags": [ + "Management" + ], + "summary": "insert pcr record", + "parameters": [ + { + "description": "Pcr", + "name": "Pcr", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/models.BackPcr" + } + }, + { + "type": "string", + "description": "token", + "name": "Token", + "in": "header", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/utils.GinResponse" + } + } + } + } + }, + "/notify/count/": { + "get": { + "produces": [ + "application/json" + ], + "tags": [ + "Notification" + ], + "summary": "count the notification", + "parameters": [ + { + "type": "string", + "description": "token", + "name": "Token", + "in": "header", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/utils.GinResponse" + } + } + } + } + }, + "/notify/{index}": { + "delete": { + "produces": [ + "application/json" + ], + "tags": [ + "Notification" + ], + "summary": "delete the notify by index, if -1 delete all", + "parameters": [ + { + "type": "string", + "description": "token", + "name": "Token", + "in": "header", + "required": true + }, + { + "type": "integer", + "description": "index", + "name": "index", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/utils.GinResponse" + } + } + } + } + }, + "/notify/{start}/{end}": { + "get": { + "produces": [ + "application/json" + ], + "tags": [ + "Notification" + ], + "summary": "list the notification in the range", + "parameters": [ + { + "type": "string", + "description": "token", + "name": "Token", + "in": "header", + "required": true + }, + { + "type": "integer", + "description": "start", + "name": "start", + "in": "path", + "required": true + }, + { + "type": "integer", + "description": "end", + "name": "end", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "allOf": [ + { + "$ref": "#/definitions/utils.GinResponse" + }, + { + "type": "object", + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/definitions/models.BackNotification" + } + } + } + } + ] + } + } + } + } + }, "/statistics/china": { "get": { "produces": [ @@ -832,6 +1536,10 @@ "description": "文章创建者id", "type": "integer" }, + "id": { + "description": "文章id", + "type": "integer" + }, "isDelete": { "description": "删除标志", "type": "integer" @@ -862,6 +1570,187 @@ } } }, + "models.BackLocation": { + "type": "object", + "properties": { + "address": { + "description": "地点的精确地址", + "type": "string" + }, + "createTime": { + "description": "创建时间", + "type": "string" + }, + "createUser": { + "description": "创建者", + "type": "integer" + }, + "id": { + "description": "ID", + "type": "integer" + }, + "isDelete": { + "description": "删除标志", + "type": "integer" + }, + "modifyTime": { + "description": "修改时间", + "type": "string" + }, + "modifyUser": { + "description": "修改者", + "type": "integer" + }, + "name": { + "description": "地点名", + "type": "string" + }, + "principalName": { + "description": "负责人姓名", + "type": "string" + }, + "principalPhone": { + "description": "负责人电话", + "type": "string" + }, + "region": { + "description": "地点所在地区", + "type": "string" + } + } + }, + "models.BackNotification": { + "type": "object", + "properties": { + "content": { + "type": "string" + }, + "kind": { + "type": "string" + }, + "time": { + "type": "string" + } + } + }, + "models.BackObservation": { + "type": "object", + "properties": { + "address": { + "description": "受观察者所在具体地点", + "type": "string" + }, + "age": { + "description": "年龄", + "type": "integer" + }, + "contactPerson": { + "description": "接触者id", + "type": "integer" + }, + "createTime": { + "description": "创建时间", + "type": "string" + }, + "createUser": { + "description": "创建者", + "type": "integer" + }, + "healthChangeTime": { + "description": "患者健康状况转化时间", + "type": "string" + }, + "healthSituation": { + "description": "被观察者的疫情状况:0- 其他,1-患者,2-密接,3-次密接", + "type": "integer" + }, + "id": { + "description": "ID", + "type": "integer" + }, + "identification": { + "description": "身份证号", + "type": "string" + }, + "isDelete": { + "description": "删除标志", + "type": "integer" + }, + "measureSituation": { + "description": "受观察者被采取措施状况 :0-未采取措施,1-解除风险,2-正在治疗,3-集中隔离,4-居家隔离", + "type": "integer" + }, + "modifyTime": { + "description": "修改时间", + "type": "string" + }, + "modifyUser": { + "description": "修改者", + "type": "integer" + }, + "name": { + "description": "姓名", + "type": "string" + }, + "phone": { + "description": "手机号码", + "type": "string" + }, + "region": { + "description": "受观察者所在区域", + "type": "string" + }, + "sex": { + "description": "性别", + "type": "integer" + }, + "trajectory": { + "description": "行程轨迹", + "type": "string" + } + } + }, + "models.BackPcr": { + "type": "object", + "properties": { + "createTime": { + "description": "创建时间", + "type": "string" + }, + "createUser": { + "description": "创建者", + "type": "integer" + }, + "detectResult": { + "description": "核酸检测结果:0-未检测,1-阴性,2-阳性", + "type": "integer" + }, + "detectTime": { + "description": "核酸检测时间", + "type": "string" + }, + "id": { + "description": "ID", + "type": "integer" + }, + "isDelete": { + "description": "删除标志", + "type": "integer" + }, + "modifyTime": { + "description": "修改时间", + "type": "string" + }, + "modifyUser": { + "description": "修改者", + "type": "integer" + }, + "observation": { + "description": "观察对象ID", + "type": "integer" + } + } + }, "models.BackUser": { "type": "object", "properties": { @@ -1130,6 +2019,9 @@ "createTime": { "type": "string" }, + "id": { + "type": "integer" + }, "modifyTime": { "type": "string" }, @@ -1147,6 +2039,173 @@ } } }, + "models.ListObservation": { + "type": "object", + "properties": { + "address": { + "description": "受观察者所在具体地点", + "type": "string" + }, + "age": { + "description": "年龄", + "type": "integer" + }, + "contactPerson": { + "description": "接触者id", + "type": "integer" + }, + "createTime": { + "description": "创建时间", + "type": "string" + }, + "createUser": { + "description": "创建者", + "type": "integer" + }, + "healthChangeTime": { + "description": "患者健康状况转化时间", + "type": "string" + }, + "healthSituation": { + "description": "被观察者的疫情状况:0- 其他,1-患者,2-密接,3-次密接", + "type": "integer" + }, + "id": { + "type": "integer" + }, + "identification": { + "description": "身份证号", + "type": "string" + }, + "measureSituation": { + "description": "受观察者被采取措施状况 :0-未采取措施,1-解除风险,2-正在治疗,3-集中隔离,4-居家隔离", + "type": "integer" + }, + "modifyTime": { + "description": "修改时间", + "type": "string" + }, + "modifyUser": { + "description": "修改者", + "type": "integer" + }, + "name": { + "description": "姓名", + "type": "string" + }, + "pcrResult": { + "description": "核酸结果:0-未检测,1-阴性,2-阳性", + "type": "integer" + }, + "pcrTime": { + "description": "核酸时间", + "type": "string" + }, + "phone": { + "description": "手机号码", + "type": "string" + }, + "record": { + "description": "状态转换内容", + "type": "string" + }, + "recordTime": { + "description": "状态转换时间", + "type": "string" + }, + "region": { + "description": "受观察者所在区域", + "type": "string" + }, + "sex": { + "description": "性别", + "type": "integer" + }, + "trajectory": { + "description": "行程轨迹", + "type": "string" + } + } + }, + "models.TreeObservation": { + "type": "object", + "properties": { + "address": { + "description": "受观察者所在具体地点", + "type": "string" + }, + "age": { + "description": "年龄", + "type": "integer" + }, + "children": { + "description": "子结点", + "type": "array", + "items": { + "$ref": "#/definitions/models.TreeObservation" + } + }, + "contactPerson": { + "description": "接触者id", + "type": "integer" + }, + "createTime": { + "description": "创建时间", + "type": "string" + }, + "createUser": { + "description": "创建者", + "type": "integer" + }, + "healthChangeTime": { + "description": "患者健康状况转化时间", + "type": "string" + }, + "healthSituation": { + "description": "被观察者的疫情状况:0- 其他,1-患者,2-密接,3-次密接", + "type": "integer" + }, + "id": { + "type": "integer" + }, + "identification": { + "description": "身份证号", + "type": "string" + }, + "measureSituation": { + "description": "受观察者被采取措施状况 :0-未采取措施,1-解除风险,2-正在治疗,3-集中隔离,4-居家隔离", + "type": "integer" + }, + "modifyTime": { + "description": "修改时间", + "type": "string" + }, + "modifyUser": { + "description": "修改者", + "type": "integer" + }, + "name": { + "description": "姓名", + "type": "string" + }, + "phone": { + "description": "手机号码", + "type": "string" + }, + "region": { + "description": "受观察者所在区域", + "type": "string" + }, + "sex": { + "description": "性别", + "type": "integer" + }, + "trajectory": { + "description": "行程轨迹", + "type": "string" + } + } + }, "models.UserApprove": { "type": "object", "properties": { diff --git a/docs/swagger.yaml b/docs/swagger.yaml index 0d09b62..1b917ad 100644 --- a/docs/swagger.yaml +++ b/docs/swagger.yaml @@ -54,6 +54,9 @@ definitions: createUser: description: 文章创建者id type: integer + id: + description: 文章id + type: integer isDelete: description: 删除标志 type: integer @@ -76,6 +79,138 @@ definitions: description: 文章标题 type: string type: object + models.BackLocation: + properties: + address: + description: 地点的精确地址 + type: string + createTime: + description: 创建时间 + type: string + createUser: + description: 创建者 + type: integer + id: + description: ID + type: integer + isDelete: + description: 删除标志 + type: integer + modifyTime: + description: 修改时间 + type: string + modifyUser: + description: 修改者 + type: integer + name: + description: 地点名 + type: string + principalName: + description: 负责人姓名 + type: string + principalPhone: + description: 负责人电话 + type: string + region: + description: 地点所在地区 + type: string + type: object + models.BackNotification: + properties: + content: + type: string + kind: + type: string + time: + type: string + type: object + models.BackObservation: + properties: + address: + description: 受观察者所在具体地点 + type: string + age: + description: 年龄 + type: integer + contactPerson: + description: 接触者id + type: integer + createTime: + description: 创建时间 + type: string + createUser: + description: 创建者 + type: integer + healthChangeTime: + description: 患者健康状况转化时间 + type: string + healthSituation: + description: 被观察者的疫情状况:0- 其他,1-患者,2-密接,3-次密接 + type: integer + id: + description: ID + type: integer + identification: + description: 身份证号 + type: string + isDelete: + description: 删除标志 + type: integer + measureSituation: + description: 受观察者被采取措施状况 :0-未采取措施,1-解除风险,2-正在治疗,3-集中隔离,4-居家隔离 + type: integer + modifyTime: + description: 修改时间 + type: string + modifyUser: + description: 修改者 + type: integer + name: + description: 姓名 + type: string + phone: + description: 手机号码 + type: string + region: + description: 受观察者所在区域 + type: string + sex: + description: 性别 + type: integer + trajectory: + description: 行程轨迹 + type: string + type: object + models.BackPcr: + properties: + createTime: + description: 创建时间 + type: string + createUser: + description: 创建者 + type: integer + detectResult: + description: 核酸检测结果:0-未检测,1-阴性,2-阳性 + type: integer + detectTime: + description: 核酸检测时间 + type: string + id: + description: ID + type: integer + isDelete: + description: 删除标志 + type: integer + modifyTime: + description: 修改时间 + type: string + modifyUser: + description: 修改者 + type: integer + observation: + description: 观察对象ID + type: integer + type: object models.BackUser: properties: approver: @@ -256,6 +391,8 @@ definitions: type: string createTime: type: string + id: + type: integer modifyTime: type: string resume: @@ -267,6 +404,129 @@ definitions: username: type: string type: object + models.ListObservation: + properties: + address: + description: 受观察者所在具体地点 + type: string + age: + description: 年龄 + type: integer + contactPerson: + description: 接触者id + type: integer + createTime: + description: 创建时间 + type: string + createUser: + description: 创建者 + type: integer + healthChangeTime: + description: 患者健康状况转化时间 + type: string + healthSituation: + description: 被观察者的疫情状况:0- 其他,1-患者,2-密接,3-次密接 + type: integer + id: + type: integer + identification: + description: 身份证号 + type: string + measureSituation: + description: 受观察者被采取措施状况 :0-未采取措施,1-解除风险,2-正在治疗,3-集中隔离,4-居家隔离 + type: integer + modifyTime: + description: 修改时间 + type: string + modifyUser: + description: 修改者 + type: integer + name: + description: 姓名 + type: string + pcrResult: + description: 核酸结果:0-未检测,1-阴性,2-阳性 + type: integer + pcrTime: + description: 核酸时间 + type: string + phone: + description: 手机号码 + type: string + record: + description: 状态转换内容 + type: string + recordTime: + description: 状态转换时间 + type: string + region: + description: 受观察者所在区域 + type: string + sex: + description: 性别 + type: integer + trajectory: + description: 行程轨迹 + type: string + type: object + models.TreeObservation: + properties: + address: + description: 受观察者所在具体地点 + type: string + age: + description: 年龄 + type: integer + children: + description: 子结点 + items: + $ref: '#/definitions/models.TreeObservation' + type: array + contactPerson: + description: 接触者id + type: integer + createTime: + description: 创建时间 + type: string + createUser: + description: 创建者 + type: integer + healthChangeTime: + description: 患者健康状况转化时间 + type: string + healthSituation: + description: 被观察者的疫情状况:0- 其他,1-患者,2-密接,3-次密接 + type: integer + id: + type: integer + identification: + description: 身份证号 + type: string + measureSituation: + description: 受观察者被采取措施状况 :0-未采取措施,1-解除风险,2-正在治疗,3-集中隔离,4-居家隔离 + type: integer + modifyTime: + description: 修改时间 + type: string + modifyUser: + description: 修改者 + type: integer + name: + description: 姓名 + type: string + phone: + description: 手机号码 + type: string + region: + description: 受观察者所在区域 + type: string + sex: + description: 性别 + type: integer + trajectory: + description: 行程轨迹 + type: string + type: object models.UserApprove: properties: email: @@ -480,6 +740,456 @@ paths: summary: get user's articles tags: - Article + /management/faker/{patientId}: + get: + parameters: + - description: Token + in: header + name: Token + required: true + type: string + - description: Patient Id + in: path + name: patientId + required: true + type: integer + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/utils.GinResponse' + summary: pull contact from faker + tags: + - Management + /management/location/: + get: + parameters: + - description: 地点的精确地址 + in: query + name: address + type: string + - description: 创建时间 + in: query + name: createTime + type: string + - description: 创建者 + in: query + name: createUser + type: integer + - description: ID + in: query + name: id + type: integer + - description: 删除标志 + in: query + name: isDelete + type: integer + - description: 修改时间 + in: query + name: modifyTime + type: string + - description: 修改者 + in: query + name: modifyUser + type: integer + - description: 地点名 + in: query + name: name + type: string + - description: 负责人姓名 + in: query + name: principalName + type: string + - description: 负责人电话 + in: query + name: principalPhone + type: string + - description: 地点所在地区 + in: query + name: region + type: string + - description: token + in: header + name: Token + required: true + type: string + produces: + - application/json + responses: + "200": + description: OK + schema: + allOf: + - $ref: '#/definitions/utils.GinResponse' + - properties: + data: + $ref: '#/definitions/models.BackLocation' + type: object + summary: list locations + tags: + - Management + post: + consumes: + - application/json + parameters: + - description: location + in: body + name: Location + required: true + schema: + $ref: '#/definitions/models.BackLocation' + - description: token + in: header + name: Token + required: true + type: string + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/utils.GinResponse' + summary: insert location + tags: + - Management + /management/location/{id}: + delete: + parameters: + - description: token + in: header + name: Token + required: true + type: string + - description: Id + in: path + name: Id + required: true + type: integer + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/utils.GinResponse' + summary: delete location + tags: + - Management + /management/observation/: + get: + parameters: + - description: token + in: header + name: Token + required: true + type: string + - description: 受观察者所在具体地点 + in: query + name: address + type: string + - description: 年龄 + in: query + name: age + type: integer + - description: 接触者id + in: query + name: contactPerson + type: integer + - description: 创建时间 + in: query + name: createTime + type: string + - description: 创建者 + in: query + name: createUser + type: integer + - description: 患者健康状况转化时间 + in: query + name: healthChangeTime + type: string + - description: 被观察者的疫情状况:0- 其他,1-患者,2-密接,3-次密接 + in: query + name: healthSituation + type: integer + - description: ID + in: query + name: id + type: integer + - description: 身份证号 + in: query + name: identification + type: string + - description: 删除标志 + in: query + name: isDelete + type: integer + - description: 受观察者被采取措施状况 :0-未采取措施,1-解除风险,2-正在治疗,3-集中隔离,4-居家隔离 + in: query + name: measureSituation + type: integer + - description: 修改时间 + in: query + name: modifyTime + type: string + - description: 修改者 + in: query + name: modifyUser + type: integer + - description: 姓名 + in: query + name: name + type: string + - description: 手机号码 + in: query + name: phone + type: string + - description: 受观察者所在区域 + in: query + name: region + type: string + - description: 性别 + in: query + name: sex + type: integer + - description: 行程轨迹 + in: query + name: trajectory + type: string + produces: + - application/json + responses: + "200": + description: OK + schema: + allOf: + - $ref: '#/definitions/utils.GinResponse' + - properties: + data: + items: + $ref: '#/definitions/models.ListObservation' + type: array + type: object + summary: list observations by query + tags: + - Management + post: + consumes: + - application/json + parameters: + - description: observation + in: body + name: Observation + required: true + schema: + $ref: '#/definitions/models.BackObservation' + - description: token + in: header + name: Token + required: true + type: string + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/utils.GinResponse' + summary: insert observation + tags: + - Management + put: + consumes: + - application/json + parameters: + - description: observation + in: body + name: Observation + required: true + schema: + $ref: '#/definitions/models.BackObservation' + - description: token + in: header + name: Token + required: true + type: string + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/utils.GinResponse' + summary: update observation + tags: + - Management + /management/observation/{id}: + get: + parameters: + - description: token + in: header + name: token + required: true + type: string + - description: id + in: path + name: id + required: true + type: integer + produces: + - application/json + responses: + "200": + description: OK + schema: + allOf: + - $ref: '#/definitions/utils.GinResponse' + - properties: + data: + $ref: '#/definitions/models.BackObservation' + type: object + summary: get observation's info + tags: + - Management + /management/observation/tree/{id}/{direction}: + get: + parameters: + - description: token + in: header + name: Token + required: true + type: string + - description: id + in: path + name: id + required: true + type: integer + - description: direction + enum: + - up + - down + - all + in: path + name: direction + required: true + type: string + produces: + - application/json + responses: + "200": + description: OK + schema: + allOf: + - $ref: '#/definitions/utils.GinResponse' + - properties: + data: + $ref: '#/definitions/models.TreeObservation' + type: object + summary: get transform chain by user + tags: + - Management + /management/pcr/: + post: + parameters: + - description: Pcr + in: body + name: Pcr + required: true + schema: + $ref: '#/definitions/models.BackPcr' + - description: token + in: header + name: Token + required: true + type: string + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/utils.GinResponse' + summary: insert pcr record + tags: + - Management + /notify/{index}: + delete: + parameters: + - description: token + in: header + name: Token + required: true + type: string + - description: index + in: path + name: index + required: true + type: integer + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/utils.GinResponse' + summary: delete the notify by index, if -1 delete all + tags: + - Notification + /notify/{start}/{end}: + get: + parameters: + - description: token + in: header + name: Token + required: true + type: string + - description: start + in: path + name: start + required: true + type: integer + - description: end + in: path + name: end + required: true + type: integer + produces: + - application/json + responses: + "200": + description: OK + schema: + allOf: + - $ref: '#/definitions/utils.GinResponse' + - properties: + data: + items: + $ref: '#/definitions/models.BackNotification' + type: array + type: object + summary: list the notification in the range + tags: + - Notification + /notify/count/: + get: + parameters: + - description: token + in: header + name: Token + required: true + type: string + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/utils.GinResponse' + summary: count the notification + tags: + - Notification /statistics/china: get: produces: diff --git a/global/config.go b/global/config.go index b27181a..ebcf8d8 100644 --- a/global/config.go +++ b/global/config.go @@ -12,6 +12,7 @@ type ServerConfig struct { Jwt JwtConfig `yaml:"jwt"` Email EmailConfig `yaml:"email"` Bos BosConfig `yaml:"bos"` + Kafka KafkaCofig `yaml:"kafka"` } type MySQLConfig struct { @@ -46,3 +47,9 @@ type BosConfig struct { SecretKey string `yaml:"secretKey"` Domain string `yaml:"domain"` } + +type KafkaCofig struct { + Servers []string `yaml:"servers"` + Topic string `yaml:"topic"` + Partition int `yaml:"partition"` +} diff --git a/global/global.go b/global/global.go index ef3ebb4..a05986d 100644 --- a/global/global.go +++ b/global/global.go @@ -4,12 +4,11 @@ import ( "errors" "fmt" "github.com/baidubce/bce-sdk-go/services/bos" - "net/http" - "github.com/gin-gonic/gin" "github.com/go-redis/redis" "go.uber.org/zap" "gorm.io/gorm" + "net/http" ) var ( @@ -76,4 +75,5 @@ var ( "NEGATIVE": 1, "POSITIVE": 2, } + KafkaProducerChan = make(chan []byte) ) diff --git a/go.mod b/go.mod index 2947833..e5d4743 100644 --- a/go.mod +++ b/go.mod @@ -18,7 +18,12 @@ require ( github.com/KyleBanks/depth v1.2.1 // indirect github.com/PuerkitoBio/purell v1.1.1 // indirect github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 // indirect + github.com/Shopify/sarama v1.32.0 // indirect github.com/baidubce/bce-sdk-go v0.9.112 // indirect + github.com/davecgh/go-spew v1.1.1 // indirect + github.com/eapache/go-resiliency v1.2.0 // indirect + github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21 // indirect + github.com/eapache/queue v1.1.0 // indirect github.com/fsnotify/fsnotify v1.5.1 // indirect github.com/gin-contrib/sse v0.1.0 // indirect github.com/go-openapi/jsonpointer v0.19.5 // indirect @@ -31,13 +36,21 @@ require ( github.com/go-sql-driver/mysql v1.6.0 // indirect github.com/golang-jwt/jwt/v4 v4.2.0 // indirect github.com/golang/protobuf v1.5.2 // indirect + github.com/golang/snappy v0.0.4 // indirect github.com/google/uuid v1.3.0 // indirect + github.com/hashicorp/go-uuid v1.0.3 // indirect github.com/hashicorp/hcl v1.0.0 // indirect + github.com/jcmturner/aescts/v2 v2.0.0 // indirect + github.com/jcmturner/dnsutils/v2 v2.0.0 // indirect + github.com/jcmturner/gofork v1.0.0 // indirect + github.com/jcmturner/gokrb5/v8 v8.4.2 // indirect + github.com/jcmturner/rpc/v2 v2.0.3 // indirect github.com/jinzhu/inflection v1.0.0 // indirect github.com/jinzhu/now v1.1.4 // indirect github.com/jordan-wright/email v4.0.1-0.20210109023952-943e75fe5223+incompatible // indirect github.com/josharian/intern v1.0.0 // indirect github.com/json-iterator/go v1.1.12 // indirect + github.com/klauspost/compress v1.15.2 // indirect github.com/leodido/go-urn v1.2.1 // indirect github.com/magiconair/properties v1.8.5 // indirect github.com/mailru/easyjson v0.7.7 // indirect @@ -49,6 +62,8 @@ require ( github.com/onsi/ginkgo v1.16.5 // indirect github.com/onsi/gomega v1.18.0 // indirect github.com/pelletier/go-toml v1.9.4 // indirect + github.com/pierrec/lz4 v2.6.1+incompatible // indirect + github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475 // indirect github.com/spf13/afero v1.8.0 // indirect github.com/spf13/cast v1.4.1 // indirect github.com/spf13/jwalterweatherman v1.1.0 // indirect @@ -59,8 +74,8 @@ require ( github.com/ugorji/go/codec v1.2.6 // indirect go.uber.org/atomic v1.9.0 // indirect go.uber.org/multierr v1.7.0 // indirect - golang.org/x/crypto v0.0.0-20220112180741-5e0467b6c7ce // indirect - golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd // indirect + golang.org/x/crypto v0.0.0-20220427172511-eb4f295cb31f // indirect + golang.org/x/net v0.0.0-20220425223048-2871e0cb64e4 // indirect golang.org/x/sys v0.0.0-20220209214540-3681064d5158 // indirect golang.org/x/text v0.3.7 // indirect golang.org/x/tools v0.1.9 // indirect diff --git a/go.sum b/go.sum index bef7ffd..063cfb6 100644 --- a/go.sum +++ b/go.sum @@ -44,6 +44,9 @@ github.com/PuerkitoBio/purell v1.1.1 h1:WEQqlqaGbrPkxLJWfBwQmfEAE1Z7ONdDLqrN38tN github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 h1:d+Bc7a5rLufV/sSk/8dngufqelfh6jnri85riMAaF/M= github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= +github.com/Shopify/sarama v1.32.0 h1:P+RUjEaRU0GMMbYexGMDyrMkLhbbBVUVISDywi+IlFU= +github.com/Shopify/sarama v1.32.0/go.mod h1:+EmJJKZWVT/faR9RcOxJerP+LId4iWdQPBGLy1Y1Njs= +github.com/Shopify/toxiproxy/v2 v2.3.0/go.mod h1:KvQTtB6RjCJY4zqNJn7C7JDFgsG5uoHYDirfUfpIm0c= github.com/agiledragon/gomonkey/v2 v2.3.1 h1:k+UnUY0EMNYUFUAQVETGY9uUTxjMdnUkP0ARyJS1zzs= github.com/agiledragon/gomonkey/v2 v2.3.1/go.mod h1:ap1AmDzcVOAz1YpeJ3TCzIgstoaWLA6jbbgxfB4w2iY= github.com/baidubce/bce-sdk-go v0.9.112 h1:qHzFxG7fwGbXCv+1smcbWFhWl6iwoXDVzPn9TUtrlss= @@ -63,6 +66,12 @@ github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ3 github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/eapache/go-resiliency v1.2.0 h1:v7g92e/KSN71Rq7vSThKaWIq68fL4YHvWyiUKorFR1Q= +github.com/eapache/go-resiliency v1.2.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5mFgVsvEsIPBvNs= +github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21 h1:YEetp8/yCZMuEPMUDHG0CW/brkkEp8mzqk2+ODEitlw= +github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1:+020luEh2TKB4/GOp8oxxtq0Daoen/Cii55CzbTV6DU= +github.com/eapache/queue v1.1.0 h1:YOEu7KNc61ntiQlcEeUIoDTJ2o8mQznoNvUhiigpIqc= +github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I= github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= @@ -71,6 +80,8 @@ github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.m github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w= github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= +github.com/fortytw2/leaktest v1.3.0/go.mod h1:jDsjWgpAGjm2CA7WthBh/CdZYEPF31XHquHwclZch5g= +github.com/frankban/quicktest v1.14.2/go.mod h1:mgiwOwqx65TmIk1wJ6Q7wvnVMocbUorkibMOrVTHZps= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= github.com/fsnotify/fsnotify v1.5.1 h1:mZcQUHVQUQWoPXXtuf9yuEXKudkV2sx1E06UadKWpgI= @@ -144,6 +155,8 @@ github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= +github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= @@ -157,6 +170,7 @@ github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.6 h1:BKbKCqvP6I+rmFHt06ZmyQtvB8xAkWdhFyr0ZUNZcxQ= +github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= @@ -180,6 +194,12 @@ github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+ github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= github.com/googleapis/google-cloud-go-testing v0.0.0-20200911160855-bcd43fbb19e8/go.mod h1:dvDLG8qkwmyD9a/MJJN3XJcT3xFxOKAvTZGvuZmac9g= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= +github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= +github.com/gorilla/securecookie v1.1.1/go.mod h1:ra0sb63/xPlUeL+yeDciTfxMRAA+MP+HVt/4epWDjd4= +github.com/gorilla/sessions v1.2.1/go.mod h1:dk2InVEVJ0sfLlnXv9EAgkf6ecYs/i80K/zI+bUmuGM= +github.com/hashicorp/go-uuid v1.0.2/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/Co8= +github.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= @@ -187,6 +207,17 @@ github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= +github.com/jcmturner/aescts/v2 v2.0.0 h1:9YKLH6ey7H4eDBXW8khjYslgyqG2xZikXP0EQFKrle8= +github.com/jcmturner/aescts/v2 v2.0.0/go.mod h1:AiaICIRyfYg35RUkr8yESTqvSy7csK90qZ5xfvvsoNs= +github.com/jcmturner/dnsutils/v2 v2.0.0 h1:lltnkeZGL0wILNvrNiVCR6Ro5PGU/SeBvVO/8c/iPbo= +github.com/jcmturner/dnsutils/v2 v2.0.0/go.mod h1:b0TnjGOvI/n42bZa+hmXL+kFJZsFT7G4t3HTlQ184QM= +github.com/jcmturner/gofork v1.0.0 h1:J7uCkflzTEhUZ64xqKnkDxq3kzc96ajM1Gli5ktUem8= +github.com/jcmturner/gofork v1.0.0/go.mod h1:MK8+TM0La+2rjBD4jE12Kj1pCCxK7d2LK/UM3ncEo0o= +github.com/jcmturner/goidentity/v6 v6.0.1/go.mod h1:X1YW3bgtvwAXju7V3LCIMpY0Gbxyjn/mY9zx4tFonSg= +github.com/jcmturner/gokrb5/v8 v8.4.2 h1:6ZIM6b/JJN0X8UM43ZOM6Z4SJzla+a/u7scXFJzodkA= +github.com/jcmturner/gokrb5/v8 v8.4.2/go.mod h1:sb+Xq/fTY5yktf/VxLsE3wlfPqQjp0aWNYyvBVK62bc= +github.com/jcmturner/rpc/v2 v2.0.3 h1:7FXXj8Ti1IaVFpSAziCZWNzbNuZmnvw/i6CqLNdWfZY= +github.com/jcmturner/rpc/v2 v2.0.3/go.mod h1:VUJYCIDm3PVOEHw8sgt091/20OJjskO/YJki3ELg/Hc= github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E= github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc= github.com/jinzhu/now v1.1.3/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8= @@ -203,6 +234,9 @@ github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1 github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= +github.com/klauspost/compress v1.14.4/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk= +github.com/klauspost/compress v1.15.2 h1:3WH+AG7s2+T8o3nrM/8u2rdqUEcQhmga7smjrT41nAw= +github.com/klauspost/compress v1.15.2/go.mod h1:PhcZ0MbTNciWF3rruxRgKxI5NkcHHrHUDtV4Yw2GlzU= github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= @@ -260,6 +294,8 @@ github.com/otiai10/mint v1.3.0/go.mod h1:F5AjcsTsWUqX+Na9fpHb52P8pcRX2CI6A3ctIT9 github.com/otiai10/mint v1.3.3/go.mod h1:/yxELlJQ0ufhjUwhshSj+wFjZ78CnZ48/1wtmBH1OTc= github.com/pelletier/go-toml v1.9.4 h1:tjENF6MfZAg8e4ZmZTeWaWiT2vXtsoO6+iuOjFhECwM= github.com/pelletier/go-toml v1.9.4/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= +github.com/pierrec/lz4 v2.6.1+incompatible h1:9UY3+iC23yxF0UfGaYrGplQ+79Rg+h/q9FV9ix19jjM= +github.com/pierrec/lz4 v2.6.1+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= @@ -268,6 +304,8 @@ github.com/pkg/sftp v1.13.1/go.mod h1:3HaPG6Dq1ILlpPZRO0HVMrsydcdLt6HRDccSgb87qR github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475 h1:N/ElC8H3+5XpJzTSTfLsJV/mx9Q9g7kxmchpfZyxgzM= +github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= github.com/robfig/cron/v3 v3.0.1 h1:WdRxkvbJztn8LMz/QEvLN5sBU+xKpSqwwUO1Pjr4qDs= github.com/robfig/cron/v3 v3.0.1/go.mod h1:eQICP3HwyT7UooqI/z+Ov+PtYAWygg1TEWWzGIFLtro= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= @@ -276,6 +314,7 @@ github.com/rogpeppe/go-internal v1.8.0 h1:FCbCCtXNOY3UtUuHUYaghJg4y7Fd14rXifAYUA github.com/rogpeppe/go-internal v1.8.0/go.mod h1:WmiCO8CzOY8rg0OYDC4/i/2WRWAB6poM+XZ2dLUbcbE= github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= +github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= github.com/spf13/afero v1.8.0 h1:5MmtuhAgYeU6qpa7w7bP0dv6MBYuup0vekhSpSkoq60= @@ -313,6 +352,9 @@ github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLY github.com/ugorji/go/codec v1.2.6 h1:7kbGefxLoDBuYXOms4yD7223OpNMMPNPZxXk5TvFcyQ= github.com/ugorji/go/codec v1.2.6/go.mod h1:V6TCNZ4PHqoHGFZuSG1W8nrCzzdgA2DozYxWFFpvxTw= github.com/urfave/cli/v2 v2.3.0/go.mod h1:LJmUH05zAU44vOAcrfzZQKsZbVcdbOG8rtL3/XcUArI= +github.com/xdg-go/pbkdf2 v1.0.0/go.mod h1:jrpuAogTd400dnrH08LKmI/xc1MbPOebTwRqcT5RDeI= +github.com/xdg-go/scram v1.1.0/go.mod h1:1WAq6h33pAW+iRreB34OORO2Nf7qel3VV3fjBj+hCSs= +github.com/xdg-go/stringprep v1.0.2/go.mod h1:8F9zXuvzgwmyT5DUm4GUfZGDdT3W+LCvS6+da4O5kxM= github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= @@ -340,6 +382,7 @@ golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8U golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20201112155050-0c6587e931a9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= @@ -347,6 +390,9 @@ golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3 h1:0es+/5331RGQPcXlMfP+Wr golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.0.0-20220112180741-5e0467b6c7ce h1:Roh6XWxHFKrPgC/EQhVubSAGQ6Ozk6IdxHSzt1mR0EI= golang.org/x/crypto v0.0.0-20220112180741-5e0467b6c7ce/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= +golang.org/x/crypto v0.0.0-20220214200702-86341886e292/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= +golang.org/x/crypto v0.0.0-20220427172511-eb4f295cb31f h1:OeJjE6G4dgCY4PIXvIRQbE8+RX+uXZyGhUy/ksMGJoc= +golang.org/x/crypto v0.0.0-20220427172511-eb4f295cb31f/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= @@ -419,10 +465,13 @@ golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96b golang.org/x/net v0.0.0-20210421230115-4e50805a0758/go.mod h1:72T/g9IO56b78aLF+1Kcs5dz7/ng1VjMUvfKvpfy+jM= golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk= golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20220121210141-e204ce36a2ba h1:6u6sik+bn/y7vILcYkK3iwTBWN7WtBvB0+SZswQnbf8= golang.org/x/net v0.0.0-20220121210141-e204ce36a2ba/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd h1:O7DYs+zxREGLKzKoMQrtrEacpb0ZVXA5rIwylE2Xchk= golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= +golang.org/x/net v0.0.0-20220425223048-2871e0cb64e4 h1:HVyaeDAYux4pnY+D/SiwmLOR36ewZ4iGQIIrtnuCjFA= +golang.org/x/net v0.0.0-20220425223048-2871e0cb64e4/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -456,6 +505,7 @@ golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -498,12 +548,14 @@ golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220209214540-3681064d5158 h1:rm+CHSpPEEW2IsXUib1ThaHIjuBVZjxNgSKmBLFfD4c= golang.org/x/sys v0.0.0-20220209214540-3681064d5158/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= diff --git a/handler/article.go b/handler/article.go index 5306051..76e90a9 100644 --- a/handler/article.go +++ b/handler/article.go @@ -31,7 +31,7 @@ func SaveArticleHandler(c *gin.Context) { return } colMap := models.MapJ2c[models.BackArticle](jsonMap, true) - if ok := article.SaveArticle(colMap); !ok { + if ok := article.SaveArticle(claims, colMap); !ok { ServerErr(c, "Save Failed") return } @@ -90,7 +90,7 @@ func ListArticlesByUser(c *gin.Context) { func DeleteArticleHandler(c *gin.Context) { id, err := strconv.Atoi(c.Param("id")) claims := utils.ClaimsFromHeader(c) - if claims.Role == global.ROLE_ID_MAP["ADMIN"] { + if claims.Role != global.ROLE_ID_MAP["ADMIN"] { Forbidden(c) return } @@ -140,7 +140,7 @@ func GetArticleHandler(c *gin.Context) { func PublishArticleHandler(c *gin.Context) { id, err := strconv.Atoi(c.Param("id")) claims := utils.ClaimsFromHeader(c) - if claims.Role == global.ROLE_ID_MAP["ADMIN"] { + if claims.Role != global.ROLE_ID_MAP["ADMIN"] { Forbidden(c) return } diff --git a/handler/management.go b/handler/management.go index 436c3b3..2cf094c 100644 --- a/handler/management.go +++ b/handler/management.go @@ -1,6 +1,7 @@ package handler import ( + "nCovTrack-Backend/global" "nCovTrack-Backend/service/management" "nCovTrack-Backend/utils" "strconv" @@ -8,8 +9,20 @@ import ( "github.com/gin-gonic/gin" ) +//PullContactHandler pull contact from faker +// @Tags Management +// @Produce json +// @Summary pull contact from faker +// @Success 200 {object} utils.GinResponse +// @Router /management/faker/{patientId} [get] +// @Param Token header string true "Token" +// @Param patientId path int true "Patient Id" func PullContactHandler(c *gin.Context) { claims := utils.ClaimsFromHeader(c) + if claims.Role != global.ROLE_ID_MAP["ADMIN"] { + Forbidden(c) + return + } patientId, _ := strconv.Atoi(c.Param("patientId")) rowsAffected := management.PullFromFaker(claims, patientId) if rowsAffected == -1 { @@ -19,13 +32,82 @@ func PullContactHandler(c *gin.Context) { utils.Succ(c, map[string]interface{}{"pullAmount": rowsAffected}) } +//GetObservationHandler get observation's info +// @Tags Management +// @Produce json +// @Summary get observation's info +// @Success 200 {object} utils.GinResponse{data=models.BackObservation} +// @Router /management/observation/{id} [get] +// @Param token header string true "token" +// @Param id path int true "id" +func GetObservationHandler(c *gin.Context) { + claims := utils.ClaimsFromHeader(c) + allowRows := []int{global.ROLE_ID_MAP["ADMIN"], global.ROLE_ID_MAP["WORKER"], global.ROLE_ID_MAP["VOLUNTEER"]} + if !utils.Contains(allowRows, claims.Role) { + Forbidden(c) + return + } + id, _ := strconv.Atoi(c.Param("id")) + utils.Succ(c, management.GetObservation(id)) +} + +//ListObservationsHandler list observations by query +// @Tags Management +// @Produce json +// @Summary list observations by query +// @Success 200 {object} utils.GinResponse{data=[]models.ListObservation} +// @Router /management/observation/ [get] +// @Param Token header string true "token" +// @Param queries query models.BackObservation true "queries" func ListObservationsHandler(c *gin.Context) { + claims := utils.ClaimsFromHeader(c) + allowRows := []int{global.ROLE_ID_MAP["ADMIN"], global.ROLE_ID_MAP["WORKER"], global.ROLE_ID_MAP["VOLUNTEER"]} + if !utils.Contains(allowRows, claims.Role) { + Forbidden(c) + return + } jsonMap := bindQuery(c) utils.Succ(c, management.ListObservation(jsonMap)) } +//TreeifyObservationHandler get transform chain by user +// @Tags Management +// @Produce json +// @Summary get transform chain by user +// @Success 200 {object} utils.GinResponse{data=models.TreeObservation} +// @Router /management/observation/tree/{id}/{direction} [get] +// @Param Token header string true "token" +// @Param id path int true "id" +// @Param direction path string true "direction" Enums(up, down, all) +func TreeifyObservationHandler(c *gin.Context) { + claims := utils.ClaimsFromHeader(c) + allowRows := []int{global.ROLE_ID_MAP["ADMIN"], global.ROLE_ID_MAP["WORKER"], global.ROLE_ID_MAP["VOLUNTEER"]} + if !utils.Contains(allowRows, claims.Role) { + Forbidden(c) + return + } + id, _ := strconv.Atoi(c.Param("id")) + direction := c.Param("direction") + tree := management.TreeifyObservations(id, direction) + utils.Succ(c, tree) +} + +//InsertObservationHandler insert observation +// @Tags Management +// @Accept json +// @Produce json +// @Summary insert observation +// @Success 200 {object} utils.GinResponse +// @Router /management/observation/ [post] +// @Param Observation body models.BackObservation true "observation" +// @Param Token header string true "token" func InsertObservationHandler(c *gin.Context) { claims := utils.ClaimsFromHeader(c) + allowRows := []int{global.ROLE_ID_MAP["ADMIN"], global.ROLE_ID_MAP["WORKER"]} + if !utils.Contains(allowRows, claims.Role) { + Forbidden(c) + return + } observaion := bindJson(c) delete(observaion, "id") ok := management.InsertObservation(claims, observaion) @@ -36,18 +118,65 @@ func InsertObservationHandler(c *gin.Context) { } } -func GetObservationHandler(c *gin.Context) { - id, _ := strconv.Atoi(c.Param("id")) - utils.Succ(c, management.GetObservation(id)) +//UpdateObservationHandler update observation +// @Tags Management +// @Accept json +// @Produce json +// @Summary update observation +// @Success 200 {object} utils.GinResponse +// @Router /management/observation/ [put] +// @Param Observation body models.BackObservation true "observation" +// @Param Token header string true "token" +func UpdateObservationHandler(c *gin.Context) { + claims := utils.ClaimsFromHeader(c) + allowRows := []int{global.ROLE_ID_MAP["ADMIN"], global.ROLE_ID_MAP["WORKER"]} + if !utils.Contains(allowRows, claims.Role) { + Forbidden(c) + return + } + observation := bindJson(c) + ok := management.UpdateObservation(claims, observation) + if ok { + utils.Succ(c, nil) + } else { + OperationFailed(c) + } } +//ListLocationHandler list locations +// @Tags Management +// @Produce json +// @Summary list locations +// @Success 200 {object} utils.GinResponse{data=models.BackLocation} +// @Router /management/location/ [get] +// @Param queries query models.BackLocation true "queries" +// @Param Token header string true "token" func ListLocationHandler(c *gin.Context) { + claims := utils.ClaimsFromHeader(c) + allowRows := []int{global.ROLE_ID_MAP["ADMIN"], global.ROLE_ID_MAP["WORKER"], global.ROLE_ID_MAP["VOLUNTEER"]} + if !utils.Contains(allowRows, claims.Role) { + Forbidden(c) + return + } queryMap := bindQuery(c) utils.Succ(c, management.ListLocation(queryMap)) } +//InsertLocationHandler insert location +// @Tags Management +// @Accept json +// @Produce json +// @Summary insert location +// @Success 200 {object} utils.GinResponse +// @Router /management/location/ [post] +// @Param Location body models.BackLocation true "location" +// @Param Token header string true "token" func InsertLocationHandler(c *gin.Context) { claims := utils.ClaimsFromHeader(c) + if claims.Role != global.ROLE_ID_MAP["ADMIN"] { + Forbidden(c) + return + } locationMap := bindJson(c) ok := management.InsertLocation(claims, locationMap) if ok { @@ -57,7 +186,20 @@ func InsertLocationHandler(c *gin.Context) { } } +//DeleteLocationHandler delete location +// @Tags Management +// @Produce json +// @Summary delete location +// @Success 200 {object} utils.GinResponse +// @Router /management/location/{id} [delete] +// @Param Token header string true "token" +// @Param Id path int true "Id" func DeleteLocationHandler(c *gin.Context) { + claims := utils.ClaimsFromHeader(c) + if claims.Role != global.ROLE_ID_MAP["ADMIN"] { + Forbidden(c) + return + } id, _ := strconv.Atoi(c.Param("id")) ok := management.DeleteLocation(id) if ok { @@ -66,3 +208,27 @@ func DeleteLocationHandler(c *gin.Context) { OperationFailed(c) } } + +//InsertPcrHandler insert pcr record +// @Tags Management +// @Produce json +// @Summary insert pcr record +// @Success 200 {object} utils.GinResponse +// @Router /management/pcr/ [post] +// @Param Pcr body models.BackPcr true "Pcr" +// @Param Token header string true "token" +func InsertPcrHandler(c *gin.Context) { + claims := utils.ClaimsFromHeader(c) + allowRows := []int{global.ROLE_ID_MAP["ADMIN"], global.ROLE_ID_MAP["WORKER"]} + if !utils.Contains(allowRows, claims.Role) { + Forbidden(c) + return + } + jsonMap := bindJson(c) + ok := management.InsertPcr(claims, jsonMap) + if ok { + utils.Succ(c, nil) + } else { + OperationFailed(c) + } +} diff --git a/handler/notify.go b/handler/notify.go new file mode 100644 index 0000000..35954e5 --- /dev/null +++ b/handler/notify.go @@ -0,0 +1,65 @@ +package handler + +import ( + "nCovTrack-Backend/models" + "nCovTrack-Backend/service/notify" + "nCovTrack-Backend/utils" + "strconv" + "time" + + "github.com/gin-gonic/gin" +) + +//InsertNotificationHandler for test +func InsertNotificationHandler(c *gin.Context) { + sendNotify := models.SendInfo{Region: []string{"江苏 徐州"}, Channel: []int{1, 0}, Notification: models.BackNotification{Time: time.Now(), Kind: "测试", Content: "Test"}} + notify.SendNotify(sendNotify) +} + +//CountNotificationHandler count the notification +// @Tags Notification +// @Produce json +// @Summary count the notification +// @Success 200 {object} utils.GinResponse +// @Router /notify/count/ [get] +// @Param Token header string true "token" +func CountNotificationHandler(c *gin.Context) { + claims := utils.ClaimsFromHeader(c) + count := notify.QueryNotificationLen(claims.Region) + utils.Succ(c, map[string]interface{}{"count": count}) +} + +//ListNotificationHandler list the notifications in the range +// @Tags Notification +// @Produce json +// @Summary list the notification in the range +// @Success 200 {object} utils.GinResponse{data=[]models.BackNotification} +// @Router /notify/{start}/{end} [get] +// @Param Token header string true "token" +// @Param start path int true "start" +// @Param end path int true "end" +func ListNotificationHandler(c *gin.Context) { + claims := utils.ClaimsFromHeader(c) + start, _ := strconv.Atoi(c.Param("start")) + end, _ := strconv.Atoi(c.Param("end")) + notifications := notify.ListNotifycation(claims.Region, start, end) + utils.Succ(c, notifications) +} + +//DeleteNotificationHandler delete the notify by index +// @Tags Notification +// @Produce json +// @Summary delete the notify by index, if -1 delete all +// @Success 200 {object} utils.GinResponse +// @Router /notify/{index} [delete] +// @Param Token header string true "token" +// @Param index path int true "index" +func DeleteNotificationHandler(c *gin.Context) { + claims := utils.ClaimsFromHeader(c) + index, _ := strconv.Atoi(c.Param("index")) + if index == -1 { + notify.CleanNotification(claims.Region) + } + notify.DeleteNotification(claims.Region, index) + utils.Succ(c, nil) +} diff --git a/handler/user.go b/handler/user.go index 784851a..fcde352 100644 --- a/handler/user.go +++ b/handler/user.go @@ -24,11 +24,13 @@ func UserRegisterHandler(c *gin.Context) { return } registered := user.NoDuplicatePhoneOrEmail(jsonMap["phone"].(string), jsonMap["email"].(string)) - if registered { + if !registered { utils.Success(c, 200, 200, "Registered", nil) + return } colMap := models.MapJ2c[models.BackUser](jsonMap, true) user.Register(colMap) + utils.Succ(c, nil) } //UserApproveHandler admin approve account diff --git a/initialize/initialize.go b/initialize/initialize.go index 8d0e9f7..0725990 100644 --- a/initialize/initialize.go +++ b/initialize/initialize.go @@ -10,6 +10,8 @@ func Initialize() *gin.Engine { initRedis() initBos() initCron() + go initProducer() + go initConsumer() g := initRouter() initSwagger() return g diff --git a/initialize/kafka.go b/initialize/kafka.go new file mode 100644 index 0000000..42fe950 --- /dev/null +++ b/initialize/kafka.go @@ -0,0 +1,70 @@ +package initialize + +import ( + "nCovTrack-Backend/global" + "nCovTrack-Backend/service/notify" + "time" + + "github.com/Shopify/sarama" +) + +func initProducer() { + config := sarama.NewConfig() + config.Producer.RequiredAcks = sarama.WaitForAll + config.Producer.Partitioner = sarama.NewRandomPartitioner + config.Producer.Return.Successes = true + config.Producer.Return.Errors = true + producer, err := sarama.NewSyncProducer(global.ServerSettings.Kafka.Servers, config) + if err != nil { + panic("kafka init failed") + } + // defer producer.Close() + for { + select { + case value := <-global.KafkaProducerChan: + producer.SendMessage(&sarama.ProducerMessage{Topic: global.ServerSettings.Kafka.Topic, Key: nil, Value: sarama.ByteEncoder(value)}) + } + } + +} + +func initConsumer() { + config := sarama.NewConfig() + config.Consumer.Offsets.CommitInterval = 1 * time.Second + client, err := sarama.NewClient(global.ServerSettings.Kafka.Servers, config) + if err != nil { + panic("kafka init failed") + } + defer client.Close() + offsetManager, err := sarama.NewOffsetManagerFromClient("", client) + if err != nil { + panic("kafka init failed") + } + defer offsetManager.Close() + partitionOffsetManager, err := offsetManager.ManagePartition(global.ServerSettings.Kafka.Topic, int32(global.ServerSettings.Kafka.Partition)) + if err != nil { + panic("kafka init failed") + } + defer partitionOffsetManager.Close() + offsetNewest, _ := partitionOffsetManager.NextOffset() + consumer, err := sarama.NewConsumer(global.ServerSettings.Kafka.Servers, config) + if err != nil { + panic("kafka init failed") + } + defer consumer.Close() + partitionConsumer, err := consumer.ConsumePartition(global.ServerSettings.Kafka.Topic, int32(global.ServerSettings.Kafka.Partition), offsetNewest) + if err != nil { + panic("kafka init failed") + } + defer partitionConsumer.Close() + for { + select { + case msg := <-partitionConsumer.Messages(): + ConsumeFunc(msg.Value) + } + } +} + +func ConsumeFunc(msg []byte) { + notify.HandleKafkaNotify(msg) +} diff --git a/main.go b/main.go index 0a2b9f9..628a40a 100644 --- a/main.go +++ b/main.go @@ -3,11 +3,20 @@ package main import ( "nCovTrack-Backend/global" "nCovTrack-Backend/initialize" + "os" + "os/signal" + "syscall" ) // @title nCov Tracker // @version 1.0 func main() { + signals := make(chan os.Signal) + signal.Notify(signals, os.Interrupt, syscall.SIGTERM) + go func() { + <-signals + os.Exit(1) + }() gin := initialize.Initialize() gin.Run(global.GetListenOn()) } diff --git a/models/article.go b/models/article.go index bab8d76..8cac4a8 100644 --- a/models/article.go +++ b/models/article.go @@ -6,7 +6,7 @@ import ( // BackArticle article struct type BackArticle struct { - ID int `gorm:"primaryKey;column:id" json:"-"` // 文章id + ID int `gorm:"primaryKey;column:id" json:"id"` // 文章id CreateTime time.Time `gorm:"column:create_time" json:"createTime"` // 文章新建时间 CreateUser int `gorm:"column:create_user" json:"createUser"` // 文章创建者id ModifyTime time.Time `gorm:"column:modify_time" json:"modifyTime"` // 文章最后更新时间 @@ -21,7 +21,7 @@ type BackArticle struct { } type ListArticle struct { - ID int `json:"-"` + ID int `json:"id"` Username string `json:"username"` CreateTime time.Time `json:"createTime"` ModifyTime time.Time `json:"modifyTime"` @@ -34,13 +34,3 @@ type ListArticle struct { func init() { initJcMap[BackArticle]() } - -//func ArticleMapJ2c(jsonMap map[string]interface{}, ignoreNil bool) map[string]interface{} { -// colMap := make(map[string]interface{}) -// for k, v := range jsonMap { -// if colKey := colKey != "" && (!ignoreNil && v == nil) { -// colMap[colKey] = v -// } -// } -// return colMap -//} diff --git a/models/kafka.go b/models/kafka.go new file mode 100644 index 0000000..2640e7f --- /dev/null +++ b/models/kafka.go @@ -0,0 +1 @@ +package models diff --git a/models/management.go b/models/management.go index 722cf56..b3a3a66 100644 --- a/models/management.go +++ b/models/management.go @@ -63,7 +63,7 @@ type BackSituationRecord struct { IsDelete int `gorm:"column:is_delete" json:"isDelete"` // 删除标志 } -type ListObeservation struct { +type ListObservation struct { ID int `json:"id"` Name string `json:"name"` // 姓名 Age int `json:"age"` // 年龄 @@ -81,10 +81,31 @@ type ListObeservation struct { CreateTime time.Time `json:"createTime"` // 创建时间 ModifyUser int `json:"modifyUser"` // 修改者 ModifyTime time.Time `json:"modifyTime"` // 修改时间 - PcrTime time.Time `json:"pcrTime"` //核酸时间 - PcrResult int `json:"pcrResult"` //核酸结果 - RecordTime time.Time `json:"recordTime"` //状态转换时间 - Record string `json:"record"` //状态转换内容 + PcrTime time.Time `json:"pcrTime"` // 核酸时间 + PcrResult int `json:"pcrResult"` // 核酸结果:0-未检测,1-阴性,2-阳性 + RecordTime time.Time `json:"recordTime"` // 状态转换时间 + Record string `json:"record"` // 状态转换内容 +} + +type TreeObservation struct { + ID int `json:"id"` + Name string `json:"name"` // 姓名 + Age int `json:"age"` // 年龄 + Sex int `json:"sex"` // 性别 + Phone string `json:"phone"` // 手机号码 + Identification string `json:"identification"` // 身份证号 + ContactPerson int `json:"contactPerson"` // 接触者id + Region string `json:"region"` // 受观察者所在区域 + Address string `json:"address"` // 受观察者所在具体地点 + HealthSituation int `json:"healthSituation"` // 被观察者的疫情状况:0- 其他,1-患者,2-密接,3-次密接 + HealthChangeTime time.Time `json:"healthChangeTime"` // 患者健康状况转化时间 + MeasureSituation int `json:"measureSituation"` // 受观察者被采取措施状况 :0-未采取措施,1-解除风险,2-正在治疗,3-集中隔离,4-居家隔离 + Trajectory string `json:"trajectory"` // 行程轨迹 + CreateUser int `json:"createUser"` // 创建者 + CreateTime time.Time `json:"createTime"` // 创建时间 + ModifyUser int `json:"modifyUser"` // 修改者 + ModifyTime time.Time `json:"modifyTime"` // 修改时间 + Children []*TreeObservation `json:"children"` // 子结点 } type QueryObservation struct { diff --git a/models/notify.go b/models/notify.go index 430461f..d5cc073 100644 --- a/models/notify.go +++ b/models/notify.go @@ -4,6 +4,12 @@ import "time" type BackNotification struct { Time time.Time `json:"time"` - Kind int `json:"kind"` + Kind string `json:"kind"` Content string `json:"content"` } + +type SendInfo struct { + Region []string `json:"region"` + Channel []int `json:"channel"` + Notification BackNotification `json:"notification"` +} diff --git a/models/utils.go b/models/utils.go index 89fdee9..952aab1 100644 --- a/models/utils.go +++ b/models/utils.go @@ -2,11 +2,13 @@ package models import ( "fmt" - "gorm.io/gorm" "nCovTrack-Backend/global" "reflect" "regexp" + "strconv" "time" + + "gorm.io/gorm" ) var colNameReg, _ = regexp.Compile(".*column:(.*);?") @@ -124,7 +126,7 @@ func BeforeBatchSave(colMaps *[]map[string]interface{}, user int) { func Upsert[T any](colMap map[string]interface{}) (ok bool, rowsAffected int64) { var tx *gorm.DB - if colMap["id"] == nil || int(colMap["id"].(float64)) == 0 { + if colMap["id"] == nil || getMapId(colMap["id"]) == 0 { tx = global.Db.Model(new(T)).Create(colMap) } else { tx = global.Db.Model(new(T)).Where("id = ?", colMap["id"]).Updates(colMap) @@ -169,7 +171,7 @@ func DeleteById[T any](id int) (ok bool, rowsAffected int64) { if tx.Error != nil { return false, 0 } - return true, rowsAffected + return true, tx.RowsAffected } func DropById[T any](id int) { @@ -253,3 +255,17 @@ func CountByOrm(tx *gorm.DB) int64 { tx.Count(&count) return count } + +func getMapId(id interface{}) int { + switch id.(type) { + case int: + return id.(int) + case string: + id, _ := strconv.Atoi(id.(string)) + return id + case float64: + return int(id.(float64)) + default: + return -1 + } +} diff --git a/router/management.go b/router/management.go index 6ab7e52..7e73b13 100644 --- a/router/management.go +++ b/router/management.go @@ -6,12 +6,18 @@ import ( "github.com/gin-gonic/gin" ) -func managementPublicRouter(router *gin.RouterGroup) { +func managementPrivateRouter(router *gin.RouterGroup) { managementRouter := router.Group("/management") { - managementRouter.GET("/observation/contact/pull/:patientId", handler.PullContactHandler) + managementRouter.GET("/faker/:patientId", handler.PullContactHandler) managementRouter.GET("/observation", handler.ListObservationsHandler) managementRouter.POST("/observation", handler.InsertObservationHandler) managementRouter.GET("/observation/:id", handler.GetObservationHandler) + managementRouter.GET("/observation/tree/:id/:direction", handler.TreeifyObservationHandler) + managementRouter.PUT("/observation", handler.UpdateObservationHandler) + managementRouter.POST("/location/", handler.InsertLocationHandler) + managementRouter.GET("/location/", handler.ListLocationHandler) + managementRouter.DELETE("/location/", handler.DeleteLocationHandler) + managementRouter.POST("/pcr/", handler.InsertPcrHandler) } } diff --git a/router/notify.go b/router/notify.go new file mode 100644 index 0000000..b22d5c5 --- /dev/null +++ b/router/notify.go @@ -0,0 +1,17 @@ +package router + +import ( + "nCovTrack-Backend/handler" + + "github.com/gin-gonic/gin" +) + +func notifyPrivateRouter(router *gin.RouterGroup) { + notifyRouter := router.Group("/notify") + { + notifyRouter.GET("/count", handler.CountNotificationHandler) + notifyRouter.POST("/", handler.InsertNotificationHandler) + notifyRouter.GET("/:start/:end", handler.ListNotificationHandler) + notifyRouter.DELETE("/:index", handler.DeleteNotificationHandler) + } +} diff --git a/router/router.go b/router/router.go index 651d884..9f41904 100644 --- a/router/router.go +++ b/router/router.go @@ -15,12 +15,13 @@ func BusiRouter() { statisticRouter(publicRouter) articlePublicRouter(publicRouter) userPublicRouter(publicRouter) - managementPublicRouter(publicRouter) } // Private { articlePrivateRouter(privateRouter) userPrivateRouter(privateRouter) + notifyPrivateRouter(privateRouter) + managementPrivateRouter(privateRouter) } } diff --git a/service/article/article.go b/service/article/article.go index 0530e75..b819e46 100644 --- a/service/article/article.go +++ b/service/article/article.go @@ -39,8 +39,8 @@ func listArticles(isPublish int, createUser int) *[]models.ListArticle { } //SaveArticle save the articles -func SaveArticle(article map[string]interface{}) (ok bool) { - models.BeforeSave(article, -1) +func SaveArticle(claims models.TokenClaims, article map[string]interface{}) (ok bool) { + models.BeforeSave(article, claims.ID) ok, rows := models.Upsert[models.BackArticle](article) return ok && rows != 0 } diff --git a/service/management/faker.go b/service/management/faker.go index 559e973..5f7a21b 100644 --- a/service/management/faker.go +++ b/service/management/faker.go @@ -10,6 +10,7 @@ import ( "time" ) +//fakerGetRequest Get data from faker func fakerGetRequest(uri string) string { resStr := utils.GetWhioutHeader(global.FACKER_HOST + uri) var res utils.GinResponse @@ -18,6 +19,7 @@ func fakerGetRequest(uri string) string { return string(dataStr) } +//queryHotelContacts Hotel contacts func queryHotelContacts(identification string) []models.HotelContactRequest { dataStr := fakerGetRequest("query/contacts/hotel/" + identification) var data []models.HotelContactRequest @@ -28,6 +30,7 @@ func queryHotelContacts(identification string) []models.HotelContactRequest { return data } +//queryRailwayContacts Railway contacts func queryRailwayContacts(identification string) []models.RailwayContactRequest { dataStr := fakerGetRequest("query/contacts/railway/" + identification) var data []models.RailwayContactRequest @@ -38,7 +41,8 @@ func queryRailwayContacts(identification string) []models.RailwayContactRequest return data } -func queryPatients(identification string) []models.PatientRequest { +//queryPatients Patients +func QueryPatients(identification string) []models.PatientRequest { dataStr := fakerGetRequest("query/contacts/railway/" + identification) var data []models.PatientRequest err := json.Unmarshal([]byte(dataStr), &data) @@ -48,6 +52,7 @@ func queryPatients(identification string) []models.PatientRequest { return data } +//queryContacts Resolve the diffrent of hotel and railway request func queryContacts(identification string) []models.BackObservation { hotelContacts := queryHotelContacts(identification) railwayContacts := queryRailwayContacts(identification) @@ -55,11 +60,13 @@ func queryContacts(identification string) []models.BackObservation { return observations } +//splitFakerAddress Extract the region func splitFakerAddress(fakerAddress string) string { addresses := strings.Split(fakerAddress, " ") return addresses[1] + " " + addresses[2] } +//fakerContacts2Observations Convvert structs func fakerContacts2Observations(contacts any) []models.BackObservation { var observations []models.BackObservation switch contacts.(type) { diff --git a/service/management/location.go b/service/management/location.go index 5564d4e..d1333c8 100644 --- a/service/management/location.go +++ b/service/management/location.go @@ -4,6 +4,7 @@ import ( "nCovTrack-Backend/models" ) +//InsertLocation Insert locations func InsertLocation(claims models.TokenClaims, locationJMap map[string]interface{}) bool { locationCMap := models.MapJ2c[models.BackLocation](locationJMap, true) models.BeforeSave(locationCMap, claims.ID) @@ -11,11 +12,13 @@ func InsertLocation(claims models.TokenClaims, locationJMap map[string]interface return (ok && rowsAffected != 0) } +//ListLocation List locations func ListLocation(queryJMap map[string]any) *[]map[string]any { queryCMap := models.MapJ2c[models.BackLocation](queryJMap, true) return models.ListField[models.BackLocation]([]map[string]any{queryCMap}, true, "is_delete") } +//DeleteLocation Delete locations func DeleteLocation(id int) bool { ok, rowsAffected := models.DeleteById[models.BackLocation](id) return (ok && rowsAffected != 0) diff --git a/service/management/observation.go b/service/management/observation.go index 8b9e84c..2dcef7a 100644 --- a/service/management/observation.go +++ b/service/management/observation.go @@ -4,10 +4,12 @@ import ( "fmt" "nCovTrack-Backend/global" "nCovTrack-Backend/models" + "nCovTrack-Backend/service/notify" "nCovTrack-Backend/utils" "time" ) +//PullFromFaker Pull observations from faker system func PullFromFaker(claims models.TokenClaims, patientId int) int64 { // Get patient's identification by id queryMap := []map[string]interface{}{{"id": patientId}} @@ -28,31 +30,39 @@ func PullFromFaker(claims models.TokenClaims, patientId int) int64 { observationsCMap := models.MapsJ2c[models.BackObservation](observationsJMap, false) models.BeforeBatchSave(&observationsCMap, claims.ID) _, rowsAffected := models.BatchInsert[models.BackObservation](observationsCMap) - // Generate situation record + // Generate situation record and send notify to the region if rowsAffected != 0 { pullSituationRecord(claims, observations) + pullNotify(observations) } return rowsAffected } -func ListObservation(jsonMap map[string]interface{}) []models.ListObeservation { +//ListObservation list observations with query +func ListObservation(jsonMap map[string]interface{}) []models.ListObservation { colMap := models.MapJ2c[models.BackObservation](jsonMap, true) queryMap := []map[string]interface{}{colMap} return listObservation(queryMap) } +//GetObservation get observation by id func GetObservation(id int) map[string]interface{} { + // Obseration observationCMap := models.GetField[models.BackObservation]([]map[string]interface{}{{"id": id}}, true, "is_delete") observationJMap := models.MapC2j[models.BackObservation](observationCMap, true) + // Pcr record pcrRecordCMap := models.ListField[models.BackPcr]([]map[string]interface{}{{"observation": id}}, true, "is_delete") pcrRecordJMap := models.MapsC2j[models.BackPcr](*pcrRecordCMap, true) + // Situation record situationRecordCMap := models.ListField[models.BackSituationRecord]([]map[string]interface{}{{"observation": id}}, true, "is_delete") situationRecordJMap := models.MapsC2j[models.BackSituationRecord](*situationRecordCMap, true) + // Assemble observationJMap["pcrRecord"] = pcrRecordJMap observationJMap["situationRecord"] = situationRecordJMap return observationJMap } +//InsertObservation add observation func InsertObservation(claims models.TokenClaims, jsonMap map[string]interface{}) bool { colMap := models.MapJ2c[models.BackObservation](jsonMap, true) models.BeforeSave(colMap, claims.ID) @@ -65,17 +75,103 @@ func InsertObservation(claims models.TokenClaims, jsonMap map[string]interface{} } func UpdateObservation(claims models.TokenClaims, jsonMap map[string]any) bool { + // Pre actions colMap := models.MapJ2c[models.BackObservation](jsonMap, true) models.BeforeSave(colMap, claims.ID) - oldMap := models.Get[models.BackObservation]([]map[string]interface{}{{"id": jsonMap["id"]}}) - insertSituationRecord(claims, oldMap, colMap) - return false + queryMap := []map[string]interface{}{{"id": jsonMap["id"]}} + // Get old record + oldMap := models.Get[models.BackObservation](queryMap) + if oldMap == nil || len(oldMap) == 0 { + return false + } + // Deal with region update + if colMap["region"] != nil && oldMap["region"].(string) != colMap["region"].(string) { + updateObservationRegion(colMap["region"].(string)) + } + // Deal with situation update + if colMap["health_situation"] != nil && int(colMap["health_situation"].(float64)) != oldMap["health_situation"].(int) || + colMap["measure_situation"] != nil && int(colMap["measure_situation"].(float64)) != oldMap["measure_situation"].(int) { + updateSituation(claims, oldMap, colMap) + } + ok, rowsAffected := models.Update[models.BackObservation](queryMap, colMap) + return ok && rowsAffected != 0 } -// listObservation the queryMap need with table name -// @Param queryMap the colMap of models.BackObservation -func listObservation(queryMap []map[string]interface{}) []models.ListObeservation { - var observations []models.ListObeservation +//TreeifyObservations get the transmission chains of observations +// Param direction: up, down, all +func TreeifyObservations(observationId int, direction string) *models.TreeObservation { + // Get arrays form back observation + var observations []models.BackObservation + if direction != "down" { + observations = append(observations, treeifyObservations(observationId, true)...) + } + if direction != "up" { + observations = append(observations, treeifyObservations(observationId, false)...) + } + // Treeify + observationMap := map[int]*models.TreeObservation{} + for _, observation := range observations { + observationMap[observation.ID] = &models.TreeObservation{ + ID: observation.ID, + Name: observation.Name, + Age: observation.Age, + Sex: observation.Sex, + Phone: observation.Phone, + Identification: observation.Identification, + ContactPerson: observation.ContactPerson, + Region: observation.Region, + Address: observation.Address, + HealthSituation: observation.HealthSituation, + HealthChangeTime: observation.HealthChangeTime, + CreateUser: observation.CreateUser, + CreateTime: observation.CreateTime, + ModifyUser: observation.ModifyUser, + ModifyTime: observation.ModifyTime, + } + } + var rootKey int + for k := range observationMap { + parentId := observationMap[k].ContactPerson + parent := observationMap[parentId] + if parent == nil { + rootKey = k + continue + } + parent.Children = append(parent.Children, observationMap[k]) + } + return observationMap[rootKey] +} + +//treeifyObservations query tree data from db +// Param direction up: true, down: false +func treeifyObservations(observationId int, direction bool) []models.BackObservation { + var res []models.BackObservation + var directionCond string + if direction { + directionCond = "p.id = cte.contact_person" + } else { + directionCond = "cte.id = p.contact_person" + } + querySql := fmt.Sprintf(` + WITH RECURSIVE cte (id, name, age, sex, phone, identification, contact_person, region, address, health_situation, health_change_time, trajectory, create_user, modify_user, create_time, modify_time) AS ( + SELECT id, name, age, sex, phone, identification, contact_person, region, address, health_situation, health_change_time, trajectory, create_user, modify_user, create_time, modify_time + FROM back_observation + WHERE contact_person = ? + UNION ALL + SELECT p.id, p.name, p.age, p.sex, p.phone, p.identification, p.contact_person, p.region, p.address, p.health_situation, p.health_change_time, p.trajectory, p.create_user, p.modify_user, p.create_time, p.modify_time + FROM back_observation p + INNER JOIN cte ON %s + ) + SELECT * FROM cte + `, directionCond) + global.Db.Model(models.BackObservation{}).Raw(querySql, observationId).Scan(&res) + return res +} + +//listObservation the queryMap need with table name +// Param queryMap the colMap of models.BackObservation +func listObservation(queryMap []map[string]interface{}) []models.ListObservation { + var observations []models.ListObservation tx := global.Db.Model(new((models.BackObservation))). Select("back_observation.*, back_pcr.detect_time AS pcr_time, detect_result AS pcr_result," + "back_situation_record.create_time AS record_time, back_situation_record.record AS record"). @@ -94,6 +190,7 @@ func listObservation(queryMap []map[string]interface{}) []models.ListObeservatio return observations } +//pullSituationRecord push situation record after pull observations func pullSituationRecord(claims models.TokenClaims, observations []models.BackObservation) { // Query observations' id var identifications []string @@ -104,7 +201,7 @@ func pullSituationRecord(claims models.TokenClaims, observations []models.BackOb observationMaps := models.ListField[models.BackObservation](queryMap, false, "id", "identification") // Assemble records var records []models.BackSituationRecord - recordContent := record00_20() + recordContent := record___20() for _, observationMap := range *observationMaps { record := models.BackSituationRecord{Observation: observationMap["id"].(int), Record: recordContent} records = append(records, record) @@ -115,20 +212,87 @@ func pullSituationRecord(claims models.TokenClaims, observations []models.BackOb recordsCMaps := models.MapsJ2c[models.BackSituationRecord](recordsJMaps, true) models.BeforeBatchSave(&recordsCMaps, claims.ID) models.BatchInsert[models.BackSituationRecord](recordsCMaps) - // Notify the admin of pull region - // Send email to the region admin } +//pullNotify send notify after pull observations +func pullNotify(observations []models.BackObservation) { + var regions []string + for _, observation := range observations { + regions = append(regions, observation.Region) + } + regions = utils.Distinct(regions) + notification := models.BackNotification{Time: time.Now(), Kind: "疫情", Content: "出现了新的接触者,请及时登录系统进行处理"} + sendInfo := models.SendInfo{Region: regions, Channel: []int{0, 1}, Notification: notification} + notify.SendNotify(sendInfo) +} + +//updateObservationRegion send notify while update observation's region func updateObservationRegion(region string) { - // Add to notify - // Send email to the target region amdin + notification := models.BackNotification{Time: time.Now(), Kind: "疫情", Content: "本地有新的接触者,请及时登录系统进行处理"} + sendInfo := models.SendInfo{Region: []string{region}, Channel: []int{0, 1}, Notification: notification} + notify.SendNotify(sendInfo) } -func updateWhileDiagnosis(claims models.TokenClaims, patientId int) { - // Update sub contact to contact and nomeasure - // Add to notify +//updateSituation make some special resolve while situation update +func updateSituation(claims models.TokenClaims, oldObservationMap, newObservationMap map[string]interface{}) { + if newObservationMap["health_situation"] != nil { + newHealthSituation := int(newObservationMap["health_situation"].(float64)) + oldHealthSituation := oldObservationMap["health_situation"].(int) + // Update health situation change time and measure_situation + if newHealthSituation != oldHealthSituation { + newObservationMap["health_change_time"] = time.Now() + newObservationMap["measure_situation"] = 0 + } + // Deal with contact to patient + if oldHealthSituation == 2 && newHealthSituation == 1 { + // Query sub contacts + queryMap := []map[string]interface{}{{"contact_person": oldObservationMap["id"].(int)}} + subContacts := models.ListField[models.BackObservation](queryMap, false, "id", "region") + // Get reginos and assemble situation record + var regions []string + var subContactRecords []models.BackSituationRecord + for _, subContact := range *subContacts { + regions = append(regions, subContact["region"].(string)) + subContactRecord := models.BackSituationRecord{ + Observation: int(newObservationMap["id"].(float64)), + Record: record___20(), + } + subContactRecords = append(subContactRecords, subContactRecord) + } + // Update sub contact + updateMap := map[string]interface{}{ + "health_situation": 2, + "health_change_time": newObservationMap["health_change_time"], + "measure_situation": 0, + } + models.Update[models.BackObservation](queryMap, updateMap) + + // Insert subContacts' record + var recordJMaps []map[string]interface{} + utils.Strcut2Map(subContactRecords, &recordJMaps) + recordCMap := models.MapsJ2c[models.BackSituationRecord](recordJMaps, true) + models.BeforeBatchSave(&recordCMap, claims.ID) + models.BatchInsert[models.BackSituationRecord](recordCMap) + + // Send nofity + regions = utils.Distinct(regions) + notification := models.BackNotification{ + Time: newObservationMap["health_change_time"].(time.Time), + Kind: "疫情", + Content: "由于密接者转为患者,次密接者状态需要修改", + } + sendInfo := models.SendInfo{ + Region: regions, + Channel: []int{0, 1}, + Notification: notification, + } + notify.SendNotify(sendInfo) + } + insertSituationRecord(claims, oldObservationMap, newObservationMap) + } } +//insertSituationRecord insert situation record func insertSituationRecord(claims models.TokenClaims, oldObservation, newObservation map[string]interface{}) bool { var oldSituation, newSituation string if oldObservation["id"] == nil { @@ -154,20 +318,22 @@ func insertSituationRecord(claims models.TokenClaims, oldObservation, newObserva switch situationConvert { case "00_10": recordContent = record00_10() - case "00_20": - recordContent = record00_20() case "00_30": recordContent = record00_30() case "00_12": recordContent = record00_12(newObservation["region"].(string), newObservation["address"].(string)) case "10_12": recordContent = record10_12(newObservation["region"].(string), newObservation["address"].(string)) + case "00_20", "33_20", "34_20": + recordContent = record___20() case "12_01", "23_01", "24_01", "33_01", "34_01": recordContent = record___01() case "20_23", "30_33", "24_23", "34_33": recordContent = record____3(newObservation["region"].(string), newObservation["address"].(string)) case "20_24", "30_34", "23_24", "33_34": recordContent = record____4(newObservation["region"].(string), newObservation["address"].(string)) + case "23_10", "24_10", "33_10", "34_10": + recordContent = record___10() default: if oldSituation != "00" { models.Upsert[models.BackObservation](oldObservation) @@ -193,7 +359,7 @@ func record00_12(region, address string) string { date := utils.FormatDate(time.Now()) return fmt.Sprintf("%s 于 %s %s 确诊为患者", date, region, address) } -func record00_20() string { +func record___20() string { date := utils.FormatDate(time.Now()) return date + " 转为密接" } diff --git a/service/management/pcr.go b/service/management/pcr.go new file mode 100644 index 0000000..1b0b652 --- /dev/null +++ b/service/management/pcr.go @@ -0,0 +1,10 @@ +package management + +import "nCovTrack-Backend/models" + +func InsertPcr(claims models.TokenClaims, jsonMap map[string]interface{}) bool { + colMap := models.MapJ2c[models.BackPcr](jsonMap, true) + models.BeforeSave(colMap, claims.ID) + ok, rowsAffected := models.Upsert[models.BackPcr](colMap) + return ok && rowsAffected != 0 +} diff --git a/service/notify/notify.go b/service/notify/notify.go index b7e1a06..b54e9e8 100644 --- a/service/notify/notify.go +++ b/service/notify/notify.go @@ -4,35 +4,65 @@ import ( "encoding/json" "nCovTrack-Backend/global" "nCovTrack-Backend/models" - "strconv" + "nCovTrack-Backend/utils" ) +type NotifyFunc func([]string, models.BackNotification) + const ( NOTIFY_KEY = "notification_" NOTIFY_DEL_VALUE = "notify_del" ) -func InsertNotification(userId int, notification models.BackNotification) { - key := NOTIFY_KEY + strconv.Itoa(userId) - valueStr, _ := json.Marshal(notification) - global.Redis.RPush(key, valueStr) +var ( + NOTIFY_CHANNEL_FUNC_ARR = []NotifyFunc{notifyNotification, emailNotification} +) + +//emailNotification send email +func emailNotification(regions []string, notification models.BackNotification) { + queryMap := []map[string]interface{}{{"region": regions, "role": global.ROLE_ID_MAP["ADMIN"]}} + observations := models.ListField[models.BackUser](queryMap, false, "email") + var emails []string + for _, observation := range *observations { + emails = append(emails, observation["email"].(string)) + } + utils.SendEmail(notification.Kind+"通知邮件", notification.Content, emails...) } -func DeleteNotification(userId int, index int) { - key := NOTIFY_KEY + strconv.Itoa(userId) +//notifyNotification add to notify system +func notifyNotification(regions []string, notification models.BackNotification) { + valueByte, _ := json.Marshal(notification) + pipe := global.Redis.TxPipeline() + for _, region := range regions { + pipe.RPush(NOTIFY_KEY+region, valueByte) + } + pipe.Exec() +} + +//DeleteNotification delete notify by id +func DeleteNotification(region string, index int) { + key := NOTIFY_KEY + region pipe := global.Redis.TxPipeline() pipe.LSet(key, int64(index), NOTIFY_DEL_VALUE) pipe.LRem(key, 2, NOTIFY_DEL_VALUE) pipe.Exec() } -func QueryNotificationLen(userId int) int { - key := NOTIFY_KEY + strconv.Itoa(userId) +//CleanNotification delete all notify +func CleanNotification(region string) { + key := NOTIFY_KEY + region + global.Redis.Del(key) +} + +//QueryNotificationLen query the count notification +func QueryNotificationLen(region string) int { + key := NOTIFY_KEY + region return int(global.Redis.LLen(key).Val()) } -func ListNotifycation(userId int, start, end int) []models.BackNotification { - key := NOTIFY_KEY + strconv.Itoa(userId) +//ListNotifycation list the notifications ny range +func ListNotifycation(region string, start, end int) []models.BackNotification { + key := NOTIFY_KEY + region var notifications []models.BackNotification notificationStrArr := global.Redis.LRange(key, int64(start), int64(end)).Val() for _, notificationStr := range notificationStrArr { @@ -42,3 +72,18 @@ func ListNotifycation(userId int, start, end int) []models.BackNotification { } return notifications } + +//SendNotify send notify to kafka +func SendNotify(send models.SendInfo) { + sendInfo, _ := json.Marshal(send) + global.KafkaProducerChan <- sendInfo +} + +//HandleKafkaNotify handle kafka info +func HandleKafkaNotify(sendInfoByte []byte) { + var sendInfo models.SendInfo + json.Unmarshal(sendInfoByte, &sendInfo) + for _, channel := range sendInfo.Channel { + NOTIFY_CHANNEL_FUNC_ARR[channel](sendInfo.Region, sendInfo.Notification) + } +} diff --git a/service/user/user.go b/service/user/user.go index 752c1cf..982c6b3 100644 --- a/service/user/user.go +++ b/service/user/user.go @@ -2,13 +2,15 @@ package user import ( "fmt" - "github.com/golang-jwt/jwt/v4" - "github.com/google/uuid" "nCovTrack-Backend/global" "nCovTrack-Backend/models" + "nCovTrack-Backend/service/notify" "nCovTrack-Backend/utils" "strings" "time" + + "github.com/golang-jwt/jwt/v4" + "github.com/google/uuid" ) const ( @@ -50,6 +52,15 @@ func Register(user map[string]interface{}) bool { user["approver"] = 0 colMap := models.MapJ2c[models.BackUser](user, false) ok, rowsAffected := models.Upsert[models.BackUser](colMap) + var sendRegion string + if int(user["role"].(float64)) == global.ROLE_ID_MAP["ADMIN"] { + sendRegion = strings.Split(user["region"].(string), " ")[0] + } else { + sendRegion = user["region"].(string) + } + notification := models.BackNotification{Time: time.Now(), Kind: "审批", Content: "有新的注册待审批"} + sendInfo := models.SendInfo{Region: []string{sendRegion}, Channel: []int{0}, Notification: notification} + notify.SendNotify(sendInfo) if !ok || rowsAffected == 0 { return false } @@ -95,7 +106,7 @@ func ApproveRegister(claims models.TokenClaims, email string, pass bool) bool { } else { approver = -claims.ID } - updateMap := map[string]interface{}{"approver": approver} + updateMap := map[string]interface{}{"approver": approver, "modify_time": time.Now()} ok, rowsAffected := models.Update[models.BackUser](queryMap, updateMap) if !ok || rowsAffected == 0 { return false @@ -111,11 +122,12 @@ func ChangePassword(changePwd map[string]interface{}) bool { } newPassword := utils.PasswordEncrypt(changePwd["newPassword"].(string)) colMap := map[string]interface{}{ - "id": 1, + "id": 1.0, "password": newPassword, } models.BeforeSave(colMap, -1) delete(colMap, "id") + delete(colMap, "modify_user") rowAffected := global.Db.Model(models.BackUser{}).Where("email = ?", changePwd["email"]).Updates(colMap).RowsAffected if rowAffected == 0 { return false diff --git a/settings-dev.yml b/settings-dev.yml index d3810f8..e5c57e2 100644 --- a/settings-dev.yml +++ b/settings-dev.yml @@ -32,3 +32,9 @@ bos: accessKey: 90dbff87c5aa4bdbb0d7a29e130b2808 secretKey: e53a672a10294abc8ecabe1ef92625b1 domain: bj.bcebos.com + +kafka: + servers: + - myhost.fallen-angle.com:9092 + topic: ncov_track + partition: 0 diff --git a/utils/email.go b/utils/email.go index 8638213..f054fe2 100644 --- a/utils/email.go +++ b/utils/email.go @@ -8,7 +8,6 @@ import ( ) func SendEmail(subject string, text string, to ...string) bool { - //TODO: add logs e := email.Email{ From: "nCovTrack Server<1853633282@qq.com>", To: to, @@ -20,6 +19,7 @@ func SendEmail(subject string, text string, to ...string) bool { smtp.PlainAuth("", global.ServerSettings.Email.Account, global.ServerSettings.Email.Password, global.ServerSettings.Email.Host), ) if err != nil { + fmt.Println("Send failed") return false } return true diff --git a/utils/http.go b/utils/http.go index 66c49d2..4e1e5f2 100644 --- a/utils/http.go +++ b/utils/http.go @@ -31,7 +31,11 @@ func GetWithHeader(url string, header map[string]string) string { cost := time.Since(startTime) var logParams []interface{} logParams = append(logParams, - "reqest", req, + "reqest", map[string]interface{}{ + "url": req.URL, + "method": req.Method, + "header": req.Header, + }, "cost", cost.String(), ) if err != nil { diff --git a/utils/list.go b/utils/list.go index a4b7009..a74ea48 100644 --- a/utils/list.go +++ b/utils/list.go @@ -15,3 +15,24 @@ func Map[T any, V any](arr []T, fun func(item T) V) []V { } return res } + +func Distinct[T comparable](arr []T) []T { + set := map[T]interface{}{} + for _, item := range arr { + set[item] = nil + } + var res []T + for k := range set { + res = append(res, k) + } + return res +} + +func Contains[T comparable](arr []T, item T) bool { + for _, a := range arr { + if a == item { + return true + } + } + return false +} diff --git a/utils/set.go b/utils/set.go deleted file mode 100644 index 3772f26..0000000 --- a/utils/set.go +++ /dev/null @@ -1,40 +0,0 @@ -package utils - -type void struct{} - -// This is set with generic - -type Set[T comparable] struct { - setMap map[T]void -} - -func NewSet[T comparable](eles ...T) *Set[T] { - set := &Set[T]{setMap: make(map[T]void)} - set.AddAll(eles...) - return set -} - -func (set *Set[T]) Add(ele T) *Set[T] { - set.setMap[ele] = void{} - return set -} - -func (set *Set[T]) AddAll(eles ...T) *Set[T] { - for _, ele := range eles { - set.Add(ele) - } - return set -} - -func (set *Set[T]) Delete(ele T) *Set[T] { - delete(set.setMap, ele) - return set -} - -func (set *Set[T]) ToSlice() []T { - var s []T - for k, _ := range set.setMap { - s = append(s, k) - } - return s -}