first push

This commit is contained in:
桀尼龟 2025-02-20 16:18:23 +08:00
parent 28e50fa51c
commit ebf4a8dcc5
85 changed files with 22558 additions and 0 deletions

25
.gitignore vendored Normal file
View File

@ -0,0 +1,25 @@
# Binaries for programs and plugins
*.exe
*.exe~
*.dll
*.so
*.dylib
# Test binary, built with `go test -c`
*.test
# Output of the go coverage tool, specifically when used with LiteIDE
*.out
# Dependency directories (remove the comment below to include it)
# vendor/
logs.log
.idea
/docs/utils/
/cmd/logs/*
/cmd/cache/*
/cmd/log/*
/conf/conf.ini
/conf/dubbogo.yaml
/conf/sdk.yaml
/conf/log.yaml

9852
api/account/account.pb.go Normal file

File diff suppressed because it is too large Load Diff

778
api/account/account.proto Normal file
View File

@ -0,0 +1,778 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
syntax = "proto3";
package account;
import "github.com/mwitkow/go-proto-validators@v0.3.2/validator.proto";
option go_package = "./;account";
service Account {
rpc Login (LoginRequest) returns (TokenInfo) {}
rpc RefreshToken (RefreshTokenRequest) returns (TokenInfo) {} //token
rpc Logout (DecryptJwtRequest) returns (CommonResponse) {}
rpc OffLine (CommonRequest) returns (CommonResponse) {}
rpc OnlineLog (LoginInfosByUserIdRequest) returns (LoginLogsResponse) {}//id获取登录的信息
rpc OnlineLogById (OnlineLogByIdRequest) returns (LoginLog) {}//id获取登录的信息
rpc CheckPwd (CheckPwdRequest) returns (UpdateResponse) {}//
// rpc RegisterOrExist (RegistRequest) returns (RequestStatus) {}
rpc SendMsg (SendMsgRequest) returns (SendMsgStatusResponse) {} //
rpc SendCustomMsg (SendCustomMsgRequest) returns (SendMsgStatusResponse) {}//
rpc SendExCustomMsg (SendCustomMsgRequest) returns (SendMsgStatusResponse) {}//
rpc SendMsgRegister (SendMsgRequest) returns (SendMsgStatusResponse) {}//
rpc CheckMsg (CheckMsgRequest) returns (SendMsgStatusResponse) {}
rpc SendNewTelNumMsg (SendNewTelNumMsgRequest) returns (SendMsgStatusResponse) {}//,
rpc UpdateTelNum (SendNewTelNumMsgRequest) returns (SendMsgStatusResponse) {}//
rpc Authentication (AuthenticationRequest) returns (RequestStatus) {}
rpc DecryptJwt (DecryptJwtRequest) returns (DecryptJwtResponse) {}//
rpc Info (InfoRequest) returns (UserInfoResponse) {}
rpc JobNumGetInfo (JobNumGetInfoRequest) returns (InfoResponse) {}
rpc List (ListRequest) returns (ListResponse) {}
rpc RandList (ListRequest) returns (ListResponse) {}
rpc ListByIDs (ListByIDsRequest) returns (ListResponse) {}
rpc Remove (RemoveRequest) returns (RemoveResponse) {}
rpc Update (UpdateRequest) returns (UpdateResponse) {}
rpc UsersByTel (UsersByTelRequest) returns (ListResponse) {}
rpc UserByTel (UserByTelRequest) returns (InfoResponse) {}
rpc OnlySendMsg (SendMsgRequest) returns (SendMsgStatusResponse) {} //
rpc OnlyCheckMsg (CheckMsgRequest) returns (SendMsgStatusResponse) {}//
rpc MailAccountByNickName(MailAccountByNickNameRequest) returns(MaiAccountResponse){} //
rpc ListV2 (ListV2Request) returns (ListResponse) {}//
rpc QueryPersonnelWithTheSameName (QueryPersonnelWithTheSameNameRequest) returns (QueryPersonnelWithTheSameNameResponse) {}//
rpc UsersByJobNum (UsersByJobNumRequest) returns (ListResponse) {}
rpc RealName (RealNameRequest) returns (RealNameResponse) {}//
rpc Register (RegistRequest) returns (RegisterResponse) {}//
rpc UserList (UserListRequest) returns (UserListResponse) {}//
rpc CheckRealName (CheckRealNameRequest) returns (CheckRealNameResponse) {}//
}
message CheckRealNameResponse{
uint64 id =1;
string status =2;
}
message CheckRealNameRequest{
uint64 id = 1;
bool pass = 2;
string notPassRemarks = 3;
}
message UserListResponse{
uint64 count = 1;
uint64 page = 2;
uint64 pageSize = 3;
repeated UserListInfo userList = 4;
}
message UserListInfo{
uint64 id = 1;
int32 status = 2;
string name = 3;
int32 sex = 4;
string nationality = 5;
int32 documentType =6;
string certificatePicture = 7;
string validity = 8;
string placeOfResidence = 9;
string groupPhoto = 10;
string attachment = 11;
string registrationTime = 12;
string auditTime = 13;
string subNum = 14;
string notPassRemarks = 15;
string telNum = 16;
}
message UserListRequest{
string domain = 1;
string subNum = 2;
int32 realNameOrNot = 3;
string name = 4;
int32 sex = 5;
int32 documentType = 6;
int32 auditStatus = 7;
uint64 page = 8;
uint64 pageSize = 9;
}
message UserInfoResponse{
uint64 id = 1;
int32 status = 2;
string name = 3;
int32 sex = 4;
string nationality = 5;
int32 documentType =6;
string certificatePicture = 7;
string validity = 8;
string placeOfResidence = 9;
string groupPhoto = 10;
string attachment = 11;
string subNum = 12;
string notPassRemarks = 13;
}
message RealNameResponse{
uint64 id = 1;
string status = 2;
}
message RealNameRequest{
uint64 id = 1;
string name = 2;
int32 sex = 3;
string nationality = 4;
int32 documentType = 5;
string certificatePicture = 6;
string validity = 7;
string placeOfResidence = 8;
string groupPhoto = 9;
string attachment = 10;
}
message RegisterResponse{
uint64 ID = 1;
uint64 status = 2;
string token = 3;
}
message UsersByJobNumRequest{
string domain = 1 ;
repeated string jobNum =2 ;
}
message QueryPersonnelWithTheSameNameRequest{
repeated string names = 1 ;
string domain = 2 ;
string status = 3 ;
}
message QueryPersonnelWithTheSameNameResponse{
repeated string names = 1 ;
uint64 count = 2 ;
}
message ListV2Request {
string domain = 1 [json_name = "domain",(validator.field) = {string_not_empty: true,human_error: "70001"} ];
uint64 pageSize = 2 ;
uint64 page = 3 ;
string key = 4 ;
string nickName = 5;
string telNum = 6 ;
string status = 7 ;
string positionName = 8 ;
string jobNum = 9 ;
string mailAccount = 10 ;
string startEnterDate = 11 ;
string endEnterDate = 12 ;
uint32 positionId = 13 ;
uint32 departmentId = 14 ;
string departmentName =15 ;
repeated string departmentNames =16 ;
repeated uint32 positionIds =17 ;
repeated uint32 departmentIds =18 ;
}
message SendClockInWechatRequest {
string domain = 1;
string telNum =2;
string operatedAt =3;
string clockType =4;
uint32 userId =5;
string ghId =6;
string address =7;
uint64 logId = 8;
}
message MailAccountByNickNameRequest {
string Domain = 1 [json_name = "domain",(validator.field) = {string_not_empty: true,human_error: "70001"}];
string NickName = 2 [json_name = "nickName",(validator.field) = {length_lt: 20,string_not_empty: true,human_error: "70005"}];
uint32 ID = 3 ;
}
message CreateMaiAccountRequest {
uint32 ID = 1 ;
string nickName = 2;
string domain = 3 ;
}
message MaiAccountResponse {
string englishName = 1 ;
string mailAccount = 2;
}
message FddCreateUserRequest {
string openid = 1 ;
uint32 wxUserId = 2;
//string UserId = 3;
string customerId = 4;
bool isVerify = 5;
string transactionNo = 6;
}
message WxBoxUserInfoRequest {
string openid = 2 ;
string ghId = 3;
}
message WxGetOpenIdByCodeRequest {
string code = 1 ;
string state = 2 ;
string ghId = 3;
}
message WxGetOpenIdByCodeResponse {
string openId = 1 ;
}
message WxBoxTelNumByCodeResponse {
string telNum = 1 ;
}
message WxBoxUserInfo {
string openId = 1 ;
string ghId = 2 ;
bool isNew = 3 ;
UserInfo user = 4 ;
uint32 wxUserId = 5 ;
FddInfo fdd = 6 ;
}
message FddInfo {
uint64 ID = 1 ;
string customerId = 2 ;
bool isVerify = 3 ;
string transactionNo = 4;
}
message UserInfo {
uint64 ID = 1 ;
string nickName = 3 ;
string telNum = 5 ;
string avatar = 7 ;
string createAt = 8 ;
uint64 realNameID = 9 ;
string realName = 10;
string iDNum = 11;
string domain = 12;
string realIDImgA = 17;
string realIDImgB = 18;
string realNameIDName = 19;
string video = 20;
}
message CommonRequest {
uint64 ID = 1 [json_name = "ID"];
}
message WxAppRequest {
string GhId = 1 [json_name = "ID"];
}
message WxAppResponse {
string AppID = 1 [json_name = "appID"];
string AppSecret = 2 [json_name = "appSecret"];
}
message WxUserUpdateRequest {
uint32 wxID = 1 [json_name = "wxId" ,(validator.field) = {string_not_empty: true,human_error: "缺少参数wxID"} ];
uint32 userID = 2 [json_name = "userID"];
}
message WxUserOrCreateRequest {
string OpenID = 1 [json_name = "openID" ,(validator.field) = {string_not_empty: true,human_error: "缺少openid"} ];
string GhID = 2 [json_name = "ghID" ,(validator.field) = {string_not_empty: true,human_error: "缺少参数ghid"} ];
}
message WxUserResponse {
string OpenID = 1 [json_name = "openID"];
uint32 UserID = 2 [json_name = "userID"];
string GhID = 3 [json_name = "ghID"];
string RoleAuth = 4 [json_name = "roleAuth"];
uint32 ID = 5 [json_name = "ID"];
}
message LoginLogsResponse {
repeated LoginLog Data = 1 [json_name = "data"];
}
message LoginLog {
string Domain = 1 [json_name = "domain"];
uint64 ID = 2 [json_name = "ID"];
uint64 UserId = 3 [json_name = "userId"];
string Ip = 4 [json_name = "ip"];
string Token = 5 [json_name = "token"];
uint64 Status = 6 [json_name = "status"];
string ExpireDate = 7 [json_name = "expireDate"];
string LastDate = 8 [json_name = "lastDate"];
string LogoutDate = 9 [json_name = "logoutDate"];
string CreatedAt = 10 [json_name = "createdAt"];
string Address = 11 [json_name = "address"];
}
message OnlineLogByIdRequest {
string Domain = 1 [json_name = "domain"];
uint64 ID = 2 [json_name = "ID"];
}
message LoginInfosByUserIdRequest {
string Domain = 1 [json_name = "domain"];
uint64 UserId = 2 [json_name = "userId"];
}
message SendNewTelNumMsgRequest {
string Domain = 1 [json_name = "domain",(validator.field) = {string_not_empty: true,human_error: "70001"} ];
uint64 ID = 2 [json_name = "ID",(validator.field) = {string_not_empty: true,human_error: "缺少参数"} ];
string NewTelNum = 3 [json_name = "newTelNum"];
string Code = 4 [json_name = "code"];
string Project = 5 [json_name = "project"];
uint32 signNo = 6 ;
}
message UserByTelRequest {
string Domain = 1 [json_name = "domain",(validator.field) = {string_not_empty: true,human_error: "70001"} ];
string Tel =2 [json_name = "tel"];
}
message CommonResponse {
}
message UsersByTelRequest {
string Domain = 1 [json_name = "domain",(validator.field) = {string_not_empty: true,human_error: "70001"} ];
repeated string Tels =2 [json_name = "tels"];
}
message ListByIDsRequest {
string Domain = 1 [json_name = "domain",(validator.field) = {string_not_empty: true,human_error: "70001"} ];
repeated uint64 IDs = 2 [json_name = "IDs"];
uint64 OrderType = 3 [json_name = "OrderType"];
uint64 Page = 4 [json_name = "page"];
uint64 PageSize = 5 [json_name = "pageSize"];
string NickName = 6 [json_name = "nickName"];
repeated string InvitationCode = 7 [json_name = "invitationCode"];
}
message SendMsgRequest {
string Domain = 1 [json_name = "domain",(validator.field) = {string_not_empty: true,human_error: "70001"} ];
string TelNum = 2 [json_name = "telNum",(validator.field) = {regex: "^1\\d{10}$",human_error: "70002"}];
string Project = 3 [json_name = "project"];
uint32 signNo = 4;
uint32 mId = 5;
string scope = 6;//
}
message SendCustomMsgRequest {
string Domain = 1 [json_name = "domain",(validator.field) = {string_not_empty: true,human_error: "70001"} ];
string TelNum = 2 [json_name = "telNum",(validator.field) = {regex: "^1\\d{10}$",human_error: "70002"}];
string Project = 3 [json_name = "project"];
string Url = 4 [json_name = "Url"];
uint64 ID = 5 [json_name = "ID"];
uint64 MId = 6 [json_name = "mId"];
uint64 Location = 7 [json_name = "location"];
uint32 SigNo = 8 [json_name = "sigNo"];
}
message CheckMsgRequest {
string Domain = 1 [json_name = "domain",(validator.field) = {string_not_empty: true,human_error: "70001"} ];
string TelNum = 2 [json_name = "telNum",(validator.field) = {regex: "^1\\d{10}$",human_error: "70002"}];
string Code = 3 [json_name = "code",(validator.field) = {string_not_empty: true,human_error: "70003"} ];
string scope = 4;//
}
message SendMsgStatusResponse {
}
message RemoveRequest {
string Domain = 1 [json_name = "domain",(validator.field) = {string_not_empty: true,human_error: "70001"} ];
uint64 ID = 2 [json_name = "ID",(validator.field) = {int_gt: 0,human_error: "70004"} ];
string code = 3;
}
message WriteOffRequest{
uint64 id = 1;
string domain = 2;
uint64 userId = 3;
string tel = 4;
string jonNum = 5;
string userName = 6;
string enterDate = 7;
string positionName =8;
uint64 positionId = 9;
string siteName = 10;
uint64 siteId =11;
string authUrl =12;
string type =13;
uint32 status =14;
string submitDate=15;
}
message WriteOffListRequest{
uint64 page = 1;
uint64 pageSize =2;
string domain = 3;
string userName =4;
uint64 userId = 5;
uint64 siteId =6;
string type =7;
uint32 status =8;
}
message WriteOffApproveRequest{
uint64 id = 1;
uint32 status = 2;
}
message WriteOffListResponse{
int64 total = 1;
repeated WriteOffRequest writeOffList = 2;
}
message RemoveResponse {
}
message UpdateRequest {
uint64 ID = 1 [json_name = "ID"]; //ID
string Domain = 2 [json_name = "domain",(validator.field) = {string_not_empty: true,human_error: "70001"} ];
string NickName = 3 [json_name = "nickName"];
string Password = 4 [json_name = "password"]; //
string Avatar = 5 [json_name = "avatar"]; //
string Status = 7 [json_name = "status"];
string TelNum = 8 [json_name = "telNum"];
string EnterDate = 14 [json_name = "enterDate"];
Extend Extend = 17 [json_name = "extend"];
string Title = 18 [json_name = "title"];
string JobNum = 19 [json_name = "jobNum"];
string BirthDate = 20 [json_name = "birthDate"];
uint64 Sex = 21 [json_name = "sex"];
string IdNum = 22 [json_name = "idNum"];
string RealName = 23 [json_name = "realName"];
string InvitationCode = 24 [json_name = "invitationCode"];
string LeftDate = 25 [json_name = "leftDate"];
string Remark = 26 [json_name = "remark"];
string RecentImg = 27 [json_name = "recentImg"];
string ICNum = 28 [json_name = "icNum"];
string Train = 29 [json_name = "train"];
string Certificate = 30 [json_name = "certificate"];
repeated trainVideo TrainVideos = 31 [json_name = "trainVideos"];
Operator operator = 32;
string SecurityCode = 33 [json_name = "securityCode"];
}
message Operator {
uint32 ID = 1;
string Name = 2;
}
message trainVideo {
string trainUUID = 1 [json_name = "trainUUID"];
string trainDesc = 2 [json_name = "trainDesc"];
string video = 3 [json_name = "video"];
string SecurityCode = 31 [json_name = "securityCode"];
}
message UpdateResponse {
}
message PrivacyInfoRequest {
uint64 ID = 1 [json_name = "ID"]; //ID
string Domain = 2 [json_name = "domain",(validator.field) = {string_not_empty: true,human_error: "70001"} ];
string SecurityCode = 3 [json_name = "securityCode"];
}
message ListRequest {
string Domain = 1 [json_name = "domain",(validator.field) = {string_not_empty: true,human_error: "70001"} ];
uint64 PageSize = 2 [json_name = "pageSize"];
uint64 Page = 3 [json_name = "page"];
string key = 4 [json_name = "key"];
string status = 5 ;
string telNum = 6;
string startEnterDate = 7;
string endEnterDate = 8;
}
message ListResponse {
string Status = 1 [json_name = "status"];
uint64 Count = 2 [json_name = "count"];
repeated AccountInfo Data = 3 [json_name = "data"];
uint64 AllCount = 4 [json_name = "allCount"];
}
message InfoRequest {
string Domain = 1 [json_name = "domain",(validator.field) = {string_not_empty: true,human_error: "70001"} ];
uint64 ID = 2 [json_name = "id"];
string scene = 3 ;// base-user数据
}
message InfoResponse {
string Status = 1 [json_name = "status"];
AccountInfo Info = 2 [json_name = "accountInfo"];
bool IsExist = 3 [json_name = "isExist"];
}
message DecryptJwtResponse {
string Domain = 1 [json_name = "status"];
uint64 ID = 2 [json_name = "id"];
string Account = 3 [json_name = "account"];
string NickName = 4 [json_name = "nickName"];
bool IsOffline = 5 [json_name = "isOffline"];
}
message DecryptJwtRequest {
string token = 1 [json_name = "token"];
string Domain = 2 [json_name = "Domain"];
}
message CheckPwdRequest {
string Token = 1 [json_name = "token"];
string Password = 2 [json_name = "password"];
}
message AuthenticationRequest {
string Name = 1 [json_name = "name"];
string IDNum = 2 [json_name = "idNum",(validator.field) = {length_eq: 18,human_error: "70006"}];
string Token = 3 [json_name = "token"];
}
message RequestStatus {
string Status = 1 [json_name = "status"];
uint64 ID = 2 [json_name = "ID"];
bool isExist = 3;
}
message RegistRequest {
string domain = 1;
string telNum = 2;
string code = 3;
string address = 4;
string telAreaCode = 5;
}
message LoginRequest {
string Domain = 1 [json_name = "domain",(validator.field) = {string_not_empty: true,human_error: "70001"} ];
string TelNum = 2 [json_name = "telNum",(validator.field) = {regex: "^1\\d{10}$",human_error: "70002"}];
string Code = 3 [json_name = "code"];
string Password = 4 [json_name = "password"];
string Ip = 5 [json_name = "ip"];
bool passCheckIp = 6 ;
}
message TokenInfo {
AccountInfo AccountInfo = 1 [json_name = "accountInfo"];
string Token = 2 [json_name = "token"];
string RefreshToken = 4 [json_name = "refresh"];
bool IsSampleAddress = 3 [json_name = "isSampleAddress"];
string nowAddress = 5 [json_name = "nowAddress"];
}
message Extend {
string JumpTo = 1 [json_name = "jumpTo"];
string Lang = 2 [json_name = "lang"];
bool CanScan = 3 [json_name = "canScan"];
bool ResolutionRatio = 4 [json_name = "resolutionRatio"];
}
message Department {
uint64 ID = 1 [json_name = "ID"];
string Name = 2 [json_name = "name"];
}
// The response message containing the greetings
message AccountInfo {
uint64 ID = 1 [json_name = "id"];
string Account = 2 [json_name = "account"];
string NickName = 3 [json_name = "nickName"];
int64 Type = 4 [json_name = "type"];
string TelNum = 5 [json_name = "telNum"];
int32 Status = 6 [json_name = "status"];
string Avatar = 7 [json_name = "avatar"];
string CreateAt = 8 [json_name = "createAt"];
uint64 RealNameID = 9 [json_name = "realNameID"];
string RealName = 10 [json_name = "realName"];
string IDNum = 11 [json_name = "iDNum"];
string MnemonicWords = 12 [json_name = "mnemonicWords"];
uint64 IsNeedChange = 13 [json_name = "isNeedChange"];
string EnterDate = 14 [json_name = "enterDate"];
float WorkYear = 15 [json_name = "workYear"];
string Domain = 16 [json_name = "domain"];
Extend Extend = 17 [json_name = "extend"];
string JobNum = 18 [json_name = "jobNum"];
string BirthDate = 19 [json_name = "birth_date"];
uint64 Age = 20 [json_name = "age"];
uint64 Sex = 21 [json_name = "sex"];
string Title = 22 [json_name = "title"];
repeated Department Departments = 23 [json_name = "departments"];
string Ip = 24 [json_name = "ip"];
string LoginDate = 25 [json_name = "loginDate"];
string InvitationCode = 26 [json_name = "invitationCode"];
uint64 NowLogId = 27 [json_name = "nowLogId"];
bool CanScan = 28 [json_name = "canScan"];
string LeftDate = 29 [json_name = "leftDate"];
repeated PositionUser Positions = 30 [json_name = "positions"];
string Remark = 31 [json_name = "remark"];
string recentImg =32;
repeated ClockUser clocks = 33;
string mailAccount = 34;
string ICNum = 35 [json_name = "icNum"];
string englishName = 36;
string Train = 37 [json_name = "train"];
string Certificate = 38 [json_name = "certificate"];
repeated trainVideo TrainVideos = 39 [json_name = "trainVideos"];
Operator operator = 40;
string updatedAt = 41;
string SecurityCode = 42 [json_name = "securityCode"];
string BlockAddr = 43 [json_name = "blockAddr"];
}
message UserInfoV2 {
uint64 ID = 1 ;
string Account = 2 ;
string NickName = 3 ;
string TelNum = 4 ;
string Status = 5 ;
string Avatar = 6 ;
string CreateAt = 7 ;
string RealName = 8;
string IDNum = 9;
string EnterDate = 10;
Extend Extend = 11;
string JobNum = 12;
string recentImg = 13;
string mailAccount = 14;
Operator operator = 15;
string updatedAt = 16;
}
message RefreshTokenRequest {
string refreshToken = 1 ;
string domain = 2;
string ip = 3 ;
}
message PositionUser {
uint64 PositionID = 1 [json_name = "positionID"];
string PositionName = 2 [json_name = "positionName"];
uint64 DepartmentId = 3 [json_name = "departmentId"];
string DepartmentCode = 4 [json_name = "departmentCode"];
string DepartmentName = 5 [json_name = "departmentName"];
uint64 UserId = 6 [json_name = "userId"];
string UserName = 7 [json_name = "userName"];
}
message JobNumGetInfoRequest{
string jobNum = 1;
string domain = 2;
}
message CreateClockDeviceRequest{
string deviceNum =1;
string deviceName =2;
string deviceSite = 3;
}
message UpdateClockDeviceRequest{
uint64 id = 1;
string deviceNum =2;
string deviceName =3;
string deviceSite = 4;
}
message ClockDeviceResponse{
uint64 id = 1;
}
message RemoveClockDeviceRequest{
uint64 id = 1;
}
message ClockDeviceListRequest{
uint64 id =1;
string deviceSite = 2;
string deviceNum = 3;
string deviceName = 4;
uint64 page = 5 ;
uint64 pageSize = 6 ;
repeated uint64 ids = 7;
}
message ClockDeviceListResponse{
uint64 count =1;
repeated ClockDeviceInfo data = 2;
}
message ClockUser{
uint64 id =1;
string createdAt =2;
string updatedAt =3;
string deletedAt =4;
uint64 deviceID =5;
uint64 userId =6;
uint64 status =7;
ClockDeviceInfo device = 8;
}
message ClockDeviceInfo {
uint64 id = 1 ;
string createAt = 2 ;
string updateAt = 3 ;
string deviceSite = 4;
string deviceNum = 5;
string deviceName = 6;
uint64 userNum = 7;
repeated ClockUserRel data = 8 ;
}
message ClockDeviceInfoResponse{
uint64 count = 1;
repeated ClockUserRel data = 2 ;
}
message ClockUserRel {
uint64 id = 1 ;
string createAt = 2 ;
string updateAt = 3;
string nickName = 4 ;
string jobNum = 5 ;
string icNum = 6;
}
message ClockDeviceInfoRequest{
uint64 id = 1;
uint64 page = 2 ;
uint64 pageSize = 3 ;
}
message ClockBatchBindRequest{
uint64 id = 1;
repeated uint64 userId = 2;
repeated uint64 deviceId =3;
}
message ClockBatchListResponse{
repeated ClockUserDeviceBatch data = 1;
}
message ClockUserDeviceBatch{
uint64 userId = 1;
uint64 deviceId = 2;
string JobNum = 3;
string deviceNum = 4;
string deviceName = 5;
string workStatus = 6;
}
message ClockLogInfo{
uint64 id = 1;
string sn = 2;
string userId =3;
string recogType =4;
string recogTime =5;
float gender =6;
string photo =7;
float passStatus =8;
string userName =9;
float userType =10;
string confidence =11;
float reflectivity =12;
string cardNumber =13;
string passWord =14;
string qrCode =15;
string tel = 16;
string reasonVisit = 17;
string receiverTel = 18;
uint64 numOfPeople = 19;
}
message ClockLogReq{
uint64 id = 1;
uint64 page = 2;
uint64 pageSize = 3;
string userName = 4;
string recogType = 5;
string deviceNum = 6;
string recogDate = 7;
uint64 userId = 8;
}
message ClockLogListResponse{
repeated ClockLogInfo data =1;
uint64 count = 2;
}

View File

@ -0,0 +1,535 @@
// Code generated by protoc-gen-gogo. DO NOT EDIT.
// source: api/account/account.proto
package account
import (
fmt "fmt"
math "math"
proto "github.com/golang/protobuf/proto"
_ "github.com/mwitkow/go-proto-validators"
regexp "regexp"
github_com_mwitkow_go_proto_validators "github.com/mwitkow/go-proto-validators"
)
// Reference imports to suppress errors if they are not otherwise used.
var _ = proto.Marshal
var _ = fmt.Errorf
var _ = math.Inf
func (this *CheckRealNameResponse) Validate() error {
return nil
}
func (this *CheckRealNameRequest) Validate() error {
return nil
}
func (this *UserListResponse) Validate() error {
for _, item := range this.UserList {
if item != nil {
if err := github_com_mwitkow_go_proto_validators.CallValidatorIfExists(item); err != nil {
return github_com_mwitkow_go_proto_validators.FieldError("UserList", err)
}
}
}
return nil
}
func (this *UserListInfo) Validate() error {
return nil
}
func (this *UserListRequest) Validate() error {
return nil
}
func (this *UserInfoResponse) Validate() error {
return nil
}
func (this *RealNameResponse) Validate() error {
return nil
}
func (this *RealNameRequest) Validate() error {
return nil
}
func (this *RegisterResponse) Validate() error {
return nil
}
func (this *UsersByJobNumRequest) Validate() error {
return nil
}
func (this *QueryPersonnelWithTheSameNameRequest) Validate() error {
return nil
}
func (this *QueryPersonnelWithTheSameNameResponse) Validate() error {
return nil
}
func (this *ListV2Request) Validate() error {
if this.Domain == "" {
return github_com_mwitkow_go_proto_validators.FieldError("Domain", fmt.Errorf(`70001`))
}
return nil
}
func (this *SendClockInWechatRequest) Validate() error {
return nil
}
func (this *MailAccountByNickNameRequest) Validate() error {
if this.Domain == "" {
return github_com_mwitkow_go_proto_validators.FieldError("Domain", fmt.Errorf(`70001`))
}
if this.NickName == "" {
return github_com_mwitkow_go_proto_validators.FieldError("NickName", fmt.Errorf(`70005`))
}
if !(len(this.NickName) < 20) {
return github_com_mwitkow_go_proto_validators.FieldError("NickName", fmt.Errorf(`70005`))
}
return nil
}
func (this *CreateMaiAccountRequest) Validate() error {
return nil
}
func (this *MaiAccountResponse) Validate() error {
return nil
}
func (this *FddCreateUserRequest) Validate() error {
return nil
}
func (this *WxBoxUserInfoRequest) Validate() error {
return nil
}
func (this *WxGetOpenIdByCodeRequest) Validate() error {
return nil
}
func (this *WxGetOpenIdByCodeResponse) Validate() error {
return nil
}
func (this *WxBoxTelNumByCodeResponse) Validate() error {
return nil
}
func (this *WxBoxUserInfo) Validate() error {
if this.User != nil {
if err := github_com_mwitkow_go_proto_validators.CallValidatorIfExists(this.User); err != nil {
return github_com_mwitkow_go_proto_validators.FieldError("User", err)
}
}
if this.Fdd != nil {
if err := github_com_mwitkow_go_proto_validators.CallValidatorIfExists(this.Fdd); err != nil {
return github_com_mwitkow_go_proto_validators.FieldError("Fdd", err)
}
}
return nil
}
func (this *FddInfo) Validate() error {
return nil
}
func (this *UserInfo) Validate() error {
return nil
}
func (this *CommonRequest) Validate() error {
return nil
}
func (this *WxAppRequest) Validate() error {
return nil
}
func (this *WxAppResponse) Validate() error {
return nil
}
func (this *WxUserUpdateRequest) Validate() error {
return nil
}
func (this *WxUserOrCreateRequest) Validate() error {
if this.OpenID == "" {
return github_com_mwitkow_go_proto_validators.FieldError("OpenID", fmt.Errorf(`缺少openid`))
}
if this.GhID == "" {
return github_com_mwitkow_go_proto_validators.FieldError("GhID", fmt.Errorf(`缺少参数ghid`))
}
return nil
}
func (this *WxUserResponse) Validate() error {
return nil
}
func (this *LoginLogsResponse) Validate() error {
for _, item := range this.Data {
if item != nil {
if err := github_com_mwitkow_go_proto_validators.CallValidatorIfExists(item); err != nil {
return github_com_mwitkow_go_proto_validators.FieldError("Data", err)
}
}
}
return nil
}
func (this *LoginLog) Validate() error {
return nil
}
func (this *OnlineLogByIdRequest) Validate() error {
return nil
}
func (this *LoginInfosByUserIdRequest) Validate() error {
return nil
}
func (this *SendNewTelNumMsgRequest) Validate() error {
if this.Domain == "" {
return github_com_mwitkow_go_proto_validators.FieldError("Domain", fmt.Errorf(`70001`))
}
return nil
}
func (this *UserByTelRequest) Validate() error {
if this.Domain == "" {
return github_com_mwitkow_go_proto_validators.FieldError("Domain", fmt.Errorf(`70001`))
}
return nil
}
func (this *CommonResponse) Validate() error {
return nil
}
func (this *UsersByTelRequest) Validate() error {
if this.Domain == "" {
return github_com_mwitkow_go_proto_validators.FieldError("Domain", fmt.Errorf(`70001`))
}
return nil
}
func (this *ListByIDsRequest) Validate() error {
if this.Domain == "" {
return github_com_mwitkow_go_proto_validators.FieldError("Domain", fmt.Errorf(`70001`))
}
return nil
}
var _regex_SendMsgRequest_TelNum = regexp.MustCompile(`^1\d{10}$`)
func (this *SendMsgRequest) Validate() error {
if this.Domain == "" {
return github_com_mwitkow_go_proto_validators.FieldError("Domain", fmt.Errorf(`70001`))
}
if !_regex_SendMsgRequest_TelNum.MatchString(this.TelNum) {
return github_com_mwitkow_go_proto_validators.FieldError("TelNum", fmt.Errorf(`70002`))
}
return nil
}
var _regex_SendCustomMsgRequest_TelNum = regexp.MustCompile(`^1\d{10}$`)
func (this *SendCustomMsgRequest) Validate() error {
if this.Domain == "" {
return github_com_mwitkow_go_proto_validators.FieldError("Domain", fmt.Errorf(`70001`))
}
if !_regex_SendCustomMsgRequest_TelNum.MatchString(this.TelNum) {
return github_com_mwitkow_go_proto_validators.FieldError("TelNum", fmt.Errorf(`70002`))
}
return nil
}
var _regex_CheckMsgRequest_TelNum = regexp.MustCompile(`^1\d{10}$`)
func (this *CheckMsgRequest) Validate() error {
if this.Domain == "" {
return github_com_mwitkow_go_proto_validators.FieldError("Domain", fmt.Errorf(`70001`))
}
if !_regex_CheckMsgRequest_TelNum.MatchString(this.TelNum) {
return github_com_mwitkow_go_proto_validators.FieldError("TelNum", fmt.Errorf(`70002`))
}
if this.Code == "" {
return github_com_mwitkow_go_proto_validators.FieldError("Code", fmt.Errorf(`70003`))
}
return nil
}
func (this *SendMsgStatusResponse) Validate() error {
return nil
}
func (this *RemoveRequest) Validate() error {
if this.Domain == "" {
return github_com_mwitkow_go_proto_validators.FieldError("Domain", fmt.Errorf(`70001`))
}
if !(this.ID > 0) {
return github_com_mwitkow_go_proto_validators.FieldError("ID", fmt.Errorf(`70004`))
}
return nil
}
func (this *WriteOffRequest) Validate() error {
return nil
}
func (this *WriteOffListRequest) Validate() error {
return nil
}
func (this *WriteOffApproveRequest) Validate() error {
return nil
}
func (this *WriteOffListResponse) Validate() error {
for _, item := range this.WriteOffList {
if item != nil {
if err := github_com_mwitkow_go_proto_validators.CallValidatorIfExists(item); err != nil {
return github_com_mwitkow_go_proto_validators.FieldError("WriteOffList", err)
}
}
}
return nil
}
func (this *RemoveResponse) Validate() error {
return nil
}
func (this *UpdateRequest) Validate() error {
if this.Domain == "" {
return github_com_mwitkow_go_proto_validators.FieldError("Domain", fmt.Errorf(`70001`))
}
if this.Extend != nil {
if err := github_com_mwitkow_go_proto_validators.CallValidatorIfExists(this.Extend); err != nil {
return github_com_mwitkow_go_proto_validators.FieldError("Extend", err)
}
}
for _, item := range this.TrainVideos {
if item != nil {
if err := github_com_mwitkow_go_proto_validators.CallValidatorIfExists(item); err != nil {
return github_com_mwitkow_go_proto_validators.FieldError("TrainVideos", err)
}
}
}
if this.Operator != nil {
if err := github_com_mwitkow_go_proto_validators.CallValidatorIfExists(this.Operator); err != nil {
return github_com_mwitkow_go_proto_validators.FieldError("Operator", err)
}
}
return nil
}
func (this *Operator) Validate() error {
return nil
}
func (this *TrainVideo) Validate() error {
return nil
}
func (this *UpdateResponse) Validate() error {
return nil
}
func (this *PrivacyInfoRequest) Validate() error {
if this.Domain == "" {
return github_com_mwitkow_go_proto_validators.FieldError("Domain", fmt.Errorf(`70001`))
}
return nil
}
func (this *ListRequest) Validate() error {
if this.Domain == "" {
return github_com_mwitkow_go_proto_validators.FieldError("Domain", fmt.Errorf(`70001`))
}
return nil
}
func (this *ListResponse) Validate() error {
for _, item := range this.Data {
if item != nil {
if err := github_com_mwitkow_go_proto_validators.CallValidatorIfExists(item); err != nil {
return github_com_mwitkow_go_proto_validators.FieldError("Data", err)
}
}
}
return nil
}
func (this *InfoRequest) Validate() error {
if this.Domain == "" {
return github_com_mwitkow_go_proto_validators.FieldError("Domain", fmt.Errorf(`70001`))
}
return nil
}
func (this *InfoResponse) Validate() error {
if this.Info != nil {
if err := github_com_mwitkow_go_proto_validators.CallValidatorIfExists(this.Info); err != nil {
return github_com_mwitkow_go_proto_validators.FieldError("Info", err)
}
}
return nil
}
func (this *DecryptJwtResponse) Validate() error {
return nil
}
func (this *DecryptJwtRequest) Validate() error {
return nil
}
func (this *CheckPwdRequest) Validate() error {
return nil
}
func (this *AuthenticationRequest) Validate() error {
if !(len(this.IDNum) == 18) {
return github_com_mwitkow_go_proto_validators.FieldError("IDNum", fmt.Errorf(`70006`))
}
return nil
}
func (this *RequestStatus) Validate() error {
return nil
}
func (this *RegistRequest) Validate() error {
return nil
}
var _regex_LoginRequest_TelNum = regexp.MustCompile(`^1\d{10}$`)
func (this *LoginRequest) Validate() error {
if this.Domain == "" {
return github_com_mwitkow_go_proto_validators.FieldError("Domain", fmt.Errorf(`70001`))
}
if !_regex_LoginRequest_TelNum.MatchString(this.TelNum) {
return github_com_mwitkow_go_proto_validators.FieldError("TelNum", fmt.Errorf(`70002`))
}
return nil
}
func (this *TokenInfo) Validate() error {
if this.AccountInfo != nil {
if err := github_com_mwitkow_go_proto_validators.CallValidatorIfExists(this.AccountInfo); err != nil {
return github_com_mwitkow_go_proto_validators.FieldError("AccountInfo", err)
}
}
return nil
}
func (this *Extend) Validate() error {
return nil
}
func (this *Department) Validate() error {
return nil
}
func (this *AccountInfo) Validate() error {
if this.Extend != nil {
if err := github_com_mwitkow_go_proto_validators.CallValidatorIfExists(this.Extend); err != nil {
return github_com_mwitkow_go_proto_validators.FieldError("Extend", err)
}
}
for _, item := range this.Departments {
if item != nil {
if err := github_com_mwitkow_go_proto_validators.CallValidatorIfExists(item); err != nil {
return github_com_mwitkow_go_proto_validators.FieldError("Departments", err)
}
}
}
for _, item := range this.Positions {
if item != nil {
if err := github_com_mwitkow_go_proto_validators.CallValidatorIfExists(item); err != nil {
return github_com_mwitkow_go_proto_validators.FieldError("Positions", err)
}
}
}
for _, item := range this.Clocks {
if item != nil {
if err := github_com_mwitkow_go_proto_validators.CallValidatorIfExists(item); err != nil {
return github_com_mwitkow_go_proto_validators.FieldError("Clocks", err)
}
}
}
for _, item := range this.TrainVideos {
if item != nil {
if err := github_com_mwitkow_go_proto_validators.CallValidatorIfExists(item); err != nil {
return github_com_mwitkow_go_proto_validators.FieldError("TrainVideos", err)
}
}
}
if this.Operator != nil {
if err := github_com_mwitkow_go_proto_validators.CallValidatorIfExists(this.Operator); err != nil {
return github_com_mwitkow_go_proto_validators.FieldError("Operator", err)
}
}
return nil
}
func (this *UserInfoV2) Validate() error {
if this.Extend != nil {
if err := github_com_mwitkow_go_proto_validators.CallValidatorIfExists(this.Extend); err != nil {
return github_com_mwitkow_go_proto_validators.FieldError("Extend", err)
}
}
if this.Operator != nil {
if err := github_com_mwitkow_go_proto_validators.CallValidatorIfExists(this.Operator); err != nil {
return github_com_mwitkow_go_proto_validators.FieldError("Operator", err)
}
}
return nil
}
func (this *RefreshTokenRequest) Validate() error {
return nil
}
func (this *PositionUser) Validate() error {
return nil
}
func (this *JobNumGetInfoRequest) Validate() error {
return nil
}
func (this *CreateClockDeviceRequest) Validate() error {
return nil
}
func (this *UpdateClockDeviceRequest) Validate() error {
return nil
}
func (this *ClockDeviceResponse) Validate() error {
return nil
}
func (this *RemoveClockDeviceRequest) Validate() error {
return nil
}
func (this *ClockDeviceListRequest) Validate() error {
return nil
}
func (this *ClockDeviceListResponse) Validate() error {
for _, item := range this.Data {
if item != nil {
if err := github_com_mwitkow_go_proto_validators.CallValidatorIfExists(item); err != nil {
return github_com_mwitkow_go_proto_validators.FieldError("Data", err)
}
}
}
return nil
}
func (this *ClockUser) Validate() error {
if this.Device != nil {
if err := github_com_mwitkow_go_proto_validators.CallValidatorIfExists(this.Device); err != nil {
return github_com_mwitkow_go_proto_validators.FieldError("Device", err)
}
}
return nil
}
func (this *ClockDeviceInfo) Validate() error {
for _, item := range this.Data {
if item != nil {
if err := github_com_mwitkow_go_proto_validators.CallValidatorIfExists(item); err != nil {
return github_com_mwitkow_go_proto_validators.FieldError("Data", err)
}
}
}
return nil
}
func (this *ClockDeviceInfoResponse) Validate() error {
for _, item := range this.Data {
if item != nil {
if err := github_com_mwitkow_go_proto_validators.CallValidatorIfExists(item); err != nil {
return github_com_mwitkow_go_proto_validators.FieldError("Data", err)
}
}
}
return nil
}
func (this *ClockUserRel) Validate() error {
return nil
}
func (this *ClockDeviceInfoRequest) Validate() error {
return nil
}
func (this *ClockBatchBindRequest) Validate() error {
return nil
}
func (this *ClockBatchListResponse) Validate() error {
for _, item := range this.Data {
if item != nil {
if err := github_com_mwitkow_go_proto_validators.CallValidatorIfExists(item); err != nil {
return github_com_mwitkow_go_proto_validators.FieldError("Data", err)
}
}
}
return nil
}
func (this *ClockUserDeviceBatch) Validate() error {
return nil
}
func (this *ClockLogInfo) Validate() error {
return nil
}
func (this *ClockLogReq) Validate() error {
return nil
}
func (this *ClockLogListResponse) Validate() error {
for _, item := range this.Data {
if item != nil {
if err := github_com_mwitkow_go_proto_validators.CallValidatorIfExists(item); err != nil {
return github_com_mwitkow_go_proto_validators.FieldError("Data", err)
}
}
}
return nil
}

File diff suppressed because it is too large Load Diff

199
cmd/app.go Normal file
View File

@ -0,0 +1,199 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package main
import (
"dubbo.apache.org/dubbo-go/v3/common/logger"
"dubbo.apache.org/dubbo-go/v3/config"
_ "dubbo.apache.org/dubbo-go/v3/imports"
"fmt"
appconfig "github.com/fonchain_enterprise/micro-account/cmd/config"
"github.com/fonchain_enterprise/micro-account/pkg/blockchain"
"github.com/fonchain_enterprise/micro-account/pkg/cache"
"github.com/fonchain_enterprise/micro-account/pkg/common/dingding"
_ "github.com/fonchain_enterprise/micro-account/pkg/common/filter"
msgconfig "github.com/fonchain_enterprise/micro-account/pkg/config"
"github.com/fonchain_enterprise/micro-account/pkg/infrsatructure/external"
"github.com/fonchain_enterprise/micro-account/pkg/m"
"github.com/fonchain_enterprise/micro-account/pkg/model"
"github.com/fonchain_enterprise/micro-account/pkg/service"
"github.com/fonchain_enterprise/utils/zap_log"
"github.com/nacos-group/nacos-sdk-go/clients"
"github.com/nacos-group/nacos-sdk-go/common/constant"
"github.com/nacos-group/nacos-sdk-go/vo"
"os"
)
func main() {
//启动新日志
if err := bootstrap(); err != nil {
panic(err)
}
//注册服务
config.SetProviderService(&service.AccountProvider{})
//config.SetProviderService(&service.CoinProvider{})
if err := config.Load(); err != nil {
panic(err)
}
//logger.SetLogger(log.GetFakeLogger())
logger.SetLogger(zap_log.GetFakeLogger())
//dubbo日志
logger.Info("帐号微服务启动成功,git commit:", os.Getenv("GIT_COMMIT"))
select {}
}
func bootstrap() (err error) {
aliConfig, err := appconfig.LoadAliEnv(m.SERVER_CONFIG)
if err != nil {
return err
}
var configEnv *appconfig.Config
if aliConfig.System.Nacos == true {
fmt.Println("使用nacos")
configEnv, err = appconfig.LoadEnvFromFileInfo(loadAli(aliConfig))
} else {
fmt.Println("使用配置文件")
configEnv, err = appconfig.LoadEnv(m.SERVER_CONFIG)
}
if err != nil {
return err
}
fmt.Printf("\n当前环境%s,版本号:%s\n", configEnv.System.Mode, configEnv.System.Version)
err = zap_log.InitZapLog("../conf/log.yaml")
if err != nil {
return err
}
//数据库
mysqlConfig := model.MysqlConfig{
Db: configEnv.Mysql.Db,
DbHost: configEnv.Mysql.DbHost,
DbPort: configEnv.Mysql.DbPort,
DbUser: configEnv.Mysql.DbUser,
DbPassWord: configEnv.Mysql.DbPassWord,
DbName: configEnv.Mysql.DbName,
}
model.LoadEnv(mysqlConfig)
//redis
redisConfig := cache.RedisConfig{
RedisDB: configEnv.Redis.RedisDB,
RedisAddr: configEnv.Redis.RedisAddr,
RedisPw: configEnv.Redis.RedisPW,
RedisDbName: configEnv.Redis.RedisDBNAme,
}
cache.LoadRedis(redisConfig)
//chain
chainConfig := blockchain.ChainConfig{
IP: configEnv.Chain.IP,
AdminMnemonicWords: configEnv.Chain.AdminMnemonicWords,
AdminContractAccount: configEnv.Chain.AdminContractAccount,
ContractName: configEnv.Chain.ContractName,
ContractType: configEnv.Chain.ContractType,
}
blockchain.LoadEnv(chainConfig)
if err != nil {
return err
}
msgInfo := msgconfig.MobileConfigTemplate{
AK: configEnv.Mobile.AK,
SK: configEnv.Mobile.SK,
URL: configEnv.Mobile.URL,
}
aliInfo := msgconfig.AliMessage{
AK: configEnv.AlMobile.AK,
AS: configEnv.AlMobile.AS,
URL: configEnv.AlMobile.URL,
}
fmt.Println("飞鸽短信配置", msgInfo)
fmt.Println("阿里短信配置", aliInfo)
msgconfig.LoadData(msgInfo, aliInfo)
dingding.LoadAccessToken(configEnv.Mobile.DingDingKey)
//logger.SetLogger()
model.SetSendPhoneNUm(configEnv.System.Mode == "prod")
fmt.Println("是否创建邮箱", configEnv.Mail.IsProd)
external.LoadEnv(configEnv.Mail.Username, configEnv.Mail.Password, configEnv.Mail.Domain, configEnv.Mail.IsProd)
return nil
}
func loadAli(aliConfig *appconfig.AliConfig) string {
fmt.Println("ali", aliConfig)
clientConfig := constant.ClientConfig{
NamespaceId: aliConfig.Nacos.NamespaceId, // 如果需要支持多namespace我们可以场景多个client,它们有不同的NamespaceId。当namespace是public时此处填空字符串。
TimeoutMs: 5000,
NotLoadCacheAtStart: true,
LogDir: "/tmp/nacos/log",
CacheDir: "/tmp/nacos/cache",
Username: aliConfig.Nacos.Username,
Password: aliConfig.Nacos.Password,
LogLevel: "debug",
}
//配置连接信息
serverConfigs := []constant.ServerConfig{
{
IpAddr: aliConfig.Nacos.IpAddr,
ContextPath: "/nacos",
Port: 80,
Scheme: "http",
},
}
// Create naming client for service discovery
configClient, err := clients.CreateConfigClient(map[string]interface{}{
"serverConfigs": serverConfigs,
"clientConfig": clientConfig,
})
if err != nil {
logger.Fatal(err)
}
//读取文件
content, err := configClient.GetConfig(vo.ConfigParam{
DataId: aliConfig.Nacos.DataId, //此处对应之前的网页配置的名称
Group: aliConfig.Nacos.Group, //此处对应之前的网页配置的分组
})
if err != nil {
logger.Fatal(err)
}
return content
}

105
cmd/config/config.go Normal file
View File

@ -0,0 +1,105 @@
package config
import (
"errors"
"fmt"
"github.com/BurntSushi/toml"
"os"
)
/********start-配置信息*********/
//Baiduco 百度上链
type Mysql struct {
Db string
DbHost string
DbPort string
DbUser string
DbPassWord string
DbName string
}
type Redis struct {
RedisDB string
RedisAddr string
RedisPW string
RedisDBNAme string
}
type Chain struct {
IP string
AdminMnemonicWords string `toml:"MnemonicWords"`
AdminContractAccount string `toml:"ContractAccount"`
ContractName string
ContractType string
}
type System struct {
Mode string
Version string
Nacos bool
}
type Mobile struct {
SK string
AK string
URL string
DingDingKey string
}
type Mail struct {
IsProd bool
Username string
Password string
Domain string
}
type Config struct {
Mysql Mysql `toml:"mysql"`
Redis Redis `toml:"redis"`
Chain Chain `toml:"chain"`
System System `toml:"system"`
Mobile Mobile `toml:"mobile"`
Mail Mail `toml:"mail"`
AlMobile AlMobile `toml:"almobile"`
}
type AlMobile struct {
AS string
AK string
URL string
}
/********start-配置信息*********/
var AppConfig *Config
func newConfig() *Config {
return new(Config)
}
func LoadEnv(path string) (*Config, error) {
_, err := os.Stat(path)
if err != nil {
return nil, err
}
AppConfig = newConfig()
if _, err := toml.DecodeFile(path, AppConfig); err != nil {
return nil, err
}
return AppConfig, nil
}
func LoadEnvFromFileInfo(data string) (*Config, error) {
fmt.Println(data)
if data == "" {
return nil, errors.New("nacos 配置文件为空")
}
AppConfig = newConfig()
if _, err := toml.Decode(data, AppConfig); err != nil {
return nil, err
}
return AppConfig, nil
}

47
cmd/config/nacos.go Normal file
View File

@ -0,0 +1,47 @@
package config
import (
"github.com/BurntSushi/toml"
"io/ioutil"
"os"
)
/********start-配置信息*********/
type Nacos struct {
NamespaceId string
Username string
Password string
IpAddr string
DataId string
Group string
}
type AliConfig struct {
System System `toml:"system"`
Nacos Nacos `toml:"Nacos"`
}
/********start-配置信息*********/
var AliAppConfig *AliConfig
func newAliConfig() *AliConfig {
return new(AliConfig)
}
func LoadAliEnv(path string) (*AliConfig, error) {
data, err := ioutil.ReadFile(path)
if err != nil {
return nil, err
}
configStr := os.ExpandEnv(string(data))
AliAppConfig = newAliConfig()
if _, err := toml.Decode(configStr, AliAppConfig); err != nil {
return nil, err
}
return AliAppConfig, nil
}

0
conf/.gitignore vendored Normal file
View File

68
docs/account.sql Normal file
View File

@ -0,0 +1,68 @@
-- --------------------------------------------------------
-- 主机: 127.0.0.1
-- 服务器版本: 5.7.38 - MySQL Community Server (GPL)
-- 服务器操作系统: Linux
-- HeidiSQL 版本: 12.0.0.6468
-- --------------------------------------------------------
/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
/*!40101 SET NAMES utf8 */;
/*!50503 SET NAMES utf8mb4 */;
/*!40103 SET @OLD_TIME_ZONE=@@TIME_ZONE */;
/*!40103 SET TIME_ZONE='+00:00' */;
/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;
/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;
/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */;
-- 导出 表 fontree-account.real_name 结构
CREATE TABLE IF NOT EXISTS `real_name` (
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
`created_at` datetime DEFAULT NULL,
`updated_at` datetime DEFAULT NULL,
`deleted_at` int(11) DEFAULT NULL,
`name` varchar(256) NOT NULL,
`id_num` varchar(256) NOT NULL,
PRIMARY KEY (`id`) USING BTREE,
KEY `idx_real_name_deleted_at` (`deleted_at`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;
CREATE TABLE `user` (
`id` BIGINT(20) UNSIGNED NOT NULL AUTO_INCREMENT,
`created_at` DATETIME NULL DEFAULT NULL,
`updated_at` DATETIME NULL DEFAULT NULL,
`deleted_at` INT(11) NULL DEFAULT '0' COMMENT '删除标志',
`account` VARCHAR(256) NULL DEFAULT NULL COLLATE 'utf8_general_ci',
`mnemonic_words` VARCHAR(256) NULL DEFAULT NULL COLLATE 'utf8_general_ci',
`tel_num` VARCHAR(256) NULL DEFAULT NULL COLLATE 'utf8_general_ci',
`password_digest` VARCHAR(256) NULL DEFAULT NULL COLLATE 'utf8_general_ci',
`nickname` VARCHAR(256) NOT NULL COLLATE 'utf8_general_ci',
`status` VARCHAR(256) NULL DEFAULT NULL COLLATE 'utf8_general_ci',
`avatar` VARCHAR(1000) NULL DEFAULT NULL COLLATE 'utf8_general_ci',
`real_name_id` BIGINT(20) UNSIGNED NULL DEFAULT NULL,
`auth` BIGINT(20) UNSIGNED NULL DEFAULT NULL,
`theme_id` BIGINT(20) UNSIGNED NULL DEFAULT NULL,
`domain` VARCHAR(50) NULL DEFAULT NULL COLLATE 'utf8_general_ci',
`public_key` VARCHAR(256) NULL DEFAULT NULL COLLATE 'utf8_general_ci',
`is_need_change` TINYINT(4) NULL DEFAULT '1' COMMENT '是否强制重置密码',
`enter_date` VARCHAR(50) NULL DEFAULT NULL COLLATE 'utf8_general_ci',
`work_year` FLOAT(3,1) NULL DEFAULT NULL,
`extend` JSON NULL DEFAULT NULL COMMENT '扩展属性',
PRIMARY KEY (`id`) USING BTREE,
UNIQUE INDEX `unqiue_tel` (`domain`, `tel_num`, `deleted_at`) USING BTREE,
UNIQUE INDEX `account` (`account`, `id`, `deleted_at`) USING BTREE,
INDEX `idx_user_deleted_at` (`deleted_at`) USING BTREE
)
COLLATE='utf8_general_ci'
ENGINE=InnoDB
AUTO_INCREMENT=41
;
-- 数据导出被取消选择。
/*!40103 SET TIME_ZONE=IFNULL(@OLD_TIME_ZONE, 'system') */;
/*!40101 SET SQL_MODE=IFNULL(@OLD_SQL_MODE, '') */;
/*!40014 SET FOREIGN_KEY_CHECKS=IFNULL(@OLD_FOREIGN_KEY_CHECKS, 1) */;
/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;
/*!40111 SET SQL_NOTES=IFNULL(@OLD_SQL_NOTES, 1) */;
INSERT INTO `user` (`id`, `created_at`, `updated_at`, `deleted_at`, `account`, `mnemonic_words`, `tel_num`, `password_digest`, `nickname`, `status`, `avatar`, `real_name_id`, `auth`, `theme_id`, `domain`, `public_key`) VALUES (40, '2022-08-03 06:06:17', '2022-08-04 02:42:17', 0, 'TenaGe8oL5KqsbJgmLFaD1zsyXU6k3Lgs', 'Fe9V/pftKfajtmR55FpMKJuI/9NsCc5Nnfgsxnb9E/IZOK76YGmz2BKDy9v2qqrA', '12233445566', '$2a$12$7C8drxzbuO3jbeMBkmzRfeQYPVJTUWByQcLmG/tljjnhokDEq79RC', '超级管理', 'notactive', '', 0, 0, NULL, 'fontree', '{"Curvname":"P-256","X":78545775124824610215124063665621548167623667204728303094007555226201575072468,"Y":50472501812965014802492291779217782793101961009658062700069826283252860388199}');

12
docs/env/ali/conf.ini vendored Normal file
View File

@ -0,0 +1,12 @@
[system]
Mode = "prod"
Version = "1.0.1"
Nacos = true
[Nacos]
NamespaceId = "${NamespaceId}"
Username = "${Username}"
Password = "${Password}"
IpAddr = "${IpAddr}"
Group = "${Group}"
DataId = "micro-account-conf"

34
docs/env/ali/dubbogo.yaml vendored Normal file
View File

@ -0,0 +1,34 @@
dubbo:
registries:
demoZK:
protocol: zookeeper
address: zookeeper:2181
protocols:
triple:
name: tri
port: 20001
provider:
services:
AccountProvider:
interface: com.fontree.microservices.common.Account # must be compatible with grpc or dubbo-java
auth: "true"
filter: echo,metrics,token,accesslog,tps,generic_service,execute,pshutdown,auth,fonValidateFilter
params:
.accessKeyId: "Accountksl"
.secretAccessKey: "BSDY-FDF1-Fontree_account"
CoinProvider:
interface: com.fontree.microservices.common.coin # must be compatible with grpc or dubbo-java
auth: "true"
filter: echo,metrics,token,accesslog,tps,generic_service,execute,pshutdown,auth,fonValidateFilter
params:
.accessKeyId: "Accountksl"
.secretAccessKey: "BSDY-FDF1-Fontree_account"
logger:
lumberjack-config:
filename: logs.log
maxsize: 1
maxage: 3
maxbackups: 5
localtime: true
compress: true

46
docs/env/ali/log.yaml vendored Normal file
View File

@ -0,0 +1,46 @@
logger:
zap-config:
level: info # 日志级别
development: false
disableCaller: false
disableStacktrace: false
encoding: "json"
# zap encoder 配置
encoderConfig:
messageKey: "message"
levelKey: "level"
timeKey: "time"
nameKey: "logger"
callerKey: "caller"
stacktraceKey: "stacktrace"
lineEnding: ""
levelEncoder: "capital"
timeEncoder: "iso8601"
durationEncoder: "seconds"
callerEncoder: "short"
nameEncoder: ""
EncodeDuration: zapcore.SecondsDurationEncoder,
params:
service: "my-service"
version: "1.0.0"
outputPaths:
- "stderr"
initialFields:
app: "account"
errorOutputPaths:
- "stderr"
lumberjack-config:
# 写日志的文件名称
filename: "logs/main.log"
# 每个日志文件长度的最大大小,单位是 MiB。默认 100MiB
maxSize: 10
# 日志保留的最大天数(只保留最近多少天的日志)
maxAge: 15
# 只保留最近多少个日志文件,用于控制程序总日志的大小
maxBackups: 10
# 是否使用本地时间,默认使用 UTC 时间
localTime: true
# 是否压缩日志文件,压缩方法 gzip
compress: false
CallerSkip: 4

18
docs/env/ali/sdk.yaml vendored Normal file
View File

@ -0,0 +1,18 @@
# endorseService Info
# testNet addrs
# endorseServiceHost: "120.48.24.223:37101"
endorseServiceHost: "127.0.0.1:37101"
complianceCheck:
# 是否需要进行合规性背书
isNeedComplianceCheck: false
# 是否需要支付合规性背书费用
isNeedComplianceCheckFee: false
# 合规性背书费用
complianceCheckEndorseServiceFee: 400
# 支付合规性背书费用的收款地址
complianceCheckEndorseServiceFeeAddr: WwLgfAatHyKx2mCJruRaML4oVf7Chzp42
# 如果通过合规性检查,签发认证签名的地址
complianceCheckEndorseServiceAddr: WwLgfAatHyKx2mCJruRaML4oVf7Chzp42
#创建平行链所需要的最低费用
minNewChainAmount: "100"
crypto: "xchain"

37
docs/env/dev/conf.ini vendored Normal file
View File

@ -0,0 +1,37 @@
[system]
Mode = "dev"
Version = "1.0.2"
[mail]
IsProd = false
Username = "postmaster@fontree.cn"
Password = "Zaq12wsx"
Domain = "fontree.cn"
[mysql]
Db = "mysql"
DbHost = "172.16.100.30"
DbPort = "3306"
DbUser = "root"
DbPassWord = "IhQmhg8HZjDmU=Ove5PnA^D"
DbName = "fontree-account"
[redis]
RedisDB = "1"
RedisAddr = "172.16.100.114:6379"
RedisPW = "kP6tW4tS3qB2dW4aE6uI5cX2"
RedisDBNAme = "1"
[chain]
IP="127.0.0.1:37101"
MnemonicWords="知 睡 迷 纤 纲 耀 镜 婆 渡 考 拔 百"
ContractAccount="XC8214684261867838@xuper"
ContractName="fp001"
ContractType="wasm"
[mobile]
URL="https://api.4321.sh/sms/template"
AK="N7469940cf"
SK="74699ca8e1ea8f80"
DingDingKey="1a4e4b18d9aa35368450c980ceb8def2f11fa0ebb2dc0a3cfd970cd3b8efc6fb"

34
docs/env/dev/dubbogo.yaml vendored Normal file
View File

@ -0,0 +1,34 @@
dubbo:
registries:
demoZK:
protocol: zookeeper
address: 172.16.100.93:2181
protocols:
triple:
name: tri
port: 20001
provider:
services:
AccountProvider:
interface: com.fontree.microservices.common.Account # must be compatible with grpc or dubbo-java
auth: "true"
filter: echo,metrics,token,accesslog,sign,tps,generic_service,execute,pshutdown,auth,fonValidateFilter
params:
.accessKeyId: "Accountksl"
.secretAccessKey: "BSDY-FDF1-Fontree_account"
CoinProvider:
interface: com.fontree.microservices.common.coin # must be compatible with grpc or dubbo-java
auth: "true"
filter: echo,metrics,token,accesslog,tps,generic_service,execute,pshutdown,auth,fonValidateFilter
params:
.accessKeyId: "Accountksl"
.secretAccessKey: "BSDY-FDF1-Fontree_account"
# logger:
# lumberjack-config:
# filename: logs.log
# maxsize: 1
# maxage: 3
# maxbackups: 5
# localtime: true
# compress: true

32
docs/env/dev/log.yaml vendored Normal file
View File

@ -0,0 +1,32 @@
logger:
CallerSkip: 4
zap-config:
level: info # 日志级别
development: false
disableCaller: false
disableStacktrace: false
encoding: "console"
# zap encoder 配置
encoderConfig:
messageKey: "message"
levelKey: "level"
timeKey: "time"
nameKey: "logger"
callerKey: "caller"
stacktraceKey: "stacktrace"
lineEnding: ""
levelEncoder: "capitalColor"
timeEncoder: "iso8601"
durationEncoder: "seconds"
callerEncoder: "short"
nameEncoder: ""
EncodeDuration: zapcore.SecondsDurationEncoder,
params:
service: "my-service"
version: "1.0.0"
outputPaths:
- "stderr"
initialFields:
app: "account"
errorOutputPaths:
- "stderr"

18
docs/env/dev/sdk.yaml vendored Normal file
View File

@ -0,0 +1,18 @@
# endorseService Info
# testNet addrs
# endorseServiceHost: "120.48.24.223:37101"
endorseServiceHost: "127.0.0.1:37101"
complianceCheck:
# 是否需要进行合规性背书
isNeedComplianceCheck: false
# 是否需要支付合规性背书费用
isNeedComplianceCheckFee: false
# 合规性背书费用
complianceCheckEndorseServiceFee: 400
# 支付合规性背书费用的收款地址
complianceCheckEndorseServiceFeeAddr: WwLgfAatHyKx2mCJruRaML4oVf7Chzp42
# 如果通过合规性检查,签发认证签名的地址
complianceCheckEndorseServiceAddr: WwLgfAatHyKx2mCJruRaML4oVf7Chzp42
#创建平行链所需要的最低费用
minNewChainAmount: "100"
crypto: "xchain"

29
docs/env/local/conf.ini vendored Normal file
View File

@ -0,0 +1,29 @@
[system]
Mode = "dev"
Version = "1.0.1"
[mysql]
Db = "mysql"
DbHost = "127.0.0.1"
DbPort = "3306"
DbUser = "root"
DbPassWord = "123456"
DbName = "fontree-account-v2"
[redis]
RedisDB = "2"
RedisAddr = "127.0.0.1:6379"
RedisPW = ""
RedisDBNAme = "2"
[chain]
IP="127.0.0.1:37101"
MnemonicWords="知 睡 迷 纤 纲 耀 镜 婆 渡 考 拔 百"
ContractAccount="XC8214684261867838@xuper"
ContractName="fp001"
ContractType="wasm"
[mobile]
URL="https://api.4321.sh/sms/template"
AK="N7469940cf"
SK="74699ca8e1ea8f80"

34
docs/env/local/dubbogo.yaml vendored Normal file
View File

@ -0,0 +1,34 @@
dubbo:
registries:
demoZK:
protocol: zookeeper
address: 127.0.0.1:2181
protocols:
triple:
name: tri
port: 20000
provider:
services:
AccountProvider:
interface: com.fontree.microservices.common.Account # must be compatible with grpc or dubbo-java
auth: "true"
filter: echo,metrics,token,accesslog,tps,generic_service,execute,pshutdown,auth,fonValidateFilter
params:
.accessKeyId: "Accountksl"
.secretAccessKey: "BSDY-FDF1-Fontree_account"
CoinProvider:
interface: com.fontree.microservices.common.coin # must be compatible with grpc or dubbo-java
auth: "true"
filter: echo,metrics,token,accesslog,tps,generic_service,execute,pshutdown,auth,fonValidateFilter
params:
.accessKeyId: "Accountksl"
.secretAccessKey: "BSDY-FDF1-Fontree_account"
# logger:
# lumberjack-config:
# filename: logs.log
# maxsize: 1
# maxage: 3
# maxbackups: 5
# localtime: true
# compress: true

32
docs/env/local/log.yaml vendored Normal file
View File

@ -0,0 +1,32 @@
logger:
CallerSkip: 4
zap-config:
level: info # 日志级别
development: false
disableCaller: false
disableStacktrace: false
encoding: "console"
# zap encoder 配置
encoderConfig:
messageKey: "message"
levelKey: "level"
timeKey: "time"
nameKey: "logger"
callerKey: "caller"
stacktraceKey: "stacktrace"
lineEnding: ""
levelEncoder: "capitalColor"
timeEncoder: "iso8601"
durationEncoder: "seconds"
callerEncoder: "short"
nameEncoder: ""
EncodeDuration: zapcore.SecondsDurationEncoder,
params:
service: "my-service"
version: "1.0.0"
outputPaths:
- "stderr"
initialFields:
app: "account"
errorOutputPaths:
- "stderr"

18
docs/env/local/sdk.yaml vendored Normal file
View File

@ -0,0 +1,18 @@
# endorseService Info
# testNet addrs
# endorseServiceHost: "120.48.24.223:37101"
endorseServiceHost: "127.0.0.1:37101"
complianceCheck:
# 是否需要进行合规性背书
isNeedComplianceCheck: false
# 是否需要支付合规性背书费用
isNeedComplianceCheckFee: false
# 合规性背书费用
complianceCheckEndorseServiceFee: 400
# 支付合规性背书费用的收款地址
complianceCheckEndorseServiceFeeAddr: WwLgfAatHyKx2mCJruRaML4oVf7Chzp42
# 如果通过合规性检查,签发认证签名的地址
complianceCheckEndorseServiceAddr: WwLgfAatHyKx2mCJruRaML4oVf7Chzp42
#创建平行链所需要的最低费用
minNewChainAmount: "100"
crypto: "xchain"

223
go.mod Normal file
View File

@ -0,0 +1,223 @@
module github.com/fonchain_enterprise/micro-account
go 1.18
replace (
github.com/fonchain_enterprise/utils/aes => ../utils/aes
github.com/fonchain_enterprise/utils/baidu => ../utils/baidu
github.com/fonchain_enterprise/utils/chain => ../utils/chain
github.com/fonchain_enterprise/utils/feie => ../utils/feie
github.com/fonchain_enterprise/utils/jwt => ../utils/jwt
github.com/fonchain_enterprise/utils/mobile => ../utils/mobile
github.com/fonchain_enterprise/utils/rand => ../utils/rand
github.com/fonchain_enterprise/utils/zap_log => ../utils/zap_log
)
require (
dubbo.apache.org/dubbo-go/v3 v3.0.2
github.com/BurntSushi/toml v1.3.2
github.com/PuerkitoBio/goquery v1.8.1
github.com/alibaba/sentinel-golang v1.0.4
github.com/dgrijalva/jwt-go v3.2.0+incompatible
github.com/dubbogo/grpc-go v1.42.9
github.com/dubbogo/triple v1.1.8
github.com/fonchain_enterprise/utils/aes v0.0.0-00010101000000-000000000000
github.com/fonchain_enterprise/utils/baidu v0.0.0-00010101000000-000000000000
github.com/fonchain_enterprise/utils/chain v0.0.0-00010101000000-000000000000
github.com/fonchain_enterprise/utils/feie v0.0.0-00010101000000-000000000000
github.com/fonchain_enterprise/utils/mobile v0.0.0-00010101000000-000000000000
github.com/fonchain_enterprise/utils/rand v0.0.0-00010101000000-000000000000
github.com/fonchain_enterprise/utils/zap_log v0.0.0-00010101000000-000000000000
github.com/go-redis/redis v6.15.9+incompatible
github.com/golang/protobuf v1.5.2
github.com/google/uuid v1.3.0
github.com/mozillazg/go-pinyin v0.20.0
github.com/mwitkow/go-proto-validators v0.3.2
github.com/nacos-group/nacos-sdk-go v1.1.1
github.com/natefinch/lumberjack v2.0.0+incompatible
github.com/pkg/errors v0.9.1
github.com/shopspring/decimal v1.4.0
go.uber.org/zap v1.21.0
golang.org/x/crypto v0.10.0
golang.org/x/text v0.10.0
google.golang.org/protobuf v1.28.0
gopkg.in/yaml.v2 v2.4.0
gorm.io/driver/mysql v1.3.5
gorm.io/gorm v1.25.5
gorm.io/plugin/soft_delete v1.2.0
)
require (
cloud.google.com/go v0.65.0 // indirect
contrib.go.opencensus.io/exporter/prometheus v0.4.1 // indirect
github.com/ChainSafe/go-schnorrkel v0.0.0-20200626160457-b38283118816 // indirect
github.com/RoaringBitmap/roaring v1.1.0 // indirect
github.com/StackExchange/wmi v0.0.0-20190523213315-cbe66965904d // indirect
github.com/Workiva/go-datastructures v1.0.52 // indirect
github.com/afex/hystrix-go v0.0.0-20180502004556-fa1af6a1f4f5 // indirect
github.com/alibabacloud-go/alibabacloud-gateway-spi v0.0.4 // indirect
github.com/alibabacloud-go/darabonba-openapi v0.2.1 // indirect
github.com/alibabacloud-go/debug v0.0.0-20190504072949-9472017b5c68 // indirect
github.com/alibabacloud-go/dysmsapi-20170525/v2 v2.0.18 // indirect
github.com/alibabacloud-go/endpoint-util v1.1.0 // indirect
github.com/alibabacloud-go/openapi-util v0.0.11 // indirect
github.com/alibabacloud-go/tea v1.2.1 // indirect
github.com/alibabacloud-go/tea-console v1.0.0 // indirect
github.com/alibabacloud-go/tea-utils v1.4.5 // indirect
github.com/alibabacloud-go/tea-xml v1.1.2 // indirect
github.com/aliyun/alibaba-cloud-sdk-go v1.61.18 // indirect
github.com/aliyun/credentials-go v1.1.2 // indirect
github.com/andybalholm/cascadia v1.3.1 // indirect
github.com/apache/dubbo-getty v1.4.8 // indirect
github.com/apache/dubbo-go-hessian2 v1.11.0 // indirect
github.com/beorn7/perks v1.0.1 // indirect
github.com/bits-and-blooms/bitset v1.2.0 // indirect
github.com/btcsuite/btcd v0.20.1-beta // indirect
github.com/btcsuite/btcutil v0.0.0-20190425235716-9e5f4b9a998d // indirect
github.com/buger/jsonparser v1.1.1 // indirect
github.com/census-instrumentation/opencensus-proto v0.2.1 // indirect
github.com/cespare/xxhash/v2 v2.1.2 // indirect
github.com/clbanning/mxj/v2 v2.5.6 // indirect
github.com/cloudflare/bn256 v0.0.0-20200818021822-8aba7cd1ae4c // indirect
github.com/cncf/udpa/go v0.0.0-20210930031921-04548b0d99d4 // indirect
github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1 // indirect
github.com/consensys/gnark v0.2.1-alpha // indirect
github.com/consensys/gurvy v0.1.2-0.20200512111154-1662e289e29b // indirect
github.com/coreos/go-semver v0.3.0 // indirect
github.com/coreos/go-systemd/v22 v22.3.2 // indirect
github.com/cosmos/go-bip39 v0.0.0-20180819234021-555e2067c45d // indirect
github.com/creasty/defaults v1.5.2 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/dubbogo/go-zookeeper v1.0.4-0.20211212162352-f9d2183d89d5 // indirect
github.com/dubbogo/gost v1.11.25 // indirect
github.com/emicklei/go-restful/v3 v3.7.4 // indirect
github.com/emirpasic/gods v1.12.1-0.20201118132343-79df803e554c // indirect
github.com/envoyproxy/go-control-plane v0.10.2-0.20220325020618-49ff273808a1 // indirect
github.com/envoyproxy/protoc-gen-validate v0.1.0 // indirect
github.com/fsnotify/fsnotify v1.5.4 // indirect
github.com/ghodss/yaml v1.0.0 // indirect
github.com/go-co-op/gocron v1.9.0 // indirect
github.com/go-errors/errors v1.0.1 // indirect
github.com/go-kit/kit v0.10.0 // indirect
github.com/go-kit/log v0.1.0 // indirect
github.com/go-logfmt/logfmt v0.5.0 // indirect
github.com/go-logr/logr v1.2.3 // indirect
github.com/go-logr/stdr v1.2.2 // indirect
github.com/go-ole/go-ole v1.2.4 // indirect
github.com/go-playground/locales v0.14.0 // indirect
github.com/go-playground/universal-translator v0.18.0 // indirect
github.com/go-playground/validator/v10 v10.11.0 // indirect
github.com/go-resty/resty/v2 v2.7.0 // indirect
github.com/go-sql-driver/mysql v1.6.0 // indirect
github.com/go-stack/stack v1.8.0 // indirect
github.com/gogo/protobuf v1.3.2 // indirect
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
github.com/golang/mock v1.5.0 // indirect
github.com/golang/snappy v0.0.4 // indirect
github.com/gorilla/websocket v1.4.2 // indirect
github.com/grpc-ecosystem/grpc-gateway v1.16.0 // indirect
github.com/grpc-ecosystem/grpc-opentracing v0.0.0-20180507213350-8e809c8a8645 // indirect
github.com/gtank/merlin v0.1.1-0.20191105220539-8318aed1a79f // indirect
github.com/gtank/ristretto255 v0.1.2 // indirect
github.com/hashicorp/errwrap v1.1.0 // indirect
github.com/hashicorp/go-multierror v1.1.1 // indirect
github.com/hashicorp/hcl v1.0.0 // indirect
github.com/hashicorp/vault/sdk v0.3.0 // indirect
github.com/hyperledger/burrow v0.30.5 // indirect
github.com/ipfs/go-cid v0.0.7 // indirect
github.com/ipfs/go-ipfs-addr v0.0.1 // indirect
github.com/ipfs/go-log v1.0.4 // indirect
github.com/ipfs/go-log/v2 v2.1.1 // indirect
github.com/jinzhu/copier v0.3.5 // indirect
github.com/jinzhu/inflection v1.0.0 // indirect
github.com/jinzhu/now v1.1.5 // indirect
github.com/jmespath/go-jmespath v0.4.0 // indirect
github.com/json-iterator/go v1.1.12 // indirect
github.com/k0kubun/pp v3.0.1+incompatible // indirect
github.com/knadh/koanf v1.4.1 // indirect
github.com/leodido/go-urn v1.2.1 // indirect
github.com/libp2p/go-buffer-pool v0.0.2 // indirect
github.com/libp2p/go-libp2p-core v0.6.1 // indirect
github.com/libp2p/go-libp2p-crypto v0.1.0 // indirect
github.com/libp2p/go-libp2p-peer v0.2.0 // indirect
github.com/libp2p/go-openssl v0.0.7 // indirect
github.com/magiconair/properties v1.8.6 // indirect
github.com/mattn/go-colorable v0.1.7 // indirect
github.com/mattn/go-isatty v0.0.14 // indirect
github.com/matttproud/golang_protobuf_extensions v1.0.1 // indirect
github.com/mimoo/StrobeGo v0.0.0-20181016162300-f8f6d4d2b643 // indirect
github.com/minio/blake2b-simd v0.0.0-20160723061019-3f5f724cb5b1 // indirect
github.com/minio/sha256-simd v0.1.1 // indirect
github.com/mitchellh/copystructure v1.2.0 // indirect
github.com/mitchellh/go-homedir v1.1.0 // indirect
github.com/mitchellh/mapstructure v1.5.0 // indirect
github.com/mitchellh/reflectwalk v1.0.2 // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.2 // indirect
github.com/mr-tron/base58 v1.2.0 // indirect
github.com/mschoch/smat v0.2.0 // indirect
github.com/multiformats/go-base32 v0.0.3 // indirect
github.com/multiformats/go-base36 v0.1.0 // indirect
github.com/multiformats/go-multiaddr v0.3.1 // indirect
github.com/multiformats/go-multibase v0.0.3 // indirect
github.com/multiformats/go-multihash v0.0.14 // indirect
github.com/multiformats/go-varint v0.0.6 // indirect
github.com/opentracing/opentracing-go v1.2.0 // indirect
github.com/patrickmn/go-cache v2.1.0+incompatible // indirect
github.com/pelletier/go-toml v1.7.0 // indirect
github.com/pierrec/lz4 v2.5.2+incompatible // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/polarismesh/polaris-go v1.1.0 // indirect
github.com/prometheus/client_golang v1.12.2 // indirect
github.com/prometheus/client_model v0.2.0 // indirect
github.com/prometheus/common v0.32.1 // indirect
github.com/prometheus/procfs v0.7.3 // indirect
github.com/prometheus/statsd_exporter v0.21.0 // indirect
github.com/robfig/cron/v3 v3.0.1 // indirect
github.com/satori/go.uuid v1.2.1-0.20181028125025-b2ce2384e17b // indirect
github.com/shirou/gopsutil v3.20.11+incompatible // indirect
github.com/shirou/gopsutil/v3 v3.21.6 // indirect
github.com/spacemonkeygo/spacelog v0.0.0-20180420211403-2296661a0572 // indirect
github.com/spaolacci/murmur3 v1.1.0 // indirect
github.com/spf13/afero v1.2.2 // indirect
github.com/spf13/cast v1.3.0 // indirect
github.com/spf13/jwalterweatherman v1.0.0 // indirect
github.com/spf13/pflag v1.0.5 // indirect
github.com/spf13/viper v1.7.1 // indirect
github.com/stretchr/testify v1.8.1 // indirect
github.com/subosito/gotenv v1.2.0 // indirect
github.com/syndtr/goleveldb v1.0.1-0.20200815110645-5c35d600f0ca // indirect
github.com/tendermint/go-amino v0.14.1 // indirect
github.com/tendermint/tendermint v0.33.1 // indirect
github.com/tjfoc/gmsm v1.3.2 // indirect
github.com/tklauser/go-sysconf v0.3.6 // indirect
github.com/tklauser/numcpus v0.2.2 // indirect
github.com/tmthrgd/go-hex v0.0.0-20190303111820-0bdcb15db631 // indirect
github.com/uber/jaeger-client-go v2.29.1+incompatible // indirect
github.com/uber/jaeger-lib v2.4.1+incompatible // indirect
github.com/ugorji/go/codec v1.2.7 // indirect
github.com/xuperchain/crypto v0.0.0-20201028025054-4d560674bcd6 // indirect
github.com/xuperchain/log15 v0.0.0-20190620081506-bc88a9198230 // indirect
github.com/xuperchain/xuper-sdk-go/v2 v2.0.0 // indirect
github.com/xuperchain/xuperchain v0.0.0-20210708031936-951e4ade7bdd // indirect
github.com/xuperchain/xupercore v0.0.0-20210608021245-b15f81dd9ecf // indirect
github.com/zouyx/agollo/v3 v3.4.5 // indirect
go.etcd.io/etcd/api/v3 v3.5.4 // indirect
go.etcd.io/etcd/client/pkg/v3 v3.5.4 // indirect
go.etcd.io/etcd/client/v3 v3.5.4 // indirect
go.opencensus.io v0.23.0 // indirect
go.opentelemetry.io/otel v1.7.0 // indirect
go.opentelemetry.io/otel/trace v1.7.0 // indirect
go.uber.org/atomic v1.9.0 // indirect
go.uber.org/multierr v1.6.0 // indirect
golang.org/x/net v0.11.0 // indirect
golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8 // indirect
golang.org/x/sync v0.1.0 // indirect
golang.org/x/sys v0.9.0 // indirect
google.golang.org/appengine v1.6.6 // indirect
google.golang.org/genproto v0.0.0-20211104193956-4c6863e31247 // indirect
google.golang.org/grpc v1.47.0 // indirect
gopkg.in/ini.v1 v1.56.0 // indirect
gopkg.in/natefinch/lumberjack.v2 v2.2.1 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)

2001
go.sum Normal file

File diff suppressed because it is too large Load Diff

1
pkg/application/coin.go Normal file
View File

@ -0,0 +1 @@
package application

5
pkg/application/init.go Normal file
View File

@ -0,0 +1,5 @@
package application
func init() {
}

255
pkg/application/order.go Normal file
View File

@ -0,0 +1,255 @@
package application
import (
"fmt"
"github.com/fonchain_enterprise/micro-account/api/account"
"github.com/fonchain_enterprise/micro-account/cmd/config"
"github.com/fonchain_enterprise/micro-account/pkg/cache"
"github.com/fonchain_enterprise/micro-account/pkg/common/jwt"
"github.com/fonchain_enterprise/micro-account/pkg/common/redis_key"
"github.com/fonchain_enterprise/micro-account/pkg/common/utils"
"github.com/fonchain_enterprise/micro-account/pkg/m"
"github.com/fonchain_enterprise/micro-account/pkg/model"
"net"
"time"
)
// Logout 登出
func Logout(in *account.DecryptJwtRequest, status uint8) error {
var loginLog *model.LoginLog
//解析token
claims, err := jwt.ParseToken(in.Token, m.JWTSecret)
if err != nil {
return err
}
//删除token信息
tokenKey := redis_key.GetTokenInfo(in.Domain, in.Token)
fmt.Print("删除token", tokenKey)
if merr := cache.RedisClient.Del(tokenKey).Err(); merr != nil {
return merr
}
//记录token信息
if err := model.DB.Model(&model.LoginLog{}).Where(&model.LoginLog{Token: in.Token}).First(&loginLog).Error; err != nil {
loginLog = &model.LoginLog{
UserId: claims.ID,
Token: in.Token,
Status: status,
ExpireDate: time.Now().Format("2006-01-02 15:04:05"),
LastDate: time.Now().Format("2006-01-02 15:04:05"),
LogoutDate: time.Now().Format("2006-01-02 15:04:05"),
}
model.DB.Model(&model.LoginLog{}).Create(loginLog)
} else {
//不存在
updateLog := &model.LoginLog{
Status: status,
LogoutDate: time.Now().Format("2006-01-02 15:04:05"),
}
model.DB.Model(&model.LoginLog{}).Where(&model.LoginLog{ID: loginLog.ID}).Updates(&updateLog)
}
return nil
}
// UpdateLastDate 更新最新操作时间
func UpdateLastDate(token string) {
var loginLog *model.LoginLog
if err := model.DB.Model(&model.LoginLog{}).Where(&model.LoginLog{Token: token}).First(&loginLog).Error; err != nil {
return
}
updateObj := &model.LoginLog{LastDate: time.Now().Format("2006-01-02 15:04:05")}
model.DB.Model(&model.LoginLog{}).Where(&model.LoginLog{Token: token}).Updates(updateObj)
return
}
// OffByLogId 踢下线
func OffByLogId(id uint64) error {
var loginLog *model.LoginLog
if err := model.DB.Model(&model.LoginLog{}).First(&loginLog, id).Error; err != nil {
return nil
}
in := &account.DecryptJwtRequest{
Token: loginLog.Token,
Domain: *loginLog.Domain,
}
return Logout(in, model.Status_Off)
}
func OnlineLogById(id uint64) (*account.LoginLog, error) {
var log *model.LoginLog
//失效时间大于当前时间
if err := model.DB.Model(&model.LoginLog{}).
First(&log, id).Error; err != nil {
return nil, err
}
res := &account.LoginLog{
ID: uint64(log.ID),
UserId: uint64(log.UserId),
Ip: log.Ip,
Status: uint64(log.Status),
ExpireDate: log.ExpireDate,
LastDate: log.LastDate,
LogoutDate: log.LogoutDate,
Address: log.Address,
CreatedAt: log.CreatedAt.Format("2006-01-02 15:04:05"),
}
return res, nil
}
// OnlineLogList 获取用户当前的在线记录
func OnlineLogList(in *account.LoginInfosByUserIdRequest) []*account.LoginLog {
var loginLogs []*model.LoginLog
var logs []*account.LoginLog
//失效时间大于当前时间
model.DB.Model(&model.LoginLog{}).
Where(&model.LoginLog{UserId: uint(in.UserId), Status: model.Status_In}).
Where("expire_date > ?", time.Now().Format("2006-01-02 15:04:05")).
Find(&loginLogs)
for _, t := range loginLogs {
temp := &account.LoginLog{
ID: uint64(t.ID),
UserId: uint64(t.UserId),
Ip: t.Ip,
//Token: t.Token,
Status: uint64(t.Status),
ExpireDate: t.ExpireDate,
LastDate: t.LastDate,
LogoutDate: t.LogoutDate,
}
logs = append(logs, temp)
}
return logs
}
// IsSampleAddress 获取用户当前的在线记录
func IsSampleAddress(nowIp string, userId uint64) (bool, error) {
var loginLog *model.LoginLog
if config.AppConfig.System.Mode == "dev" {
return true, nil
}
//失效时间大于当前时间
if err := model.DB.Model(&model.LoginLog{}).
Where(&model.LoginLog{UserId: uint(userId)}).
Where("status in (?)", []uint8{model.Status_In, model.Status_Out}).
Order("id desc").
First(&loginLog).Error; err != nil {
return false, err
}
if loginLog.Ip == nowIp { //两个ip一样直接退出
return true, nil
}
location, err1 := utils.AliIpAddress(loginLog.Ip)
nowLocation, err2 := utils.AliIpAddress(nowIp)
fmt.Println("查询ip地址:", err1, err2, location, nowIp, nowLocation)
if err1 == nil && err2 == nil {
if location == nowLocation {
return true, nil
} else {
return false, nil
}
}
return true, nil
}
// GetIpAddressByIp 根据ip获取时间
func GetIpAddressByIp(nowIp string) string {
tempKey := redis_key.GetIpAddressKey(nowIp)
cache.RedisClient.Get(redis_key.GetIpAddressKey(nowIp))
val, _ := cache.RedisClient.Get(tempKey).Result()
if val != "" {
return val
}
/*
if err == redis.Nil {
fmt.Println("键 'mykey' 不存在")
} else if err != nil {
panic(err)
} else {
fmt.Println("键 'mykey' 的值为:", val)
}
*/
location, _ := utils.AliIpAddress(nowIp)
cache.RedisClient.Set(tempKey, location, 3*24*time.Hour)
return location
}
func IsPublicIp(ipString string) bool {
ip := net.ParseIP(ipString)
if ip == nil {
fmt.Println("Invalid IP")
return false
}
if ip.IsLoopback() {
fmt.Println("Loopback IP")
return false
}
if ip.To4() != nil {
if ip[0] == 10 {
fmt.Println("Private network IP")
return false
}
if ip[0] == 172 && (ip[1]&0xf0) == 16 {
return false
}
if ip[0] == 192 && ip[1] == 168 {
return false
}
}
return true
}
func GetAddressByID(domain string, userId uint64) string {
var loginLog *model.LoginLog
//失效时间大于当前时间
if err := model.DB.Model(&model.LoginLog{}).
Where(&model.LoginLog{UserId: uint(userId), Domain: &domain}).
Where("status in (?)", []uint8{model.Status_In, model.Status_Out}).
Order("id desc").
First(&loginLog).Error; err != nil {
return ""
}
return loginLog.Address
}

View File

@ -0,0 +1,36 @@
package application
import (
"github.com/fonchain_enterprise/micro-account/pkg/cache"
"testing"
)
func TestGetIpAddressByIp2(t *testing.T) {
config := cache.RedisConfig{
RedisDB: "2",
RedisAddr: "127.0.0.1:6379",
RedisPw: "",
RedisDbName: "2",
}
cache.LoadRedis(config)
type args struct {
nowIp string
}
tests := []struct {
name string
args args
want string
}{
{args: args{nowIp: "58.210.42.242"}},
// TODO: Add test cases.
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got := GetIpAddressByIp(tt.args.nowIp); got != tt.want {
t.Errorf("GetIpAddressByIp() = %v, want %v", got, tt.want)
}
})
}
}

58
pkg/application/token.go Normal file
View File

@ -0,0 +1,58 @@
package application
import (
"errors"
"github.com/fonchain_enterprise/micro-account/pkg/m"
"github.com/fonchain_enterprise/micro-account/pkg/model"
"gorm.io/gorm"
"time"
)
// AddRefreshToken 签发refreshtoken记录
func AddRefreshToken(token string) error {
var count int64
model.DB.Model(&model.RefreshToken{}).Where(&model.RefreshToken{RefreshToken: token}).Count(&count)
if count > 0 {
return nil
}
//记录登录信息
refreshToken := &model.RefreshToken{
RefreshToken: token,
UseNum: 0,
LastUseDate: time.Now().Format("2006-01-02 15:04:05"),
IsForbid: model.IsForBid_No,
ExpireDate: time.Now().Add(time.Duration(m.RefreshTokenTime) * time.Hour).Format("2006-01-02 15:04:05"), //过期时间
}
return model.DB.Create(&refreshToken).Error
}
func CheckRefreshToke(token string) error {
var refrshTokenObj *model.RefreshToken
if err := model.DB.Model(&model.RefreshToken{}).Where(&model.RefreshToken{RefreshToken: token}).First(&refrshTokenObj).Error; err != nil {
if err == gorm.ErrRecordNotFound {
return errors.New("this refresh_token is not exist")
}
return err
}
if refrshTokenObj.IsForbid == model.IsForBid_Yes {
return errors.New("this refresh_token is forbidden")
}
if refrshTokenObj.UseNum > 0 {
return errors.New("this refresh_token is used")
}
//记录登录信息
updateLog := &model.RefreshToken{
UseNum: refrshTokenObj.UseNum + 1,
LastUseDate: time.Now().Format("2006-01-02 15:04:05"),
}
return model.DB.Model(&model.RefreshToken{}).Where(&model.RefreshToken{ID: refrshTokenObj.ID}).Updates(&updateLog).Error
}

145
pkg/application/user.go Normal file
View File

@ -0,0 +1,145 @@
package application
import (
"fmt"
"github.com/fonchain_enterprise/micro-account/api/account"
"github.com/fonchain_enterprise/micro-account/pkg/m"
"github.com/fonchain_enterprise/micro-account/pkg/model"
)
var (
authDb = "fontree-auth_v1"
)
func List(in *account.ListV2Request, limit int, offset int) ([]*model.User, int64) {
var list []*model.User
var count int64
fmt.Println("进入查看测试测试车")
//获取自己领导的部门
//Select("a.*,a.id as tid").
selectStr :=
`
ANY_VALUE(a.id) as id,
ANY_VALUE(a.created_at) as created_at,
ANY_VALUE(a.updated_at) as updated_at,
ANY_VALUE(a.deleted_at) as deleted_at,
ANY_VALUE(a.account) as account,
ANY_VALUE(a.mnemonic_words ) as mnemonic_words,
ANY_VALUE(a.tel_num) as tel_num,
ANY_VALUE(a.password_digest) as password_digest,
ANY_VALUE(a.nickname) as nickname,
ANY_VALUE(a.status) as status,
ANY_VALUE(a.avatar) as avatar,
ANY_VALUE(a.real_name_id) as real_name_id,
ANY_VALUE(a.auth) as auth,
ANY_VALUE(a.theme_id) as theme_id,
ANY_VALUE(a.domain) as domain,
ANY_VALUE(a.public_key) as public_key,
ANY_VALUE(a.is_need_change) as is_need_change,
ANY_VALUE(a.enter_date) as enter_date,
ANY_VALUE(a.extend) as extend,
ANY_VALUE(a.title) as title,
ANY_VALUE(a.job_num) as job_num,
ANY_VALUE(a.birth_date) as birth_date,
ANY_VALUE(a.sex) as sex,
ANY_VALUE(a.last_login_date) as last_login_date,
ANY_VALUE(a.ip) as ip,
ANY_VALUE(a.invitation_code) as invitation_code,
ANY_VALUE(a.left_date) as left_date,
ANY_VALUE(a.remark) as remark,
ANY_VALUE(a.recent_img) as recent_img,
ANY_VALUE(a.english_name) as english_name,
ANY_VALUE(a.mail_account) as mail_account,
ANY_VALUE(a.ic_num) as ic_num,
ANY_VALUE(a.train) as train,
ANY_VALUE(a.certificate) as certificate,
ANY_VALUE(a.operator) as operator
`
searchObj := model.DB.
Table("user as a").
Select(selectStr).
Joins("LEFT JOIN `"+authDb+"`.hierarchy_dep_position_user b ON b.user_id = a.id and b.deleted_at = 0").
Joins("LEFT JOIN `"+authDb+"`.hierarchy_position c ON c.id = b.position_id and c.deleted_at = 0").
Joins("LEFT JOIN `"+authDb+"`.hierarchy_hierarchy d ON d.id = b.department_id and d.deleted_at = 0").
Where("a.domain = ?", in.Domain).
Where("a.deleted_at = 0").
Order("a.id desc")
if in.NickName != "" {
searchObj = searchObj.Where("a.nickname like ?", "%"+in.NickName+"%")
}
if in.TelNum != "" {
searchObj = searchObj.Where("a.tel_num = ?", in.TelNum)
}
if in.Status != "" {
searchObj = searchObj.Where("a.status = ?", in.Status)
}
if in.PositionName != "" {
searchObj = searchObj.Where("c.name like ?", "%"+in.PositionName+"%")
}
if in.PositionId != 0 {
searchObj = searchObj.Where("b.position_id = ?", in.PositionId)
}
if in.DepartmentId != 0 {
searchObj = searchObj.Where("b.department_id = ?", in.DepartmentId)
}
if len(in.DepartmentIds) != 0 {
searchObj = searchObj.Where("b.department_id in (?)", in.DepartmentIds)
}
if in.DepartmentName != "" {
searchObj = searchObj.Where("d.name like ?", "%"+in.DepartmentName+"%")
}
if len(in.DepartmentNames) > 0 && len(in.DepartmentNames) <= 10 {
nameQueries := model.DB
for _, k := range in.DepartmentNames {
nameQueries = nameQueries.Or("d.name like ?", "%"+k+"%")
}
searchObj = searchObj.Where(nameQueries)
}
if in.JobNum != "" {
searchObj = searchObj.Where("a.job_num = ?", in.JobNum)
//searchObj = searchObj.Where(model.User{JobNum: in.JobNum})
}
if in.MailAccount != "" {
searchObj = searchObj.Where("a.mail_account = ?", in.MailAccount)
//searchObj = searchObj.Where(model.User{JobNum: in.JobNum})
}
if in.StartEnterDate != "" {
searchObj = searchObj.Where("a.enter_date >= ?", in.StartEnterDate)
//searchObj = searchObj.Where(model.User{JobNum: in.JobNum})
}
if in.EndEnterDate != "" {
searchObj = searchObj.Where("a.enter_date <= ?", in.EndEnterDate)
}
searchObj = searchObj.Where("a.deleted_at = 0")
searchObj.Select("COUNT(DISTINCT a.id)").Scan(&count)
searchObj.Select(selectStr).Group("a.id").Limit(limit).Offset(offset).Find(&list)
fmt.Println("进入查看测试测试车结束")
return list, count
}
func SynNickName(in *account.UpdateRequest) {
if in.Domain == m.DefaultDomain {
model.DB.Table(authDb+".hierarchy_department_user").Where("user_id = ?", in.ID).Update("user_name", in.NickName)
}
}

View File

@ -0,0 +1 @@
package application

25
pkg/blockchain/common.go Normal file
View File

@ -0,0 +1,25 @@
package blockchain
import (
"fmt"
"github.com/fonchain_enterprise/utils/chain"
)
//ChainClient 区块链单例
var (
ChainClient chain.BlockChain
)
type ChainConfig struct {
IP string
AdminMnemonicWords string
AdminContractAccount string
ContractName string
ContractType string
}
func LoadEnv(chainConfig ChainConfig) {
//从本地读取环境变量
fmt.Println("1----", chainConfig)
ChainClient = chain.NewXuperChain(chainConfig.IP, chainConfig.AdminMnemonicWords, chainConfig.ContractName, chainConfig.ContractType, chainConfig.AdminContractAccount)
}

92
pkg/cache/common.go vendored Normal file
View File

@ -0,0 +1,92 @@
package cache
import (
"errors"
"fmt"
"github.com/fonchain_enterprise/utils/zap_log"
"strconv"
"time"
"dubbo.apache.org/dubbo-go/v3/common/logger"
"github.com/go-redis/redis"
)
// RedisClient Redis缓存客户端单例
var (
RedisClient *redis.Client
)
var deleteScript = `
if redis.call("get",KEYS[1]) == ARGV[1] then
return redis.call("del",KEYS[1])
else
return 0
end
`
type RedisConfig struct {
RedisDB string
RedisAddr string
RedisPw string
RedisDbName string
}
//LoadRedis 在中间件中初始化redis链接
func LoadRedis(configEnv RedisConfig) {
db, _ := strconv.ParseUint(configEnv.RedisDbName, 10, 64)
client := redis.NewClient(&redis.Options{
Addr: configEnv.RedisAddr,
Password: configEnv.RedisPw,
DB: int(db),
})
_, err := client.Ping().Result()
if err != nil {
logger.Info(err)
panic(err)
}
RedisClient = client
}
//LockConcurrency 锁死并发
func LockConcurrency(key string, value string, ms time.Duration) (bool, error) {
fmt.Println(ms)
setNx := RedisClient.SetNX(key, value, ms)
result, err := setNx.Result()
if err != nil {
zap_log.Error(fmt.Sprintf("锁死加解密的时候redis 失效,err%s,%v", key, err))
//panic(err)
return false, err
}
if result {
zap_log.Info(fmt.Sprintf("新增key存在设置成功%s", key))
} else {
zap_log.Info(fmt.Sprintf("新增key已存在设置失败%s", key))
}
zap_log.Info(fmt.Sprintf("日志%v%v%s", result, err, key))
if setNx.Val() == false {
return false, errors.New("已经被人锁定")
}
return true, nil
}
func Release(key, value string) error {
result, err := RedisClient.Eval(deleteScript, []string{key}, value).Result()
if err != nil {
return err
}
// 判断Lua脚本执行的结果
if result == int64(1) {
fmt.Println("Lock released.")
return nil
} else {
fmt.Println("Failed to release lock, or lock was not held by this client.")
return errors.New("释放失败也可能是超时自动解锁了,请您刷新")
}
}

80
pkg/cache/common_test.go vendored Normal file
View File

@ -0,0 +1,80 @@
package cache
import (
"fmt"
"testing"
"time"
)
func TestLockConcurrency(t *testing.T) {
config := RedisConfig{
RedisDB: "2",
RedisAddr: "127.0.0.1:6379",
RedisPw: "",
RedisDbName: "2",
}
LoadRedis(config)
type args struct {
key string
value string
ms time.Duration
}
tests := []struct {
name string
args args
want bool
}{
// TODO: Add test cases.
{args: args{key: "a:b:c", value: "1", ms: 10000 * time.Millisecond}},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got, _ := LockConcurrency(tt.args.key, tt.args.value, tt.args.ms); got != tt.want {
t.Errorf("LockConcurrency() = %v, want %v", got, tt.want)
}
})
}
}
func TestRelease(t *testing.T) {
config := RedisConfig{
RedisDB: "2",
RedisAddr: "127.0.0.1:6379",
RedisPw: "",
RedisDbName: "2",
}
LoadRedis(config)
key := "abe"
concurrency, err := LockConcurrency(key, "1", 10*time.Second)
fmt.Println(concurrency, err)
if err != nil {
return
}
err = Release(key, "2")
fmt.Println(err)
type args struct {
key string
value string
}
tests := []struct {
name string
args args
wantErr bool
}{
// TODO: Add test cases.
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if err := Release(tt.args.key, tt.args.value); (err != nil) != tt.wantErr {
t.Errorf("Release() error = %v, wantErr %v", err, tt.wantErr)
}
})
}
}

View File

@ -0,0 +1,89 @@
package dingding
import (
"encoding/json"
"fmt"
"net/http"
"strings"
)
// DingClient
var (
//DingClient *DingConfig
)
type DingConfig struct {
AccessToken string
Url string
}
type DingMsg struct {
project string
AppMode string
Url string
Info string
Err error
}
type DingText struct {
Content string `json:"content"`
}
type DingMsgInfo struct {
Msgtype string `json:"msgtype"`
Text DingText `json:"text"`
}
var dingClient *DingConfig
func LoadAccessToken(accessToken string) {
dingClient = &DingConfig{
AccessToken: accessToken,
Url: "https://oapi.dingtalk.com/robot/send",
}
}
func (d *DingConfig) SendMsg(text string) {
url := d.Url + "?access_token=" + d.AccessToken
dingMsgInfo := DingMsgInfo{
Msgtype: "text",
Text: DingText{
Content: text,
},
}
dingMsgInfoByte, _ := json.Marshal(dingMsgInfo)
res, err := http.Post(
url,
"application/json",
strings.NewReader(string(dingMsgInfoByte)))
if err != nil {
fmt.Println("发送错误:", url, err, string(dingMsgInfoByte))
}
defer res.Body.Close()
return
}
func Send(info string) {
msg := DingMsg{
Info: info,
}
SendInfo(msg)
}
func SendInfo(msg DingMsg) {
text := "通知:\n" + msg.Info
if msg.Err != nil {
text = text + "错误:" + msg.Err.Error() + "/n"
}
dingClient.SendMsg(text)
return
}

View File

@ -0,0 +1,68 @@
package encryption
import (
"bytes"
"crypto/aes"
"crypto/cipher"
"crypto/md5"
"encoding/hex"
)
var (
SALT string = "c-1ha$i#nfon901"
)
func AesKey(id string) []byte {
var aesKey string
h := md5.New()
h.Write([]byte(id + SALT))
aesKey = hex.EncodeToString(h.Sum(nil))
return []byte(aesKey)
}
func PKCS7Padding(ciphertext []byte, blockSize int) []byte {
padding := blockSize - len(ciphertext)%blockSize
padtext := bytes.Repeat([]byte{byte(padding)}, padding)
return append(ciphertext, padtext...)
}
func PKCS7UnPadding(origData []byte) []byte {
length := len(origData)
unpadding := int(origData[length-1])
return origData[:(length - unpadding)]
}
//AES加密,CBC
func AesEncrypt(origData []byte, id string) ([]byte, error) {
key := AesKey(id)
block, err := aes.NewCipher(key)
if err != nil {
return nil, err
}
blockSize := block.BlockSize()
origData = PKCS7Padding(origData, blockSize)
blockMode := cipher.NewCBCEncrypter(block, key[:blockSize])
crypted := make([]byte, len(origData))
blockMode.CryptBlocks(crypted, origData)
return crypted, nil
}
//AES解密
func AesDecrypt(crypted []byte, id string) ([]byte, error) {
key := AesKey(id)
block, err := aes.NewCipher(key)
if err != nil {
return nil, err
}
blockSize := block.BlockSize()
blockMode := cipher.NewCBCDecrypter(block, key[:blockSize])
origData := make([]byte, len(crypted))
blockMode.CryptBlocks(origData, crypted)
origData = PKCS7UnPadding(origData)
return origData, nil
}

View File

@ -0,0 +1,70 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package filter
import (
"context"
"github.com/fonchain_enterprise/micro-account/pkg/e"
perrors "github.com/pkg/errors"
"regexp"
"strconv"
)
import (
"dubbo.apache.org/dubbo-go/v3/common/extension"
"dubbo.apache.org/dubbo-go/v3/filter"
"dubbo.apache.org/dubbo-go/v3/protocol"
)
type validator interface {
Validate() error
}
func init() {
extension.SetFilter("fonValidateFilter", NewFonValidateFilter)
}
func NewFonValidateFilter() filter.Filter {
return &FonValidateFilter{}
}
type FonValidateFilter struct {
}
func (f *FonValidateFilter) Invoke(ctx context.Context, invoker protocol.Invoker, invocation protocol.Invocation) protocol.Result {
if len(invocation.Arguments()) > 0 {
if v, ok := invocation.Arguments()[0].(validator); ok {
if err := v.Validate(); err != nil {
errMsg := err.Error()
re3, _ := regexp.Compile(`^invalid(.*): `)
rep := re3.ReplaceAllString(errMsg, "")
if errCode, err := strconv.ParseInt(rep, 10, 64); err == nil {
return &protocol.RPCResult{Err: perrors.Errorf("%v", e.GetMsg(int(errCode)))}
}
return &protocol.RPCResult{Err: perrors.Errorf("%v", rep)}
}
}
}
return invoker.Invoke(ctx, invocation)
}
func (f *FonValidateFilter) OnResponse(ctx context.Context, result protocol.Result, invoker protocol.Invoker, protocol protocol.Invocation) protocol.Result {
return result
}

100
pkg/common/jwt/jwt.go Normal file
View File

@ -0,0 +1,100 @@
package jwt
import (
"github.com/fonchain_enterprise/micro-account/pkg/m"
"math/rand"
"time"
"github.com/dgrijalva/jwt-go"
)
type Claims struct {
ID uint `json:"id"`
Account string `json:"account"`
Domain string `json:"domain"`
NickName string `json:"nickName"`
Phone string `json:"phone"`
jwt.StandardClaims
}
type RefreshClaims struct {
ID uint `json:"id"`
RId int `json:"rid"`
jwt.StandardClaims
}
func GenerateTotalToken(id uint, domain string, hour int, phone string, jwtSecret []byte) (string, string, error) {
token, err := GenerateToken(id, domain, hour, phone, jwtSecret)
if err != nil {
return "", "", err
}
refreshToken, err := GenerateRefreshToken(id, domain, m.RefreshTokenTime, jwtSecret)
if err != nil {
return "", "", err
}
return token, refreshToken, err
}
// GenerateToken 签发用户Token
func GenerateToken(id uint, domain string, hour int, phone string, jwtSecret []byte) (string, error) {
nowTime := time.Now()
expireTime := nowTime.Add(time.Duration(hour) * time.Hour)
claims := Claims{
ID: id,
//Account: account,
Domain: domain,
//NickName: nickName,
Phone: phone,
StandardClaims: jwt.StandardClaims{
ExpiresAt: expireTime.Unix(),
Issuer: "mall",
},
}
tokenClaims := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
token, err := tokenClaims.SignedString(jwtSecret)
return token, err
}
// ParseToken 验证用户token
func ParseToken(token string, jwtSecret []byte) (*Claims, error) {
tokenClaims, err := jwt.ParseWithClaims(token, &Claims{}, func(token *jwt.Token) (interface{}, error) {
return jwtSecret, nil
})
if tokenClaims != nil {
if claims, ok := tokenClaims.Claims.(*Claims); ok && tokenClaims.Valid {
return claims, nil
}
}
return nil, err
}
// GenerateRefreshToken 签发用户Token
func GenerateRefreshToken(id uint, domain string, hour int, jwtSecret []byte) (string, error) {
nowTime := time.Now()
expireTime := nowTime.Add(time.Duration(hour) * time.Hour)
claims := RefreshClaims{
ID: id,
RId: rand.Intn(999),
StandardClaims: jwt.StandardClaims{
ExpiresAt: expireTime.Unix(),
Issuer: domain,
},
}
tokenClaims := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
token, err := tokenClaims.SignedString(jwtSecret)
return token, err
}
// ParseRefreshToken 验证用户token
func ParseRefreshToken(token string, jwtSecret []byte) (*RefreshClaims, error) {
tokenClaims, err := jwt.ParseWithClaims(token, &RefreshClaims{}, func(token *jwt.Token) (interface{}, error) {
return jwtSecret, nil
})
if tokenClaims != nil {
if claims, ok := tokenClaims.Claims.(*RefreshClaims); ok && tokenClaims.Valid {
return claims, nil
}
}
return nil, err
}

View File

@ -0,0 +1,38 @@
package jwt
import (
"fmt"
"github.com/fonchain_enterprise/micro-account/pkg/m"
"testing"
"time"
)
func TestParseToken(t *testing.T) {
str := "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MjMzLCJhY2NvdW50IjoiVU1jektDWDVTRHpnZm43eDZkNTFLMTYxaThZNlhjdWVNIiwiZG9tYWluIjoiYXJ0aXN0aW5mbyIsIm5pY2tOYW1lIjoiMTM5NjIzMTA3NjUiLCJwaG9uZSI6IjEzOTYyMzEwNzY1IiwiZXhwIjoxNjg0NzYyMjY2LCJpc3MiOiJtYWxsIn0.8zG3OA9uRJnzxYorQ2_cK6FhQuMlsi7WF8zkIic1ggM"
str = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6NDAsImFjY291bnQiOiJUZW5hR2U4b0w1S3FzYkpnbUxGYUQxenN5WFU2azNMZ3MiLCJkb21haW4iOiJmb250cmVlIiwibmlja05hbWUiOiLotoXnuqfnrqHnkIYiLCJwaG9uZSI6IjEyMjMzNDQ1NTY2IiwiZXhwIjoxNjk3MTM3NTc0LCJpc3MiOiJtYWxsIn0.rHt4rYi8lgOhaHDscHjRsYBbSdcaz-uCXJyXroih62I"
claims, err := ParseToken(str, m.JWTSecret)
fmt.Println(err)
fmt.Println(claims)
}
func TestParseToken2(t *testing.T) {
t1 := time.Now()
fmt.Print(GenerateToken(70, "", "fontree", "耿阳"+
"", -m.TokenTime, "18205052627", m.JWTSecret))
fmt.Println(time.Now().Sub(t1))
}
func TestRefreshToken(t *testing.T) {
str1, err := GenerateRefreshToken(70, "fontree", 20, m.JWTSecret)
fmt.Println(str1, err)
//str := "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MjMzLCJhY2NvdW50IjoiVU1jektDWDVTRHpnZm43eDZkNTFLMTYxaThZNlhjdWVNIiwiZG9tYWluIjoiYXJ0aXN0aW5mbyIsIm5pY2tOYW1lIjoiMTM5NjIzMTA3NjUiLCJwaG9uZSI6IjEzOTYyMzEwNzY1IiwiZXhwIjoxNjg0NzYyMjY2LCJpc3MiOiJtYWxsIn0.8zG3OA9uRJnzxYorQ2_cK6FhQuMlsi7WF8zkIic1ggM"
claims, err := ParseRefreshToken(str1, m.JWTSecret)
fmt.Println(err)
fmt.Println(claims)
}

44
pkg/common/log/gorm.go Normal file
View File

@ -0,0 +1,44 @@
package log
import (
"context"
"fmt"
"go.uber.org/zap"
"gorm.io/gorm/logger"
"time"
)
func NewGormLogger() logger.Interface {
return &zapLogger{zapFakeLog.GetZapLogger()}
}
type zapLogger struct {
logger *zap.Logger
}
func (l *zapLogger) LogMode(level logger.LogLevel) logger.Interface {
newLogger := *l
return &newLogger
}
func (l *zapLogger) Info(ctx context.Context, s string, args ...interface{}) {
l.logger.Info(fmt.Sprintf(s, args...))
}
func (l *zapLogger) Warn(ctx context.Context, s string, args ...interface{}) {
l.logger.Warn(fmt.Sprintf(s, args...))
}
func (l *zapLogger) Error(ctx context.Context, s string, args ...interface{}) {
l.logger.Error(fmt.Sprintf(s, args...))
}
func (l *zapLogger) Trace(ctx context.Context, begin time.Time, fc func() (string, int64), err error) {
if err != nil {
l.Error(ctx, "[%.3fms] [error] %v", time.Since(begin).Seconds()*1000, err)
return
}
sql, rows := fc()
l.Info(ctx, "[%.3fms] [rows:%v] %s", time.Since(begin).Seconds()*1000, rows, sql)
}

35
pkg/common/log/init.go Normal file
View File

@ -0,0 +1,35 @@
package log
import (
"fmt"
"gopkg.in/yaml.v2"
"io/ioutil"
"os"
)
func init() {
bytes, err := getConfig()
var info *DuInfo
if err = yaml.Unmarshal(bytes, &info); err != nil {
panic(err)
}
InitLogger(info.Config)
return
}
func getConfig() ([]byte, error) {
configFilePath := "../conf/log.yaml"
_, err := os.Stat(configFilePath)
if os.IsNotExist(err) {
fmt.Println("-----------不存在")
} else {
fmt.Println("------------存在")
}
return ioutil.ReadFile(configFilePath)
}

141
pkg/common/log/log.go Normal file
View File

@ -0,0 +1,141 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package log
import (
"fmt"
"github.com/natefinch/lumberjack"
"go.uber.org/zap"
"go.uber.org/zap/zapcore"
)
var zapFakeLog *ZapLoggerFake
type DuInfo struct {
Config *Config `yaml:"logger"`
}
type Config struct {
LumberjackConfig *lumberjack.Logger `yaml:"lumberjack-config"`
ZapConfig *zap.Config `yaml:"zap-config"`
CallerSkip int
}
type ZapLoggerFake struct {
logger *zap.Logger
}
// InitLogger use for init logger by @conf
func InitLogger(conf *Config) {
var (
_ *zap.Logger
config = &Config{}
)
if conf == nil || conf.ZapConfig == nil {
zapLoggerEncoderConfig := zapcore.EncoderConfig{
TimeKey: "time",
LevelKey: "level",
NameKey: "logger",
CallerKey: "caller",
MessageKey: "message",
StacktraceKey: "stacktrace",
EncodeLevel: zapcore.CapitalColorLevelEncoder,
EncodeTime: zapcore.ISO8601TimeEncoder,
EncodeDuration: zapcore.SecondsDurationEncoder,
EncodeCaller: zapcore.ShortCallerEncoder,
}
config.ZapConfig = &zap.Config{
Level: zap.NewAtomicLevelAt(zap.InfoLevel),
Development: false,
Encoding: "console",
EncoderConfig: zapLoggerEncoderConfig,
OutputPaths: []string{"stderr"},
ErrorOutputPaths: []string{"stderr"},
}
} else {
config.ZapConfig = conf.ZapConfig
}
if conf != nil {
config.CallerSkip = conf.CallerSkip
}
if config.CallerSkip == 0 { //因为包装了两层所以设置3次
config.CallerSkip = 3
}
var zapLogger *zap.Logger
if conf == nil || conf.LumberjackConfig == nil {
zapLogger, _ = config.ZapConfig.Build(zap.AddCaller(), zap.AddCallerSkip(config.CallerSkip))
} else {
config.LumberjackConfig = conf.LumberjackConfig
zapLogger = initZapLoggerWithSyncer(config)
}
zapFakeLog = &ZapLoggerFake{logger: zapLogger}
return
}
func GetFakeLogger() *ZapLoggerFake {
return zapFakeLog
}
func GetZapLog() *zap.Logger {
return zapFakeLog.logger
}
// initZapLoggerWithSyncer init zap Logger with syncer
func initZapLoggerWithSyncer(conf *Config) *zap.Logger {
var fields []zapcore.Field
if len(conf.ZapConfig.InitialFields) > 0 {
for key, value := range conf.ZapConfig.InitialFields {
fields = append(fields, zap.Any(key, value))
}
}
fmt.Println("配置lumber", conf.LumberjackConfig)
core := zapcore.NewCore(
conf.getEncoder(),
conf.getLogWriter(),
zap.NewAtomicLevelAt(conf.ZapConfig.Level.Level()),
)
if len(fields) >= 1 {
core = core.With(fields)
}
return zap.New(core, zap.AddCaller(), zap.AddCallerSkip(conf.CallerSkip))
}
// getEncoder get encoder by config, zapcore support json and console encoder
func (c *Config) getEncoder() zapcore.Encoder {
if c.ZapConfig.Encoding == "json" {
return zapcore.NewJSONEncoder(c.ZapConfig.EncoderConfig)
} else if c.ZapConfig.Encoding == "console" {
return zapcore.NewConsoleEncoder(c.ZapConfig.EncoderConfig)
}
return nil
}
// getLogWriter get Lumberjack writer by LumberjackConfig
func (c *Config) getLogWriter() zapcore.WriteSyncer {
return zapcore.AddSync(c.LumberjackConfig)
}

148
pkg/common/log/logging.go Normal file
View File

@ -0,0 +1,148 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package log
import (
"fmt"
"go.uber.org/zap"
"go.uber.org/zap/zapcore"
)
func (s *ZapLoggerFake) GetZapLogger() *zap.Logger {
return s.logger
}
// Debug uses fmt.Sprint to construct and log a message.
func (s *ZapLoggerFake) Debug(args ...interface{}) {
s.logAndZap(zap.DebugLevel, "", args)
}
// Info uses fmt.Sprint to construct and log a message.
func (s *ZapLoggerFake) Info(args ...interface{}) {
s.logAndZap(zap.InfoLevel, "", args)
}
// Warn uses fmt.Sprint to construct and log a message.
func (s *ZapLoggerFake) Warn(args ...interface{}) {
s.logAndZap(zap.WarnLevel, "", args)
}
// Error uses fmt.Sprint to construct and log a message.
func (s *ZapLoggerFake) Error(args ...interface{}) {
s.logAndZap(zap.ErrorLevel, "", args)
}
// Fatal uses fmt.Sprint to construct and log a message, then calls os.Exit.
func (s *ZapLoggerFake) Fatal(args ...interface{}) {
s.logAndZap(zap.FatalLevel, "", args)
}
// Debugf uses fmt.Sprintf to log a templated message.
func (s *ZapLoggerFake) Debugf(template string, args ...interface{}) {
s.log(zap.DebugLevel, template, args, nil)
}
// Infof uses fmt.Sprintf to log a templated message.
func (s *ZapLoggerFake) Infof(template string, args ...interface{}) {
s.log(zap.InfoLevel, template, args, nil)
}
// Warnf uses fmt.Sprintf to log a templated message.
func (s *ZapLoggerFake) Warnf(template string, args ...interface{}) {
s.log(zap.WarnLevel, template, args, nil)
}
// Errorf uses fmt.Sprintf to log a templated message.
func (s *ZapLoggerFake) Errorf(template string, args ...interface{}) {
s.log(zap.ErrorLevel, template, args, nil)
}
// Fatalf uses fmt.Sprintf to log a templated message, then calls os.Exit.
func (s *ZapLoggerFake) Fatalf(template string, args ...interface{}) {
s.log(zap.FatalLevel, template, args, nil)
}
func (s *ZapLoggerFake) logAndZap(lvl zapcore.Level, template string, fmtArgs []interface{}) {
s.realLogAndZap(lvl, template, fmtArgs)
}
func (s *ZapLoggerFake) realLogAndZap(lvl zapcore.Level, template string, fmtArgs []interface{}) {
if lvl < zap.DPanicLevel && !s.logger.Core().Enabled(lvl) {
return
}
args, context := s.sweetenFields(fmtArgs)
msg := getMessage(template, args)
if ce := s.logger.Check(lvl, msg); ce != nil {
ce.Write(context...)
}
}
func (s *ZapLoggerFake) log(lvl zapcore.Level, template string, fmtArgs []interface{}, context []zap.Field) {
// If logging at this level is completely disabled, skip the overhead of
// string formatting.
if lvl < zap.DPanicLevel && !s.logger.Core().Enabled(lvl) {
return
}
msg := getMessage(template, fmtArgs)
if ce := s.logger.Check(lvl, msg); ce != nil {
ce.Write(context...)
}
}
// getMessage format with Sprint, Sprintf, or neither.
func getMessage(template string, fmtArgs []interface{}) string {
if len(fmtArgs) == 0 {
return template
}
if template != "" {
return fmt.Sprintf(template, fmtArgs...)
}
if len(fmtArgs) == 1 {
if str, ok := fmtArgs[0].(string); ok {
return str
}
}
return fmt.Sprint(fmtArgs...)
}
func (s *ZapLoggerFake) sweetenFields(args []interface{}) ([]interface{}, []zap.Field) {
if len(args) == 0 {
return nil, nil
}
// Allocate enough space for the worst case; if users pass only structured
// fields, we shouldn't penalize them with extra allocations.
fields := make([]zap.Field, 0, len(args))
var newArgs []interface{}
for i := 0; i < len(args); i++ {
// This is a strongly-typed field. Consume it and move on.
if f, ok := args[i].(zap.Field); ok {
fields = append(fields, f)
} else {
newArgs = append(newArgs, args[i])
}
}
return newArgs, fields
}

10
pkg/common/page/page.go Normal file
View File

@ -0,0 +1,10 @@
package page
func GetOffset(page uint64, pageSize uint64) int {
if page <= 0 {
return 0
}
return int((page - 1) * pageSize)
}

View File

@ -0,0 +1,94 @@
package redis_key
import (
"fmt"
"github.com/alibaba/sentinel-golang/util"
"github.com/fonchain_enterprise/micro-account/pkg/common/utils"
"time"
)
const (
mobile = "mobile:"
token = "token:"
)
func UserDailyGetCoinKey(userId uint32) string {
return fmt.Sprintf("coin:micro:user::id:%d:daily:%s", userId, time.Now().Format(util.DateFormat))
}
func UserRegisterGetCoinKey(userId uint32) string {
return fmt.Sprintf("coin:micro:user::id:%d:register", userId)
}
func UserCoinLock(domain string, key uint32) string {
return fmt.Sprintf("%s:lock:user:%d", domain, key)
}
func GetAccountKey(domain, key string) string {
return domain + ":" + mobile + key
}
func VerityCode(domain, key string) string {
return domain + ":code:time:" + mobile + key
}
func BlackListKey(domain string) string {
return domain + ":blackList:" + mobile
}
func GetOnlyAccountKey(domain, key string) string {
return domain + ":only:" + mobile + key
}
func GetTokenInfo(domain, key string) string {
return domain + ":" + token + "info:" + utils.Get16MD5Encode(key)
}
func GetIpAddressKey(key string) string {
return "ip_address:" + key
}
func GetTokenLogoutInfo(domain, key string) string {
return domain + ":" + token + "logout_err:" + key
}
func GetAccountRegisterKey(domain, key string) string {
return domain + ":register:" + mobile + key
}
func GetAccountKeyCountToday(domain, key string) string {
return domain + ":count:date:" + time.Now().Format("2006-01-02") + ":" + mobile + key
}
func GetAccountKeyCountTodayHour(domain, telNum, scope string) string {
return domain + ":count:date:" + scope + ":" + time.Now().Format("2006-01-02 15") + ":" + telNum
}
func MinLimit(domain, telNum, scope string) string {
return domain + ":count:min_limit:" + scope + ":" + telNum
}
func GetChangeTelKey(domain, key string, id string) string {
return domain + ":changeTel:" + mobile + id + ":" + key
}
func GetOneMinuteKey(domain, key string, id string) string {
return domain + ":minute:" + mobile + id + ":" + key
}
func GetNowNewTelById(domain string, id string) string {
return domain + ":now_tel:" + id
}
func GetBoxAccessToken(key string) string {
return "box:access_token:" + key
}
func GetWxAccessToken(key string) string {
return "box:access_token:" + key
}
// GetCheckPasswordRate 限制解密 频率
func GetCheckPasswordRate(domain, tel string) string {
return domain + ":check:psd:" + mobile + tel
}

View File

@ -0,0 +1,220 @@
package idnum
import (
"errors"
"strconv"
"time"
)
var weight = [17]int{7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2}
var valid_value = [11]byte{'1', '0', 'X', '9', '8', '7', '6', '5', '4', '3', '2'}
var valid_province = []string{
"11", // 北京市
"12", // 天津市
"13", // 河北省
"14", // 山西省
"15", // 内蒙古自治区
"21", // 辽宁省
"22", // 吉林省
"23", // 黑龙江省
"31", // 上海市
"32", // 江苏省
"33", // 浙江省
"34", // 安徽省
"35", // 福建省
"36", // 山西省
"37", // 山东省
"41", // 河南省
"42", // 湖北省
"43", // 湖南省
"44", // 广东省
"45", // 广西壮族自治区
"46", // 海南省
"50", // 重庆市
"51", // 四川省
"52", // 贵州省
"53", // 云南省
"54", // 西藏自治区
"61", // 陕西省
"62", // 甘肃省
"63", // 青海省
"64", // 宁夏回族自治区
"65", // 新疆维吾尔自治区
"71", // 台湾省
"81", // 香港特别行政区
"91", // 澳门特别行政区
}
// Check citizen number 18 valid.
func IsValidCitizenNo18(citizenNo18 *[]byte) bool {
nLen := len(*citizenNo18)
if nLen != 18 {
return false
}
nSum := 0
for i := 0; i < nLen-1; i++ {
n, _ := strconv.Atoi(string((*citizenNo18)[i]))
nSum += n * weight[i]
}
mod := nSum % 11
if valid_value[mod] == (*citizenNo18)[17] {
return true
}
return false
}
// Convert citizen 15 to 18.
func Citizen15To18(citizenNo15 []byte) []byte {
nLen := len(citizenNo15)
if nLen != 15 {
return nil
}
citizenNo18 := make([]byte, 0)
citizenNo18 = append(citizenNo18, citizenNo15[:6]...)
citizenNo18 = append(citizenNo18, '1', '9')
citizenNo18 = append(citizenNo18, citizenNo15[6:]...)
sum := 0
for i, v := range citizenNo18 {
n, _ := strconv.Atoi(string(v))
sum += n * weight[i]
}
mod := sum % 11
citizenNo18 = append(citizenNo18, valid_value[mod])
return citizenNo18
}
func IsLeapYear(nYear int) bool {
if nYear <= 0 {
return false
}
if (nYear%4 == 0 && nYear%100 != 0) || nYear%400 == 0 {
return true
}
return false
}
// Check birthday's year month day valid.
func CheckBirthdayValid(nYear, nMonth, nDay int) bool {
if nYear < 1900 || nMonth <= 0 || nMonth > 12 || nDay <= 0 || nDay > 31 {
return false
}
curYear, curMonth, curDay := time.Now().Date()
if nYear == curYear {
if nMonth > int(curMonth) {
return false
} else if nMonth == int(curMonth) && nDay > curDay {
return false
}
}
if 2 == nMonth {
if IsLeapYear(nYear) && nDay > 29 {
return false
} else if nDay > 28 {
return false
}
} else if 4 == nMonth || 6 == nMonth || 9 == nMonth || 11 == nMonth {
if nDay > 30 {
return false
}
}
return true
}
// Check province code valid.
func CheckProvinceValid(citizenNo []byte) bool {
provinceCode := make([]byte, 0)
provinceCode = append(provinceCode, citizenNo[:2]...)
provinceStr := string(provinceCode)
for i, _ := range valid_province {
if provinceStr == valid_province[i] {
return true
}
}
return false
}
// Check citizen number valid.
func IsValidCitizenNo(citizenNo *[]byte) bool {
nLen := len(*citizenNo)
if nLen != 15 && nLen != 18 {
return false
}
for i, v := range *citizenNo {
n, _ := strconv.Atoi(string(v))
if n >= 0 && n <= 9 {
continue
}
if v == 'X' && i == 16 {
continue
}
return false
}
if !CheckProvinceValid(*citizenNo) {
return false
}
if nLen == 15 {
*citizenNo = Citizen15To18(*citizenNo)
if citizenNo == nil {
return false
}
} else if !IsValidCitizenNo18(citizenNo) {
return false
}
nYear, _ := strconv.Atoi(string((*citizenNo)[6:10]))
nMonth, _ := strconv.Atoi(string((*citizenNo)[10:12]))
nDay, _ := strconv.Atoi(string((*citizenNo)[12:14]))
if !CheckBirthdayValid(nYear, nMonth, nDay) {
return false
}
return true
}
// Get information from citizen number. Birthday, gender, province mask.
func GetCitizenNoInfo(citizenNo []byte) (err error, birthday string, isMale bool, addrMask int) {
err = nil
birthday = ""
isMale = false
addrMask = 0
if !IsValidCitizenNo(&citizenNo) {
err = errors.New("身份号错误,请重新录入")
return
}
// Birthday information.
nYear, _ := strconv.Atoi(string(citizenNo[6:10]))
nMonth, _ := strconv.Atoi(string(citizenNo[10:12]))
nDay, _ := strconv.Atoi(string(citizenNo[12:14]))
birthday = time.Date(nYear, time.Month(nMonth), nDay, 0, 0, 0, 0, time.Local).Format("2006-01-02")
// Gender information.
genderMask, _ := strconv.Atoi(string(citizenNo[16]))
if genderMask%2 == 0 {
isMale = false
} else {
isMale = true
}
// Address code mask.
addrMask, _ = strconv.Atoi(string(citizenNo[:2]))
return
}

View File

@ -0,0 +1,172 @@
package idnum
import (
"encoding/json"
"errors"
"fmt"
"github.com/fonchain_enterprise/micro-account/pkg/cache"
"io/ioutil"
"net/http"
"net/url"
"strings"
"time"
)
var param = map[string]string{
"grant_type": "client_credentials",
"client_id": "AlbWwhnZINIy1YqWP3agQA42",
"client_secret": "NL2nT4rnGHIcpopBI93a7G85WscluOEH",
}
type IDCheckRes struct {
ErrorCode int `json:"error_code"`
ErrorMsg string `json:"error_msg"`
LogID int `json:"log_id"`
Timestamp int `json:"timestamp"`
Cached int `json:"cached"`
Result interface{} `json:"result"`
}
type TokenInfo struct {
RefreshToken string `json:"refresh_token"`
ExpiresIn int `json:"expires_in"`
Scope string `json:"scope"`
SessionKey string `json:"session_key"`
AccessToken string `json:"access_token"`
SessionSecret string `json:"session_secret"`
}
/*
Tru89O1zosjSCIN2uUlEctbE
rLgGU2gwNvEQAo0UooTwArtvqBTaL3Y3
25346530
*/
func CheckIDNumFromNet(idNum string, name string) error {
var host = "https://aip.baidubce.com/rest/2.0/face/v3/person/idmatch"
accessToken, err := getAccessToken()
fmt.Println("1百度生成token---", accessToken, err)
if err != nil {
return err
}
uri, err := url.Parse(host)
if err != nil {
fmt.Println(err)
return err
}
query := uri.Query()
query.Set("access_token", accessToken)
uri.RawQuery = query.Encode()
var params = map[string]string{}
params["id_card_number"] = idNum
params["name"] = name
sendBody, err := json.Marshal(params)
if err != nil {
fmt.Println(err)
return err
}
sendData := string(sendBody)
client := &http.Client{}
request, err := http.NewRequest("POST", uri.String(), strings.NewReader(sendData))
if err != nil {
fmt.Println(err)
return err
}
request.Header.Set("Content-Type", "application/json")
response, err := client.Do(request)
defer response.Body.Close()
result, err := ioutil.ReadAll(response.Body)
if err != nil {
fmt.Println(err)
return err
}
fmt.Println(string(result))
var res IDCheckRes
err = json.Unmarshal(result, &res)
fmt.Println(string(result))
if err != nil {
fmt.Println(err)
return err
}
if res.ErrorCode != 0 {
if res.ErrorCode == 222351 {
return errors.New("不匹配或者身份证不存在")
}
return errors.New("实名认证未通过")
}
return nil
}
func getAccessToken() (string, error) {
var tokenInfo TokenInfo
var err error
key := "baidu:Id:access_token" + param["client_id"]
strCmd := cache.RedisClient.Get(key)
accessToken := strCmd.Val()
if accessToken != "" {
err := json.Unmarshal([]byte(accessToken), &tokenInfo)
if err != nil {
return "", err
}
return tokenInfo.AccessToken, nil
}
accessToken, err = getNewAccessToken()
if err != nil {
return "", err
}
if merr := cache.RedisClient.Set(key, accessToken, 5*60*1000*time.Millisecond).Err(); merr != nil {
return "", merr
}
err = json.Unmarshal([]byte(accessToken), &tokenInfo)
if err != nil {
return "", err
}
return tokenInfo.AccessToken, nil
}
func getNewAccessToken() (string, error) {
accessToken := ""
var host = "https://aip.baidubce.com/oauth/2.0/token"
uri, err := url.Parse(host)
fmt.Println(uri)
if err != nil {
fmt.Println(err)
return accessToken, err
}
query := uri.Query()
for k, v := range param {
query.Set(k, v)
}
uri.RawQuery = query.Encode()
response, err := http.Get(uri.String())
fmt.Println(response)
if err != nil {
fmt.Println(err)
return accessToken, err
}
result, err := ioutil.ReadAll(response.Body)
if err != nil {
fmt.Println(err)
return accessToken, err
}
fmt.Println(string(result))
return string(result), err
}

View File

@ -0,0 +1,25 @@
package idnum
import (
"fmt"
"testing"
)
const (
Status_1 = iota + 1
Status_2
)
func Test_fb_recursion(t *testing.T) {
citizenNo := []byte("370406199808220116")
err, birthday, isMale, add := GetCitizenNoInfo(citizenNo)
fmt.Println(birthday, isMale, add, err)
citizenNo = []byte("370406199808220116")
err, birthday, isMale, add = GetCitizenNoInfo(citizenNo)
fmt.Println(birthday, isMale, add, err)
fmt.Println(Status_1)
fmt.Println(Status_2)
}

406
pkg/common/utils/ip.go Normal file
View File

@ -0,0 +1,406 @@
package utils
import (
"encoding/binary"
"encoding/json"
"errors"
"fmt"
"golang.org/x/text/encoding/simplifiedchinese"
"io/ioutil"
"net"
"net/http"
"os"
"path/filepath"
"strconv"
"strings"
"time"
)
const (
// DefaultDict 默认字典
DefaultDict = "./conf/data.dat"
// IndexLen 索引长度
IndexLen = 7
// RedirectMode1 国家的类型, 指向另一个指向
RedirectMode1 = 0x01
// RedirectMode2 国家的类型, 指向一个指向
RedirectMode2 = 0x02
)
type Result struct {
IP string `json:"ip"`
Location Location `json:"location"`
AdInfo AdInfo `json:"ad_info"`
}
type ResultV2 struct {
IP string `json:"ip"`
City string `json:"city"`
Country string `json:"country"`
}
type Location struct {
Lat float64 `json:"lat"`
Lng float64 `json:"lng"`
}
type AdInfo struct {
Nation string `json:"nation"`
Province string `json:"province"`
City string `json:"city"`
District string `json:"district"`
AdcodE int `json:"adcode"`
}
type IpResult struct {
Status int `json:"status"`
Message string `json:"message"`
RequestID string `json:"request_id"`
Result Result `json:"result"`
}
type IpResultV2 struct {
Ret int `json:"ret"`
Msg string `json:"Msg"`
LogId string `json:"log_id"`
Result ResultV2 `json:"data"`
}
type IPDict struct {
fileData []byte //文件数据
offset uint32 //当前下标定位
firstOffset uint32 //第一条IP记录的偏移地址
lastOffset uint32 //最后一条IP记录的偏移地址
totalIPNum uint32 //IP记录的总条数不包含版本信息记录
}
type IPLocation struct {
IP string `json:"ip"`
BeginIP string `json:"begin_ip"`
EndIP string `json:"end_ip"`
Country string `json:"country"`
Area string `json:"area"`
}
func NewIPDict() *IPDict {
return &IPDict{}
}
func (q *IPDict) Load(fileName string) error {
filePath, err := dictPath(fileName)
if err != nil {
return err
}
dictFile, err := os.OpenFile(filePath, os.O_RDONLY, 0400)
if err != nil {
return err
}
defer dictFile.Close()
q.fileData, err = ioutil.ReadAll(dictFile)
if err != nil {
return err
}
buf := q.readBuf(8)
q.firstOffset = binary.LittleEndian.Uint32(buf[:4])
q.lastOffset = binary.LittleEndian.Uint32(buf[4:])
q.totalIPNum = (q.lastOffset - q.firstOffset) / IndexLen
return nil
}
func (q *IPDict) FindIP(ip string) (*IPLocation, error) {
if false == checkIPv4(ip) {
return nil, errors.New("IP format error")
}
res := IPLocation{IP: ip}
if nil == q.fileData {
err := q.Load(DefaultDict)
if nil != err {
return nil, err
}
}
q.seekOffset(0)
index := q.findIndex(ip)
if index <= 0 {
return nil, errors.New("IP not fount")
}
q.seekOffset(index)
res.BeginIP = long2ip(q.getIPLong4()) //endIPOffset
endIPOffset := q.getRedirectOffset()
q.seekOffset(endIPOffset)
res.EndIP = long2ip(q.getIPLong4()) //endIPOffset
mode := q.readMode() // 标志字节
var country, area []byte
enc := simplifiedchinese.GBK.NewDecoder()
switch mode {
case RedirectMode1: // 标志字节为1表示国家和区域信息都被同时重定向
countryOffset := q.getRedirectOffset() // 重定向地址
q.seekOffset(countryOffset)
mode2 := q.readMode() // 标志字节
switch mode2 {
case RedirectMode2: // 标志字节为2表示国家信息又被重定向
q.seekOffset(q.getRedirectOffset()) // 重定向地址
country = q.readString(0)
q.seekOffset(countryOffset + 4) // 重定向地址
area = q.readArea()
default: // 否则,表示国家信息没有被重定向
country = q.readString(mode2)
area = q.readArea()
}
case RedirectMode2: // 标志字节为2表示国家信息被重定向
q.seekOffset(q.getRedirectOffset()) // 重定向地址
country = q.readString(0)
q.seekOffset(endIPOffset + 8)
area = q.readArea()
default:
country = q.readString(mode)
area = q.readArea()
}
countryUTF8, _ := enc.String(string(country))
if strings.Trim(countryUTF8, " ") == "CZ88.NET" {
res.Country = ""
} else {
res.Country = countryUTF8
}
areaUTF8, _ := enc.String(string(area))
if strings.Trim(areaUTF8, " ") == "CZ88.NET" {
res.Area = ""
} else {
res.Area = areaUTF8
}
return &res, nil
}
func (q *IPDict) findIndex(ip string) uint32 {
if false == checkIPv4(ip) {
return 0
}
if nil == q.fileData {
err := q.Load(DefaultDict)
if nil != err {
return 0
}
}
uIP := ip2long(ip) // 将输入的IP地址转化为可比较的IP地址
min := uint32(0) // 搜索的下边界
max := q.totalIPNum // 搜索的上边界
findIndex := q.lastOffset // 如果没有找到就返回最后一条IP记录IPDict.Dat的版本信息
for min <= max {
// 当上边界小于下边界时,查找失败
mid := (min + max) / 2 // 计算近似中间记录
q.seekOffset(q.firstOffset + mid*IndexLen)
cBeginIP := q.getIPLong4() // 获取中间记录的开始IP地址
if uIP < cBeginIP { // 用户的IP小于中间记录的开始IP地址时
max = mid - 1 // 将搜索的上边界修改为中间记录减一
} else {
q.seekOffset(q.getRedirectOffset())
cEndIP := q.getIPLong4() // 获取中间记录的开始IP地址
if uIP > cEndIP { // 用户的IP大于中间记录的结束IP地址时
min = mid + 1 // 将搜索的下边界修改为中间记录加一
} else {
// 用户的IP在中间记录的IP范围内时
findIndex = q.firstOffset + mid*IndexLen
break // 则表示找到结果,退出循环
}
}
}
return findIndex
}
//模拟文件读取Seek
func (q *IPDict) seekOffset(offset uint32) {
q.offset = offset
}
//模拟文件读取Read
func (q *IPDict) readBuf(length uint32) []byte {
q.offset = q.offset + length
return q.fileData[q.offset-length : q.offset] // 标志字节
}
//返回读取的长整型数
func (q *IPDict) getIPLong4() uint32 {
buf := q.readBuf(4)
return binary.LittleEndian.Uint32(buf)
}
//返回读取的3个字节的长整型数
func (q *IPDict) getRedirectOffset() uint32 {
buf := q.readBuf(3)
return binary.LittleEndian.Uint32([]byte{buf[0], buf[1], buf[2], 0})
}
// readString 获取字符
func (q *IPDict) readMode() byte {
return q.readBuf(1)[0] // 标志字节
}
// readString 获取字符串
func (q *IPDict) readString(char byte) []byte {
data := make([]byte, 0, 30)
if char != 0 {
data = append(data, char)
}
buf := q.readBuf(1)
for buf[0] != 0 {
data = append(data, buf[0])
buf = q.readBuf(1)
}
return data
}
// readArea 获取地区字符串
func (q *IPDict) readArea() []byte {
mode := q.readMode()
switch mode { // 标志字节
case 0: // 结束标识
return []byte{}
case RedirectMode1:
case RedirectMode2: // 标志字节为1或2表示区域信息被重定向
q.seekOffset(q.getRedirectOffset()) // 重定向地址
return q.readString(0)
}
return q.readString(mode)
}
//数值IP转换字符串IP
func long2ip(ipInt uint32) string {
// need to do two bit shifting and “0xff” masking
ipInt64 := int64(ipInt)
b0 := strconv.FormatInt((ipInt64>>24)&0xff, 10)
b1 := strconv.FormatInt((ipInt64>>16)&0xff, 10)
b2 := strconv.FormatInt((ipInt64>>8)&0xff, 10)
b3 := strconv.FormatInt(ipInt64&0xff, 10)
return b0 + "." + b1 + "." + b2 + "." + b3
}
//字符串IP转换数值IP
func ip2long(ip string) uint32 {
bIP := net.ParseIP(ip).To4()
if nil == bIP {
return 0
}
return binary.BigEndian.Uint32(bIP)
}
//返回字典绝对路径
func dictPath(dictFileName string) (string, error) {
if filepath.IsAbs(dictFileName) {
return dictFileName, nil
}
var dictFilePath string
cwd, err := os.Getwd()
if err != nil {
return dictFilePath, err
}
dictFilePath = filepath.Clean(filepath.Join(cwd, dictFileName))
return dictFilePath, nil
}
//检查ip地址
func checkIPv4(IP string) bool {
// 字符串这样切割
strList := strings.Split(IP, ".")
if len(strList) != 4 {
return false
}
for _, s := range strList {
if len(s) == 0 || (len(s) > 1 && s[0] == '0') {
return false
}
// 直接访问字符串的值
if s[0] < '0' || s[0] > '9' {
return false
}
// 字符串转数字
n, err := strconv.Atoi(s)
if err != nil {
return false
}
if n < 0 || n > 255 {
return false
}
}
return true
}
func GetIpAddress(ip string) (string, error) {
IPDict := NewIPDict()
//载入IP字典
err := IPDict.Load("../conf/qqwry.dat")
if err != nil {
return "", err
}
//查询IP
res, err := IPDict.FindIP(ip)
if err != nil {
return "", err
}
return res.Country, nil
}
func GetIpOnlyAddress(ip string) string {
IPDict := NewIPDict()
//载入IP字典
err := IPDict.Load("../conf/qqwry.dat")
if err != nil {
return ""
}
//查询IP
res, err := IPDict.FindIP(ip)
if err != nil {
return ""
}
return res.Country
}
func AliIpAddress(ip string) (string, error) {
url := "https://c2ba.api.huachen.cn/ip?ip=" + ip
client := &http.Client{
Timeout: 1 * time.Second,
}
//提交请求
reqest, err := http.NewRequest("GET", url, nil)
//增加header选项
reqest.Header.Add("Authorization", "APPCODE 89aaef07254149aabac798c911647673")
if err != nil {
fmt.Println(err)
return "", err
//panic(err)
}
//处理返回结果
response, err := client.Do(reqest)
if err != nil {
fmt.Println(err)
return "", err
}
resByte, err := ioutil.ReadAll(response.Body)
fmt.Println("1-------------", string(resByte))
var result IpResultV2
err = json.Unmarshal(resByte, &result)
fmt.Printf("1-------------%+v\n", result)
defer response.Body.Close()
return result.Result.Country + result.Result.City, nil
}
func GetIpOnlyAddressFromAli(ip string) string {
IPDict := NewIPDict()
//载入IP字典
err := IPDict.Load("../conf/qqwry.dat")
if err != nil {
return ""
}
//查询IP
res, err := IPDict.FindIP(ip)
if err != nil {
return ""
}
return res.Country
}

View File

@ -0,0 +1,11 @@
package utils
import (
"fmt"
"testing"
)
func TestAliIpAddress(t *testing.T) {
fmt.Println(AliIpAddress("58.208.146.190"))
}

19
pkg/common/utils/phone.go Normal file
View File

@ -0,0 +1,19 @@
package utils
import "regexp"
// CheckMobile 检验手机号
func CheckMobile(phone string) bool {
// 匹配规则
// ^1第一位为一
// [345789]{1} 后接一位345789 的数字
// \\d \d的转义 表示数字 {9} 接9位
// $ 结束符
regRuler := "^1[345789]{1}\\d{9}$"
// 正则调用规则
reg := regexp.MustCompile(regRuler)
// 返回 MatchString 是否匹配
return reg.MatchString(phone)
}

View File

@ -0,0 +1,45 @@
package utils
import (
"fmt"
"github.com/fonchain_enterprise/utils/feie"
"log"
"testing"
)
func TestGet16MD5Encode(t *testing.T) {
info := feie.PrintInfo{
Num: "1829",
Date: "4/27",
DrinkName: "测试",
Tag: []string{"香草*5", "焦糖*5", "果子*10"},
Code: "测试--徐嘉鸿 13834233425",
}
feie := &feie.Feie{
User: "chenyao@taifeng.ltd",
Ukey: "8mxyRrjhCKzB4Pde",
Url: "http://api.feieyun.cn/Api/Open/",
}
res, err := feie.Print("960233232", info)
fmt.Println(res, err)
}
func TestDecimalToAny(t *testing.T) {
fmt.Println(DecimalToAny(69))
IPDict := NewIPDict()
//载入IP字典
err := IPDict.Load("../../../conf/qqwry.dat")
if err != nil {
log.Fatalln(err)
}
//查询IP
res, err := IPDict.FindIP("114.218.158.24")
if err != nil {
log.Fatalln(err)
}
log.Println(res)
log.Println(res.Area)
log.Println(res.Country)
}

52
pkg/common/utils/time.go Normal file
View File

@ -0,0 +1,52 @@
package utils
import (
"fmt"
"strconv"
"time"
)
func SubYearFromNowBefore(t1 time.Time) float32 {
t2 := time.Now()
res := float64(SubMonth(t2, t1)) / 12.0
value, err := strconv.ParseFloat(fmt.Sprintf("%.1f", res), 64)
if err != nil {
return 0
}
return float32(value)
}
func SubYearFromStartAndEnd(start time.Time,end time.Time) float32 {
res := float64(SubMonth(end, start)) / 12.0
value, err := strconv.ParseFloat(fmt.Sprintf("%.1f", res), 64)
if err != nil {
return 0
}
return float32(value)
}
func SubMonth(t1, t2 time.Time) (month int) {
y1 := t1.Year()
y2 := t2.Year()
m1 := int(t1.Month())
m2 := int(t2.Month())
d1 := t1.Day()
d2 := t2.Day()
yearInterval := y1 - y2
// 如果 d1的 月-日 小于 d2的 月-日 那么 yearInterval-- 这样就得到了相差的年数
if m1 < m2 || (m1 == m2 && d1 < d2) {
yearInterval--
}
// 获取月数差值
monthInterval := (m1 + 12) - m2
if d1 < d2 {
monthInterval--
}
monthInterval %= 12
month = yearInterval*12 + monthInterval
return
}

55
pkg/common/utils/ucode.go Normal file
View File

@ -0,0 +1,55 @@
package utils
import (
"crypto/md5"
"encoding/hex"
"fmt"
)
var tenToAny map[int]string = map[int]string{
0: "0", 1: "1", 2: "2", 3: "3", 4: "4", 5: "5", 6: "6", 7: "7", 8: "8", 9: "9",
10: "a", 11: "b", 12: "c", 13: "d", 14: "e", 15: "f", 16: "g", 17: "h", 18: "i", 19: "j", 20: "k", 21: "l", 22: "m", 23: "n", 24: "o", 25: "p", 26: "q", 27: "r", 28: "s", 29: "t", 30: "u", 31: "v", 32: "w", 33: "x", 34: "y", 35: "z",
36: "A", 37: "B", 38: "C", 39: "D", 40: "E", 41: "F", 42: "G", 43: "H", 44: "I", 45: "J", 46: "K", 47: "L", 48: "M", 49: "N", 50: "O", 51: "P", 52: "Q", 53: "R", 54: "S", 55: "T", 56: "U", 57: "V", 58: "W", 59: "X", 60: "Y", 61: "Z",
}
//SetLangErr 设置英语
func SetLangErr() float32 {
return float32(0)
}
//返回一个16位md5加密后的字符串
func Get16MD5Encode(data string) string {
return GetMD5Encode(data)[8:24]
}
func GetMD5Encode(data string) string {
h := md5.New()
h.Write([]byte(data))
return hex.EncodeToString(h.Sum(nil))
}
// DecimalToAny 10进制转任意进制
func DecimalToAny(num int) string {
n := len(tenToAny)
fmt.Println("1----", n)
new_num_str := ""
var remainder int
var remainder_string string
for num != 0 {
remainder = num % n
fmt.Println(remainder)
remainder_string = tenToAny[remainder]
new_num_str = remainder_string + new_num_str
num = num / n
}
if len(new_num_str) < 8 {
j := 8 - len(new_num_str)
for i := 0; i < j; i++ {
new_num_str = "0" + new_num_str
}
}
return new_num_str
}

82
pkg/common/utils/utils.go Normal file
View File

@ -0,0 +1,82 @@
package utils
import (
"github.com/shopspring/decimal"
"unicode"
)
//HasEnglish 判断字符串是否包含英文
func HasEnglish(s string) bool {
for _, r := range s {
if unicode.Is(unicode.Latin, r) {
return true
}
}
return false
}
//HasChinese 判断字符串是否包含中文
func HasChinese(s string) bool {
for _, r := range s {
if unicode.Is(unicode.Han, r) {
return true
}
}
return false
}
//HasEnglishAndChinese 判断字符串是否同时包含英文和中文
func HasEnglishAndChinese(s string) bool {
return HasEnglish(s) && HasChinese(s)
}
//FirstIsBiggerOrEqualDec 比较两个string转化成数字对比大小
func FirstIsBiggerOrEqualDec(dec1, dec2 decimal.Decimal) (bool, error) {
// 比较 decimal.Decimal 值
if dec1.LessThan(dec2) {
return false, nil
}
return true, nil
}
//FirstIsBiggerOrEqual 比较两个string转化成数字对比大小
func FirstIsBiggerOrEqual(dec1 decimal.Decimal, b string) (bool, error) {
dec2, err := decimal.NewFromString(b)
if err != nil {
return false, err
}
// 比较 decimal.Decimal 值
if dec1.LessThan(dec2) {
return false, nil
}
return true, nil
}
//FirstIsBiggerOrEqualString 比较两个string转化成数字对比大小
func FirstIsBiggerOrEqualString(a, b string) (bool, error) {
dec1, err := decimal.NewFromString(a)
if err != nil {
return false, err
}
dec2, err := decimal.NewFromString(b)
if err != nil {
return false, err
}
// 比较 decimal.Decimal 值
if dec1.LessThan(dec2) {
return false, nil
}
return true, nil
}

View File

@ -0,0 +1,66 @@
package utils
import "testing"
func Test_hasEnglish(t *testing.T) {
type args struct {
s string
}
tests := []struct {
name string
args args
want bool
}{
{args: args{s: "阿丽米罕·色依提"}, want: false},
// TODO: Add test cases.
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got := HasEnglish(tt.args.s); got != tt.want {
t.Errorf("hasEnglish() = %v, want %v", got, tt.want)
}
})
}
}
func Test_hasEnglishAndChinese(t *testing.T) {
type args struct {
s string
}
tests := []struct {
name string
args args
want bool
}{
{args: args{s: "阿丽米罕·色依提"}, want: false},
// TODO: Add test cases.
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got := HasEnglishAndChinese(tt.args.s); got != tt.want {
t.Errorf("hasEnglishAndChinese() = %v, want %v", got, tt.want)
}
})
}
}
func Test_hasEnglishAndChinese1(t *testing.T) {
type args struct {
s string
}
tests := []struct {
name string
args args
want bool
}{
{args: args{s: "阿丽米罕·色依提"}, want: false},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got := HasEnglishAndChinese(tt.args.s); got != tt.want {
t.Errorf("hasEnglishAndChinese() = %v, want %v", got, tt.want)
}
})
}
}

View File

@ -0,0 +1,141 @@
package verifica
import (
"errors"
"fmt"
"github.com/fonchain_enterprise/micro-account/pkg/config"
"github.com/fonchain_enterprise/utils/mobile"
)
const SIG_NO = 155123
const SIG_NO_SELLER = 159789
func SendMsg(telNum string, project string) (string, error) {
var sigNo uint
sigNo = SIG_NO
if project == "seller" {
sigNo = SIG_NO_SELLER
}
mobileTemplate := config.GetMobile()
if telNum == "" {
return "", errors.New("手机号不合法")
}
code := mobile.RandCode()
//content := "验证码模板:尊敬的用户,您的验证码为$$15分钟内有效请勿泄露。"
fmt.Println("发送短信请求参数:", telNum, mobile.TMP1, sigNo, code)
/**
TODO
*/
/*
if telNum == "15895559080" {
dingding.Send(fmt.Sprintf("尊敬的用户,您的验证码为%s15分钟内有效请勿泄露。", code))
return code, nil
}
*/
fmt.Println("发送短信请求参数:", telNum, mobile.TMP1, sigNo, code)
return code, mobileTemplate.Send(telNum, mobile.TMP1, sigNo, code)
}
func SendMsgV2(telNum string, project string, tempSignNo uint) (string, error) {
var sigNo uint
sigNo = SIG_NO
if project == "seller" {
sigNo = SIG_NO_SELLER
}
mobileTemplate := config.GetMobile()
//mobileTemplate := config.GetAlMobile()
if telNum == "" {
return "", errors.New("手机号不合法")
}
code := mobile.RandCode()
//content := "验证码模板:尊敬的用户,您的验证码为$$15分钟内有效请勿泄露。"
/**
TODO
*/
/*
if telNum == "15895559080" {
dingding.Send(fmt.Sprintf("尊敬的用户,您的验证码为%s15分钟内有效请勿泄露。", code))
return code, nil
}
*/
fmt.Println("发送短信请求参数:", telNum, mobile.TMP1, sigNo, code)
return code, mobileTemplate.Send(telNum, mobile.TMP1, sigNo, code)
//fmt.Println("发送短信请求参数:", telNum, mobile.Sign, mobile.AlTMP1, code)
//return code, mobileTemplate.SendAlSms(telNum, mobile.Sign, mobile.AlTMP1, code)
}
func SendCustomMsg(telNum string, url string, m uint) error {
var sigNo uint
sigNo = SIG_NO
mobileTemplate := config.GetMobile()
if telNum == "" {
return errors.New("手机号不合法")
}
/**
TODO
if telNum == "15895559080" {
arr := strings.Split(url, "||")
if len(arr) <= 1 {
fmt.Println("解析失败")
return nil
}
if m == 134802 {
dingding.Send(fmt.Sprintf("尊敬的用户,您的帐号登陆地址(%s)异常,请点击下线该帐号%s", arr[0], arr[1]))
return nil
} else if m == 136784 {
dingding.Send(fmt.Sprintf("尊敬的用户,%s等待您的审批请点击查看%s", arr[0], arr[1]))
return nil
}
}
*/
fmt.Println(telNum, m, sigNo, url)
return mobileTemplate.Send(telNum, m, sigNo, url)
}
func SendCustomCode(telNum string, templateId uint, sigNo uint) (string, error) {
mobileTemplate := config.GetMobile()
//mobileTemplate := config.GetAlMobile()
if telNum == "" {
return "", errors.New("手机号不合法")
}
code := mobile.RandCode()
fmt.Println("发送短信请求参数:", telNum, mobile.TMP1, sigNo, code)
//fmt.Println("发送短信请求参数:", telNum, mobile.Sign, mobile.AlTMP1, code)
return code, mobileTemplate.Send(telNum, templateId, sigNo, code)
//return code, mobileTemplate.SendAlSms(telNum, mobile.Sign, mobile.AlTMP1, code)
}
func SendCustomSignNoMsg(telNum string, url string, m uint, sigNo uint) error {
mobileTemplate := config.GetMobile()
//mobileTemplate := config.GetAlMobile()
if telNum == "" {
return errors.New("手机号不合法")
}
return mobileTemplate.Send(telNum, m, sigNo, url)
//return mobileTemplate.SendAlSms(telNum, mobile.Sign, mobile.AlTMP1, url)
}

View File

@ -0,0 +1,28 @@
package verifica
import (
"fmt"
"github.com/fonchain_enterprise/micro-account/pkg/config"
"testing"
)
func TestSendCustomMsg(t *testing.T) {
msgInfo := config.MobileConfigTemplate{
AK: "N7469940cf",
SK: "74699ca8e1ea8f80",
URL: "https://api.4321.sh/sms/template",
}
almsgInfo := config.AliMessage{
AK: "LTAI5tFLAxtbtTsD4xAEtWcr",
AS: "ooHMm6GuRs1InieHojZaTjEJAMquKX",
URL: "dysmsapi.aliyuncs.com",
}
fmt.Println("短信配置", msgInfo)
config.LoadData(msgInfo, almsgInfo)
mobileTemplate := config.GetMobile()
fmt.Println(mobileTemplate.Send("18362666451", 136784, 155123, "用印申请0||https://dwz.cn/gwc1q4D8"))
}

View File

@ -0,0 +1,82 @@
package wechat
import (
"encoding/json"
"errors"
"fmt"
"github.com/fonchain_enterprise/micro-account/pkg/cache"
"io/ioutil"
"net/http"
"time"
)
type TokenInfo struct {
AccessToken string `json:"access_token"`
CreateDate string `json:"createDate"`
ErrCode int `json:"errcode"`
}
func getNowAccessToken(appID, appSecret string) (openInfo *TokenInfo, err error) {
str := "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=%s&secret=%s"
url := fmt.Sprintf(str, appID, appSecret)
resp, err := http.Get(url)
if err != nil {
fmt.Println(err)
return nil, err
}
body, err := ioutil.ReadAll(resp.Body)
defer resp.Body.Close()
if resp.StatusCode != 200 {
fmt.Printf("请求失败%d\n", resp.StatusCode)
return nil, errors.New(fmt.Sprintf("请求失败%d", resp.StatusCode))
}
fmt.Println("返回数据是", string(body))
err = json.Unmarshal(body, &openInfo)
if err != nil {
fmt.Println(err)
return nil, err
}
if openInfo.ErrCode != 0 {
fmt.Println("微信提示错误", string(body))
return nil, errors.New("微信提示错误:" + string(body))
}
return
}
func GetAccessToken(appID, appSecret string) (openInfo *TokenInfo, err error) {
key := "wx:token:" + appID
str := cache.RedisClient.Get(key)
if str.Val() != "" { //存在
err := json.Unmarshal([]byte(str.Val()), &openInfo)
return openInfo, err
}
//更新
openInfo, err = getNowAccessToken(appID, appSecret)
if err != nil {
return nil, err
}
openInfo.CreateDate = time.Now().Format("2006-01-02 15:04:05")
r, err := json.Marshal(openInfo)
fmt.Println(string(r))
_, err = cache.RedisClient.Set(key, string(r), 6500*time.Second).Result()
return openInfo, err
}

View File

@ -0,0 +1,209 @@
package tempate
import (
"bytes"
"encoding/json"
"errors"
"fmt"
"github.com/fonchain_enterprise/micro-account/pkg/cache"
"github.com/fonchain_enterprise/micro-account/pkg/common/redis_key"
"github.com/fonchain_enterprise/micro-account/pkg/common/wechat"
"github.com/google/uuid"
"io/ioutil"
"net/http"
"strconv"
)
type ClockInTemplate struct {
ToUser string `json:"touser"`
TemplateID string `json:"template_id"`
ClientMsgID string `json:"client_msg_id"`
ClockInMsgData ClockInMsgData `json:"data"`
}
type StrangerClockInTemplate struct {
ToUser string `json:"touser"`
TemplateID string `json:"template_id"`
ClientMsgID string `json:"client_msg_id"`
Url string `json:"url"`
ClockInMsgData StrangerClockInMsgData `json:"data"`
}
type Thing struct {
Value string `json:"value"`
}
type ClockInMsgData struct {
Time3 Thing `json:"time3"`
Name Thing `json:"thing1"`
Const2 Thing `json:"const2"`
Thing5 Thing `json:"thing5"`
}
type StrangerClockInMsgData struct {
Thing2 Thing `json:"thing2"`
PhoneNumber10 Thing `json:"phone_number10"`
CharacterString14 Thing `json:"character_string14"`
Thing6 Thing `json:"thing6"`
Const11 Thing `json:"const11"`
}
type ClockInTemplateMsgInfo struct {
TemplateId string
OpenId string
OperatedAt string
Name string
Address string
ClockType string
VisitorSName string
VisitorSTel string
ReasonVisit string
NumberOfPeople uint64
}
func SendStrangerWechatTempMsg(wechatObj wechat.Wechat, info ClockInTemplateMsgInfo, logID uint64) error {
appID := wechatObj.Appid
appSecret := wechatObj.AppSecret
accessToken, err := wechat.GetAccessToken(appID, appSecret)
URL := fmt.Sprintf("https://material.szjixun.cn/#/pages/control-gate/index?sn=%v&id=%v", info.Address, logID)
clockInTemplate := StrangerClockInTemplate{
ToUser: info.OpenId,
TemplateID: info.TemplateId,
ClientMsgID: uuid.New().String(),
Url: URL,
ClockInMsgData: StrangerClockInMsgData{
Thing2: Thing{info.VisitorSName}, //来访人员
PhoneNumber10: Thing{info.VisitorSTel}, //联系电话
CharacterString14: Thing{strconv.FormatUint(info.NumberOfPeople, 10)}, //随行人数
Thing6: Thing{info.Name}, //拜访人
Const11: Thing{info.ReasonVisit}, //拜访事由
},
}
msg, err := json.Marshal(clockInTemplate)
openInfo, err := sendTemplateMsg(accessToken.AccessToken, msg)
fmt.Println("提示设呢么", openInfo, err)
if err != nil {
return err
}
fmt.Println("123123--123", openInfo)
fmt.Println(openInfo.Errmsg)
fmt.Println(openInfo.Errcode)
if openInfo.Errcode != 40001 {
return nil
}
fmt.Println("不顶用")
cache.RedisClient.Del(redis_key.GetWxAccessToken(appID))
return sendTemplateMsgAgain(appID, appSecret, msg)
}
func SendWechatTemplateMsg(wechatObj wechat.Wechat, info ClockInTemplateMsgInfo) error {
clockType := "上班"
appID := wechatObj.Appid
appSecret := wechatObj.AppSecret
templateId, openId, operatedAt, Name, address, _ := info.TemplateId, info.OpenId, info.OperatedAt, info.Name, info.Address, info.ClockType
accessToken, err := wechat.GetAccessToken(appID, appSecret)
if err != nil {
return err
}
if info.ClockType == "off" {
clockType = "下班"
}
clockInTemplate := ClockInTemplate{
ToUser: openId,
TemplateID: templateId,
ClientMsgID: uuid.New().String(),
ClockInMsgData: ClockInMsgData{
Time3: Thing{Value: operatedAt},
Name: Thing{Value: Name},
Const2: Thing{Value: clockType},
Thing5: Thing{Value: address},
},
}
msg, err := json.Marshal(clockInTemplate)
openInfo, err := sendTemplateMsg(accessToken.AccessToken, msg)
fmt.Println("提示设呢么", openInfo, err)
if err != nil {
return err
}
fmt.Println("123123--123", openInfo)
fmt.Println(openInfo.Errmsg)
fmt.Println(openInfo.Errcode)
if openInfo.Errcode != 40001 {
return nil
}
fmt.Println("不顶用")
cache.RedisClient.Del(redis_key.GetWxAccessToken(appID))
return sendTemplateMsgAgain(appID, appSecret, msg)
}
func sendTemplateMsgAgain(appID, appSecret string, msg []byte) error {
accessToken, err := wechat.GetAccessToken(appID, appSecret)
if err != nil {
return err
}
openInfo, err := sendTemplateMsg(accessToken.AccessToken, msg)
fmt.Println("提示设呢么", openInfo, err)
if err != nil {
return err
}
fmt.Println("123123--123", openInfo)
fmt.Println(openInfo.Errmsg)
fmt.Println(openInfo.Errcode)
if openInfo.Errcode != 40001 {
return nil
}
return errors.New(openInfo.Errmsg)
}
// "errcode": 0,
// "errmsg": "ok",
func sendTemplateMsg(accessToken string, code []byte) (res *wechat.CommonRes, err error) {
url := "https://api.weixin.qq.com/cgi-bin/message/template/send?access_token=" + accessToken
// 创建要发送的数据
// 发送POST请求
resp, err := http.Post(url, "application/json", bytes.NewBuffer(code))
if err != nil {
fmt.Println("发送请求失败:", err)
return
}
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
if resp.StatusCode != 200 {
fmt.Printf("请求失败%d\n", resp.StatusCode)
return nil, errors.New(fmt.Sprintf("请求失败%d", resp.StatusCode))
}
fmt.Println("2--返回数据是", string(body))
err = json.Unmarshal(body, &res)
if err != nil {
fmt.Println(err)
return nil, err
}
return res, err
}

View File

@ -0,0 +1,46 @@
package tempate
import (
"github.com/fonchain_enterprise/micro-account/pkg/cache"
"github.com/fonchain_enterprise/micro-account/pkg/common/wechat"
"testing"
)
func TestSendWechatTemplateMsg(t *testing.T) {
redisConfig := cache.RedisConfig{
RedisDB: "1",
RedisAddr: "r-bp1mjimyh1ejg1mxclpd.redis.rds.aliyuncs.com:6379",
RedisPw: "fonchain_opv:kP6tW4tS3qB2dW4aE6uI5cX2",
RedisDbName: "1",
}
cache.LoadRedis(redisConfig)
type args struct {
appID string
appSecret string
templateId string
openId string
operatedAt string
Name string
address string
clockType string
}
tests := []struct {
name string
args args
wantErr bool
}{
{args: args{appID: "wx72ffc6670d5ddb12", appSecret: "50bec0ef9a7883de5b2fb3a74b23aff4", templateId: "alklszCrWJsueAOFwdlrvo2rN-XXwHqE_oHl_55kQmo", openId: "o_ath6SpAdmfaLeZD8v1mc_c-XxU", operatedAt: "2023-07-18 13:48:12", Name: "耿阳", address: "顾廷龙", clockType: "off"}},
// TODO: Add test cases.
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if err := SendWechatTemplateMsg(wechat.Wechat{Appid: tt.args.appID, AppSecret: tt.args.appSecret}, ClockInTemplateMsgInfo{TemplateId: tt.args.templateId, OpenId: tt.args.openId, OperatedAt: tt.args.operatedAt, Name: tt.args.Name, Address: tt.args.address, ClockType: tt.args.clockType}); (err != nil) != tt.wantErr {
t.Errorf("SendWechatTemplateMsg() error = %v, wantErr %v", err, tt.wantErr)
}
})
}
}

339
pkg/common/wechat/wechat.go Normal file
View File

@ -0,0 +1,339 @@
package wechat
import (
"bytes"
"encoding/json"
"errors"
"fmt"
"github.com/fonchain_enterprise/micro-account/pkg/cache"
"github.com/fonchain_enterprise/micro-account/pkg/common/redis_key"
"io/ioutil"
"net/http"
"time"
)
type Wechat struct {
Appid string
AppSecret string
}
type OpenIDInfo struct {
AccessToken string `json:"access_token"`
ExpiresIn int `json:"expires_in"`
RefreshToken string `json:"refresh_token"`
Openid string `json:"openid"`
Scope string `json:"scope"`
IsSnapshotuser int `json:"is_snapshotuser"`
Unionid string `json:"unionid"`
Errmsg string `json:"errmsg"`
Errcode int `json:"errcode"`
}
type PhoneRes struct {
PhoneInfo *PhoneInfo `json:"phone_info"`
Errmsg string `json:"errmsg"`
Errcode int `json:"errcode"`
}
type CommonRes struct {
Errmsg string `json:"errmsg"`
Errcode int `json:"errcode"`
}
type PhoneInfo struct {
PhoneNumber string `json:"phoneNumber"`
PurePhoneNumber string `json:"purePhoneNumber"`
Errcode int `json:"errcode"`
}
type BoxOpenId struct {
Openid string `json:"openid"`
Errmsg string `json:"errmsg"`
Errcode int `json:"errcode"`
}
type BoxAccessToken struct {
AccessToken string `json:"access_token"`
ExpiresIn int `json:"expires_in"`
RefreshToken string `json:"refresh_token"`
Errmsg string `json:"errmsg"`
Errcode int `json:"errcode"`
}
func GetOpenID(appID, appSecret, code string) (openInfo *OpenIDInfo, err error) {
var openIDInfo *OpenIDInfo
str := "https://api.weixin.qq.com/sns/oauth2/access_token?appid=%s&secret=%s&code=%s&grant_type=authorization_code"
url := fmt.Sprintf(str, appID, appSecret, code)
resp, err := http.Get(url)
if err != nil {
fmt.Println(err)
return nil, err
}
body, err := ioutil.ReadAll(resp.Body)
defer resp.Body.Close()
if resp.StatusCode != 200 {
fmt.Printf("请求失败%d\n", resp.StatusCode)
return nil, errors.New(fmt.Sprintf("请求失败%d", resp.StatusCode))
}
fmt.Println("返回数据是", string(body))
err = json.Unmarshal(body, &openInfo)
if err != nil {
fmt.Println(err)
return nil, err
}
fmt.Println(openIDInfo)
return
}
func GetBoxPhone(appID, appSecret, code string) (string, error) {
accessToken, err := GetBoxAccessToken(appID, appSecret)
if err != nil {
return "", err
}
openInfo, err := getBoxPhone(accessToken, code)
fmt.Println("提示设呢么", openInfo, err)
if err != nil {
return "", err
}
fmt.Println("123123--123", openInfo)
fmt.Println(openInfo.Errmsg)
fmt.Println(openInfo.Errcode)
if openInfo.Errcode != 40001 && openInfo.PhoneInfo != nil {
return openInfo.PhoneInfo.PurePhoneNumber, nil
}
fmt.Println("不顶用")
cache.RedisClient.Del(redis_key.GetBoxAccessToken(appID))
return getBoxPhoneAgain(appID, appSecret, code)
}
func getBoxPhoneAgain(appID, appSecret, code string) (string, error) {
accessToken, err := GetBoxAccessToken(appID, appSecret)
if err != nil {
return "", err
}
openInfo, err := getBoxPhone(accessToken, code)
fmt.Println("提示设呢么", openInfo, err)
if err != nil {
return "", err
}
fmt.Println("123123--123", openInfo)
fmt.Println(openInfo.Errmsg)
fmt.Println(openInfo.Errcode)
if openInfo.Errcode != 40001 && openInfo.PhoneInfo != nil {
return openInfo.PhoneInfo.PurePhoneNumber, nil
}
return "", errors.New(openInfo.Errmsg)
}
// GetBoxOpenID 获取小程序的openid
func GetBoxOpenID(appID, appSecret, code string) (string, error) {
/*
accessToken, err := GetBoxAccessToken(appID, appSecret)
if err != nil {
return "", err
}
*/
openInfo, err := getLoginOpenIdByCode(appID, appSecret, code)
fmt.Println("提示设呢么", openInfo, err)
if err != nil {
return "", err
}
return openInfo, nil
//cache.RedisClient.Del(redis_key.GetBoxAccessToken(appID))
//return getBoxOpenIDAgain(appID, appSecret, code)
}
func getBoxOpenIDAgain(appID, appSecret, code string) (string, error) {
accessToken, err := GetBoxAccessToken(appID, appSecret)
if err != nil {
return "", err
}
openInfo, err := getOpenIdByCode(accessToken, code)
if err != nil {
return "", err
}
if openInfo.Errcode != 0 {
return "", errors.New(openInfo.Errmsg)
}
return openInfo.Openid, nil
}
func getLoginOpenIdByCode(appId, appSecret, code string) (string, error) {
str := "https://api.weixin.qq.com/sns/jscode2session?appid=%s&secret=%s&js_code=%s&grant_type=authorization_code"
url := fmt.Sprintf(str, appId, appSecret, code)
resp, err := http.Get(url)
if err != nil {
return "", err
}
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
if resp.StatusCode != 200 {
fmt.Printf("请求失败%d\n", resp.StatusCode)
return "", errors.New(fmt.Sprintf("请求失败%d", resp.StatusCode))
}
fmt.Println("2--返回数据是", string(body))
var openInfo OpenIDInfo
err = json.Unmarshal(body, &openInfo)
if err != nil {
fmt.Println(err)
return "", err
}
if openInfo.Errcode != 0 {
return "", errors.New(openInfo.Errmsg)
}
return openInfo.Openid, err
}
func getOpenIdByCode(accessToken, code string) (openInfo *OpenIDInfo, err error) {
url := "https://api.weixin.qq.com/wxa/getpluginopenpid?access_token=" + accessToken
// 创建要发送的数据
data := []byte(fmt.Sprintf(`{"code": "%s"}`, code))
fmt.Println("1-------------", string(data))
fmt.Println("1-------------", accessToken)
// 发送POST请求
resp, err := http.Post(url, "application/json", bytes.NewBuffer(data))
if err != nil {
fmt.Println("发送请求失败:", err)
return
}
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
if resp.StatusCode != 200 {
fmt.Printf("请求失败%d\n", resp.StatusCode)
return nil, errors.New(fmt.Sprintf("请求失败%d", resp.StatusCode))
}
fmt.Println("2--返回数据是", string(body))
err = json.Unmarshal(body, &openInfo)
if err != nil {
fmt.Println(err)
return nil, err
}
return openInfo, err
}
// getBoxPhone 获取手机号
func getBoxPhone(accessToken, code string) (res *PhoneRes, err error) {
url := "https://api.weixin.qq.com/wxa/business/getuserphonenumber?access_token=" + accessToken
// 创建要发送的数据
data := []byte(fmt.Sprintf(`{"code": "%s"}`, code))
// 发送POST请求
resp, err := http.Post(url, "application/json", bytes.NewBuffer(data))
if err != nil {
fmt.Println("发送请求失败:", err)
return
}
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
if resp.StatusCode != 200 {
fmt.Printf("请求失败%d\n", resp.StatusCode)
return nil, errors.New(fmt.Sprintf("请求失败%d", resp.StatusCode))
}
fmt.Println("2--返回数据是", string(body))
err = json.Unmarshal(body, &res)
if err != nil {
fmt.Println(err)
return nil, err
}
return res, err
}
func GetBoxAccessToken(appID, appSecret string) (string, error) {
accessToken := cache.RedisClient.Get(redis_key.GetBoxAccessToken(appID)).Val()
if accessToken != "" {
return accessToken, nil
}
var openIDInfo *BoxAccessToken
str := "https://api.weixin.qq.com/cgi-bin/token?appid=%s&secret=%s&grant_type=client_credential"
url := fmt.Sprintf(str, appID, appSecret)
resp, err := http.Get(url)
if err != nil {
return "", err
}
body, err := ioutil.ReadAll(resp.Body)
defer resp.Body.Close()
if resp.StatusCode != 200 {
fmt.Printf("请求失败%d\n", resp.StatusCode)
return "", errors.New(fmt.Sprintf("请求失败%d", resp.StatusCode))
}
fmt.Println("返回数据是", string(body))
err = json.Unmarshal(body, &openIDInfo)
if err != nil {
fmt.Println(err)
return "", err
}
//记录下
fmt.Println("123123123", redis_key.GetBoxAccessToken(appID), openIDInfo.AccessToken)
fmt.Println(redis_key.GetBoxAccessToken(appID), openIDInfo.AccessToken)
cache.RedisClient.Set(redis_key.GetBoxAccessToken(appID), openIDInfo.AccessToken, 6000*time.Second)
return openIDInfo.AccessToken, nil
}

View File

@ -0,0 +1,84 @@
package wechat
import (
"github.com/fonchain_enterprise/micro-account/pkg/cache"
"reflect"
"testing"
)
func TestGetOpenID(t *testing.T) {
redisConfig := cache.RedisConfig{
RedisDB: "2",
RedisAddr: "127.0.0.1:6379",
RedisPw: "",
RedisDbName: "2",
}
cache.LoadRedis(redisConfig)
type args struct {
appID string
appSecret string
code string
}
tests := []struct {
name string
args args
wantOpenInfo *OpenIDInfo
wantErr bool
}{
{name: "", args: args{appID: "wx2ab0adfa3346d44f", appSecret: "d85d38e7a055432254a09f00899971c8", code: "xxx"}, wantOpenInfo: &OpenIDInfo{}},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
gotOpenInfo, err := GetBoxOpenID(tt.args.appID, tt.args.appSecret, tt.args.code)
if (err != nil) != tt.wantErr {
t.Errorf("GetOpenID() error = %v, wantErr %v", err, tt.wantErr)
return
}
if !reflect.DeepEqual(gotOpenInfo, tt.wantOpenInfo) {
t.Errorf("GetOpenID() gotOpenInfo = %v, want %v", gotOpenInfo, tt.wantOpenInfo)
}
})
}
}
func TestGetBoxPhone(t *testing.T) {
redisConfig := cache.RedisConfig{
RedisDB: "2",
RedisAddr: "127.0.0.1:6379",
RedisPw: "",
RedisDbName: "2",
}
cache.LoadRedis(redisConfig)
type args struct {
appID string
appSecret string
code string
}
tests := []struct {
name string
args args
want string
wantErr bool
}{
{name: "", args: args{appID: "wx2ab0adfa3346d44f", appSecret: "d85d38e7a055432254a09f00899971c8", code: "xxx"}},
// TODO: Add test cases.
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got, err := GetBoxPhone(tt.args.appID, tt.args.appSecret, tt.args.code)
if (err != nil) != tt.wantErr {
t.Errorf("GetBoxPhone() error = %v, wantErr %v", err, tt.wantErr)
return
}
if got != tt.want {
t.Errorf("GetBoxPhone() got = %v, want %v", got, tt.want)
}
})
}
}

33
pkg/config/config.go Normal file
View File

@ -0,0 +1,33 @@
package config
import (
"github.com/fonchain_enterprise/utils/mobile"
)
var MobileConfig MobileConfigTemplate
var mobileTemplate mobile.Message
var mobileAlTemplate mobile.AliMessage
type MobileConfigTemplate struct {
AK string
SK string
URL string
}
type AliMessage struct {
AK string
AS string
URL string
}
func GetMobile() mobile.Message {
return mobileTemplate
}
func GetAlMobile() mobile.AliMessage {
return mobileAlTemplate
}
func LoadData(info MobileConfigTemplate, alInfo AliMessage) {
mobileTemplate = mobile.NewFeiGe(info.AK, info.SK, info.URL)
mobileAlTemplate = mobile.NewAli(alInfo.AK, alInfo.AS, alInfo.URL)
}

1
pkg/domain/account.go Normal file
View File

@ -0,0 +1 @@
package domain

1
pkg/domain/coin.go Normal file
View File

@ -0,0 +1 @@
package domain

203
pkg/domain/msg_code.go Normal file
View File

@ -0,0 +1,203 @@
package domain
import (
"errors"
"fmt"
"github.com/fonchain_enterprise/micro-account/pkg/cache"
"github.com/fonchain_enterprise/micro-account/pkg/common/redis_key"
"github.com/fonchain_enterprise/micro-account/pkg/m"
"time"
)
func CheckMsg(key string) error {
n, err := cache.RedisClient.Exists(key).Result()
fmt.Println("n", n)
if err != nil {
return err
}
if n == 0 {
return nil
}
str := cache.RedisClient.Get(key)
num, err := str.Int()
if err != nil {
return err
}
if num > 30 {
return errors.New(m.Mobile_Send_Over)
}
return nil
}
// CheckMsgPre 检测短信发送限制
func CheckMsgPre(domain string, telNum string, scope string) error {
key := redis_key.GetAccountKeyCountTodayHour(domain, telNum, scope)
//一分钟最多发一条
minStr := cache.RedisClient.Get(redis_key.MinLimit(domain, telNum, scope))
if minStr.Val() != "" {
return errors.New(m.Mobile_Sended)
}
//一个小时最多10次
n, err := cache.RedisClient.Exists(key).Result()
fmt.Println("n", n)
if err != nil {
return err
}
if n == 0 {
return nil
}
str := cache.RedisClient.Get(key)
num, err := str.Int()
if err != nil {
return err
}
if num > 10 {
return errors.New(m.Mobile_Send_Over)
}
return nil
}
// SetOnlyRecordTelMsgCode 记录验证码
func SetOnlyRecordTelMsgCode(domain, tel, code, scope string) error {
//发送验证码
if merr := cache.RedisClient.Set(redis_key.GetOnlyAccountKey(domain, tel), code, 15*60*1000*time.Millisecond).Err(); merr != nil {
return merr
}
//发送验证码
if merr := cache.RedisClient.Set(redis_key.MinLimit(domain, tel, scope), code, 1*60*1000*time.Millisecond).Err(); merr != nil {
return merr
}
return SetTodayNum(domain, tel)
}
// InBlockList 黑名单
func InBlockList(domain string, tel string) bool {
isExist, err := cache.RedisClient.HExists(redis_key.BlackListKey(domain), tel).Result() //发送注册验证码 校验验证码时间限制
if err != nil {
panic(err)
return false
}
if isExist == true {
fmt.Println("黑名单")
return true
}
fmt.Println("白名单")
return false
}
// CodeLive 发送的验证码是否活着
func CodeLive(domain string, tel string) error {
str := cache.RedisClient.Get(redis_key.VerityCode(domain, tel)) //发送注册验证码 校验验证码时间限制
if str.Val() != "" {
return errors.New(m.Mobile_Sended)
}
return nil
}
// SetRecordTelMsgCode 发送短信成功之后记录部分信息
func SetRecordTelMsgCode(domain string, tel string, code string) error {
//发送验证码
if merr := cache.RedisClient.Set(redis_key.GetAccountKey(domain, tel), code, 15*60*1000*time.Millisecond).Err(); merr != nil {
return merr
}
//发送验证码
if merr := cache.RedisClient.Set(redis_key.VerityCode(domain, tel), code, 55*1000*time.Millisecond).Err(); merr != nil {
return merr
}
//注册的时候验证码
if merr := cache.RedisClient.Set(redis_key.GetAccountRegisterKey(domain, tel), code, 60*60*1000*time.Millisecond).Err(); merr != nil {
return merr
}
return SetTodayNum(domain, tel)
}
// SetRecordTelMsgCodeLogin 登录之后发送的短信
func SetRecordTelMsgCodeLogin(domain string, tel string, code string, id string) error {
//一分钟之内的
fmt.Println(redis_key.GetOneMinuteKey(domain, tel, id))
if merr := cache.RedisClient.Set(redis_key.GetOneMinuteKey(domain, tel, id), code, 1*60*1000*time.Millisecond).Err(); merr != nil {
return merr
}
//15分钟之内的
if merr := cache.RedisClient.Set(redis_key.GetChangeTelKey(domain, tel, id), code, 15*60*1000*time.Millisecond).Err(); merr != nil {
return merr
}
if merr := cache.RedisClient.Set(redis_key.GetNowNewTelById(domain, id), tel, 24*60*60*1000*time.Millisecond).Err(); merr != nil {
return merr
}
return SetTodayNum(domain, tel)
}
// DelRecordTelMsgCodeLogin 登录之后发送的短信
func DelRecordTelMsgCodeLogin(domain string, tel string, id string) error {
//15分钟之内的
if merr := cache.RedisClient.Del(redis_key.GetChangeTelKey(domain, tel, id), redis_key.GetOneMinuteKey(domain, tel, id)).Err(); merr != nil {
return merr
}
return SetTodayNum(domain, tel)
}
// SetTodayNum 当日记录发送记录
func SetTodayNum(domain string, tel string) error {
//当日记录发送记录
telTodayNum := redis_key.GetAccountKeyCountToday(domain, tel)
cache.RedisClient.Incr(telTodayNum)
cache.RedisClient.Expire(telTodayNum, 24*60*60*1000*time.Millisecond)
return nil
}
func CheckRegisterCode(domain string, tel string, code string) error {
str := cache.RedisClient.Get(redis_key.GetAccountRegisterKey(domain, tel))
cacheCode := str.Val()
if cacheCode == "" {
return errors.New("没有发送数据")
}
if code != cacheCode {
return errors.New("验证码错误")
}
return nil
}

View File

@ -0,0 +1,78 @@
package domain
import (
"fmt"
"github.com/fonchain_enterprise/micro-account/pkg/cache"
"github.com/fonchain_enterprise/micro-account/pkg/common/redis_key"
"testing"
)
func TestCheckMsg(t *testing.T) {
config := cache.RedisConfig{
RedisDB: "2",
RedisAddr: "127.0.0.1:6379",
RedisPw: "",
RedisDbName: "2",
}
cache.LoadRedis(config)
key := redis_key.GetAccountKeyCountTodayHour("test", "18205052627", "")
//key := redis_key.GetAccountKeyCountToday("test", "18205052627")
//没有字段
cache.RedisClient.Del(key)
if err := CheckMsg(key); err != nil {
t.Errorf("验证不通过 :%s", err.Error())
}
//字段数字小于10
/*
cache.RedisClient.Set(key, 8, 0)
if err := CheckMsg(key); err != nil {
t.Errorf("验证不通过: %s", err.Error())
}
*/
cache.RedisClient.Set(key, 11, 0)
if err := CheckMsg(key); err == nil {
t.Errorf("验证不通过:超过设定参数,没有提示")
}
}
func TestInBlockList(t *testing.T) {
config := cache.RedisConfig{
RedisDB: "2",
RedisAddr: "127.0.0.1:6379",
RedisPw: "",
RedisDbName: "2",
}
cache.LoadRedis(config)
type args struct {
domain string
tel string
}
tests := []struct {
name string
args args
want bool
}{
// TODO: Add test cases.
{args: args{domain: "test", tel: "18205052627"}, want: true},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if InBlockList(tt.args.domain, tt.args.tel) == true {
fmt.Println("黑名单")
} else {
fmt.Println("白名单")
}
})
}
}

90
pkg/e/code.go Normal file
View File

@ -0,0 +1,90 @@
package e
var (
JWTSecret = []byte("asdfqwer1234")
)
var (
Acquire_Daily_Login = "daily_login"
Acquire_Register = "register"
)
var (
TimeFormatMin = "2006-01-02 15:04"
)
const (
Success = 200
Error = 500
ParamsError = 400
InvalidToken = 501
)
const (
Failed = 1
Ok = 0
NotLogin = 401
SUCCESS = 200
UpdatePasswordSuccess = 201
DeleteSuccess = 204
NotExistInentifier = 202
ERROR = 500
InvalidParams = 400
//成员错误
ErrorExistNick = 10001
ErrorExistUser = 10002
ErrorNotExistUser = 10003
ErrorNotCompare = 10004
ErrorNotComparePassword = 10005
ErrorFailEncryption = 10006
ErrorNotExistProduct = 10007
ErrorNotExistAddress = 10008
ErrorExistFavorite = 10009
//店家错误
ErrorBossCheckTokenFail = 20001
ErrorBossCheckTokenTimeout = 20002
ErrorBossToken = 20003
ErrorBoss = 20004
ErrorBossInsufficientAuthority = 20005
ErrorBossProduct = 20006
//管理员错误
ErrorAuthCheckTokenFail = 30001 //token 错误
ErrorAuthCheckTokenTimeout = 30002 //token 过期
ErrorAuthToken = 30003
ErrorAuth = 30004
ErrorAuthInsufficientAuthority = 30005
ErrorReadFile = 30006
ErrorSendEmail = 30007
ErrorCallApi = 30008
ErrorUnmarshalJson = 30009
ErrorAdminFindUser = 30010
//数据库错误
ErrorDatabase = 40001
//对象存储错误
ErrorOss = 50001
ErrorUploadFile = 50002
//店铺错误
ErrorExistShopName = 60001
ErrorNotExistShopName = 60002
ErrorNotAdmin = 60003
ErrNoDomain = 70001
ErrTelNum = 70002
ErrNoCode = 70003
ErrNoID = 70004
ErrNickName = 70005
InvalidID = 70006
InvalidPas = 70007
ErrStatus = 70008
ErrNoType = 70009
ErrNoUserID = 70010
ErrNoName = 70011
ErrNoDepCode = 70012
ErrNoTitle = 70013
ErrNoUrl = 70014
ErrNoMethod = 70015
)

75
pkg/e/msg.go Normal file
View File

@ -0,0 +1,75 @@
package e
var MsgFlags = map[int]string{
SUCCESS: "ok",
UpdatePasswordSuccess: "修改密码成功",
NotExistInentifier: "该第三方账号未绑定",
ERROR: "fail",
InvalidParams: "请求参数错误",
ErrorExistNick: "已存在该昵称",
ErrorExistUser: "已存在该用户名",
ErrorNotExistUser: "该用户不存在",
ErrorNotCompare: "账号密码错误",
ErrorNotComparePassword: "两次密码输入不一致",
ErrorFailEncryption: "加密失败",
ErrorNotExistProduct: "该商品不存在",
ErrorNotExistAddress: "该收获地址不存在",
ErrorExistFavorite: "已收藏该商品",
ErrorBossCheckTokenFail: "商家的Token鉴权失败",
ErrorBossCheckTokenTimeout: "商家TOken已超时",
ErrorBossToken: "商家的Token生成失败",
ErrorBoss: "商家Token错误",
ErrorBossInsufficientAuthority: "商家权限不足",
ErrorBossProduct: "商家读文件错误",
ErrorAuthCheckTokenFail: "Token鉴权失败",
ErrorAuthCheckTokenTimeout: "TOken已超时",
ErrorAuthToken: "Token生成失败",
ErrorAuth: "Token错误",
ErrorAuthInsufficientAuthority: "权限不足",
ErrorReadFile: "读文件失败",
ErrorSendEmail: "发送邮件失败",
ErrorCallApi: "调用接口失败",
ErrorUnmarshalJson: "解码JSON失败",
ErrorUploadFile: "上传失败",
ErrorAdminFindUser: "管理员查询用户失败",
ErrorDatabase: "数据库操作出错,请重试",
ErrorOss: "OSS配置错误",
ErrorExistShopName: "店铺已被注册,请检查店铺名称和统一社会信用码",
ErrorNotExistShopName: "店铺不存在",
ErrorNotAdmin: "非管理员",
InvalidToken: "Token验证失败",
ErrNoDomain: "环境变量必须要有",
ErrTelNum: "手机号码错误",
ErrNoCode: "验证码必须要有",
ErrNoID: "ID缺少",
ErrNickName: "请填写正确的姓名项",
InvalidID: "身份证长度18位",
InvalidPas: "密码不小于6位",
ErrStatus: "状态非法",
ErrNoType: "缺少类型",
ErrNoUserID: "缺少用户ID",
ErrNoName: "缺少名称",
ErrNoDepCode: "缺少部门code",
ErrNoTitle: "缺少标题",
ErrNoUrl: "缺少url",
ErrNoMethod: "缺少method",
}
// GetMsg 获取状态码对应信息
func GetMsg(code int) string {
msg, ok := MsgFlags[code]
if ok {
return msg
}
return MsgFlags[ERROR]
}

View File

@ -0,0 +1,331 @@
package mail
import (
"crypto/tls"
"errors"
"fmt"
"github.com/PuerkitoBio/goquery"
"io"
"log"
"net/http"
"net/http/cookiejar"
"net/url"
"strings"
"time"
)
const (
//LoginSuccessUrl = "https://mail.fontree.cn/iredadmin/dashboard?checknew" //登录后的重定向地址
CreateUrl = "http://106.12.56.142/admin/box/new?new=true"
LoginUrl = "http://106.12.56.142/admin/login"
)
type iredCookie struct {
Cookie string
Name string
ExpireAt *time.Time
}
type IRedMail struct {
IsProd bool `json:"isProd"`
Username string `json:"username"`
Password string `json:"password"`
Domain string
*iredCookie
}
type CreateAccountInfo struct {
Username string
Password string
Cn string
}
var ReadMail *IRedMail
func LoadEnv(userName, psw, domain string, isProd bool) {
ReadMail = &IRedMail{
IsProd: isProd,
Username: userName,
Password: psw,
Domain: domain,
}
}
//CreateMailAccount 创建电子邮箱账号
func (m *IRedMail) CreateMailAccount(new CreateAccountInfo) error {
if m.IsProd != true {
fmt.Println("过滤创建邮箱帐号")
return nil
}
//0 登陆
cookies, err := m.login()
if err != nil {
return err
}
/*
//1 先去解析csrf_token
csrfToken, err := m.getCsrfTokenBeforeAdd()
if err != nil {
return err
}
fmt.Println(csrfToken, err)
*/
//1 先去解析csrf_token
err = m.createAccount(cookies, new)
if err != nil {
return err
}
return nil
}
// login 登陆超管
func (m *IRedMail) login() ([]*http.Cookie, error) {
cookies, csrfToken, err := m.getCsrfTokenAndCookieBeforeLogin()
if err != nil {
return nil, err
}
fmt.Println(cookies, csrfToken)
loginUrl := LoginUrl
values := url.Values{}
values.Set("email", m.Username)
values.Set("password", m.Password)
values.Set("_csrf_token", csrfToken)
// 忽略HTTPS证书验证
tr := &http.Transport{
TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
}
tempCookieJar, _ := cookiejar.New(nil)
u, err := url.Parse("http://106.12.56.142")
if err != nil {
log.Fatal(err)
return nil, err
}
tempCookieJar.SetCookies(u, cookies)
// 创建一个自定义Transport的HTTP客户端
//client := &http.Client{Transport: tr, Jar:cookies }
client := &http.Client{Transport: tr, Jar: tempCookieJar}
// 发起POST请求
res, err := client.PostForm(loginUrl, values)
if err != nil {
log.Fatal(err)
return nil, err
}
// 发送请求
defer res.Body.Close()
//fmt.Println(res.)
str, err := io.ReadAll(res.Body)
if err != nil {
return nil, err
}
fmt.Println("成功")
fmt.Println(string(str))
/*
if res.Request.URL.String() != LoginSuccessUrl {
msg := res.Request.URL.Query().Get("msg")
return errors.New("超管登录失败提示:" + msg)
}
*/
/*
for _, cookie := range res.Cookies() {
temp := &iredCookie{
Cookie: cookie.Value,
Name: cookie.Name,
}
m.iredCookie = temp
}
*/
return res.Cookies(), nil
}
// getCsrfTokenAndCookieBeforeLogin 登陆前获取token
func (m *IRedMail) getCsrfTokenAndCookieBeforeLogin() ([]*http.Cookie, string, error) {
var csrfToken string
var isExist bool
cookieJar, _ := cookiejar.New(nil)
tr := &http.Transport{
TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
}
// 创建一个HTTP客户端并设置cookie jar
client := &http.Client{
Jar: cookieJar,
Transport: tr,
}
// 创建登录请求
loginURL := LoginUrl
req, err := http.NewRequest("GET", loginURL, nil)
if err != nil {
fmt.Println("创建请求失败:", err)
return nil, "", err
}
// 发送登录请求
res, err := client.Do(req)
if err != nil {
fmt.Println("请求错误", loginURL, err)
return nil, "", err
}
defer res.Body.Close()
if err != nil {
return nil, "", err
}
str, err := io.ReadAll(res.Body)
if err != nil {
return nil, "", err
}
// 解析HTML
doc, err := goquery.NewDocumentFromReader(strings.NewReader(string(str)))
if err != nil {
return nil, "", err
}
doc.Find("input[name='_csrf_token']").Each(func(i int, s *goquery.Selection) {
csrfToken, isExist = s.Attr("value")
fmt.Println("查找1---", csrfToken, isExist) // 输出: testUser
})
if isExist == false {
return nil, "", errors.New("没有查找到csrf_token")
}
return res.Cookies(), csrfToken, nil
}
// getCsrfTokenBeforeAdd 登陆前获取token
func (m *IRedMail) getCsrfTokenBeforeAdd() (string, error) {
var csrfToken string
var isExist bool
cookieJar, _ := cookiejar.New(nil)
tr := &http.Transport{
TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
}
// 创建一个HTTP客户端并设置cookie jar
client := &http.Client{
Jar: cookieJar,
Transport: tr,
}
// 创建登录请求
loginURL := CreateUrl + m.Domain
req, err := http.NewRequest("GET", loginURL, nil)
if err != nil {
fmt.Println("创建请求失败:", err)
return "", err
}
// 向请求中添加cookie
cookie := &http.Cookie{
Name: m.iredCookie.Name,
Value: m.iredCookie.Cookie,
}
req.AddCookie(cookie)
// 发送登录请求
res, err := client.Do(req)
if err != nil {
fmt.Println("请求错误", loginURL, err)
return "", err
}
defer res.Body.Close()
if err != nil {
return "", err
}
str, err := io.ReadAll(res.Body)
if err != nil {
return "", err
}
// 解析HTML
doc, err := goquery.NewDocumentFromReader(strings.NewReader(string(str)))
if err != nil {
return "", err
}
doc.Find("input[name='csrf_token']").Each(func(i int, s *goquery.Selection) {
csrfToken, isExist = s.Attr("value")
fmt.Println("查找1---", csrfToken, isExist) // 输出: testUser
})
if isExist == false {
return "", errors.New("没有查找到csrf_token")
}
return csrfToken, nil
}
// createAccount 创建用户mail
func (m *IRedMail) createAccount(cookies []*http.Cookie, info CreateAccountInfo) error {
cookieJar, _ := cookiejar.New(nil)
values := url.Values{}
values.Set("name", info.Cn)
values.Set("user", info.Username)
values.Set("domain", m.Domain)
values.Set("passwordPlaintext", info.Password)
tr := &http.Transport{
TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
}
u, err := url.Parse("http://106.12.56.142")
if err != nil {
log.Fatal(err)
return err
}
cookieJar.SetCookies(u, cookies)
// 创建一个HTTP客户端并设置cookie jar
client := &http.Client{
Jar: cookieJar,
Transport: tr,
//CheckRedirect:
}
// 创建登录请求
loginURL := CreateUrl
req, err := http.NewRequest("POST", loginURL, strings.NewReader(values.Encode()))
if err != nil {
fmt.Println("创建请求失败:", err)
return err
}
req.Header.Set("content-type", "application/x-www-form-urlencoded")
// 发送登录请求
res, err := client.Do(req)
if err != nil {
fmt.Println("请求错误", loginURL, err)
return err
}
defer res.Body.Close()
fmt.Println("状态码", res.StatusCode)
fmt.Println("状态码", res.Status)
return nil
}

View File

@ -0,0 +1,125 @@
package mail
import (
"fmt"
"net/http"
"reflect"
"testing"
)
func TestIRedMail_getCsrfTokenAndCookieBeforeLogin(t *testing.T) {
type fields struct {
IsProd bool
Username string
Password string
Domain string
iredCookie *iredCookie
}
tests := []struct {
name string
fields fields
want []*http.Cookie
want1 string
wantErr bool
}{
// TODO: Add test cases.
{fields: fields{Username: "admin@fontree.cn", Password: "fontree567"}},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
m := &IRedMail{
IsProd: tt.fields.IsProd,
Username: tt.fields.Username,
Password: tt.fields.Password,
Domain: tt.fields.Domain,
iredCookie: tt.fields.iredCookie,
}
got, got1, err := m.getCsrfTokenAndCookieBeforeLogin()
fmt.Println("1------", got, got1)
if (err != nil) != tt.wantErr {
t.Errorf("getCsrfTokenAndCookieBeforeLogin() error = %v, wantErr %v", err, tt.wantErr)
return
}
if !reflect.DeepEqual(got, tt.want) {
t.Errorf("getCsrfTokenAndCookieBeforeLogin() got = %v, want %v", got, tt.want)
}
if got1 != tt.want1 {
t.Errorf("getCsrfTokenAndCookieBeforeLogin() got1 = %v, want %v", got1, tt.want1)
}
})
}
}
func TestIRedMail_login(t *testing.T) {
type fields struct {
IsProd bool
Username string
Password string
Domain string
iredCookie *iredCookie
}
tests := []struct {
name string
fields fields
want []*http.Cookie
want1 string
wantErr bool
}{
// TODO: Add test cases.
{fields: fields{Username: "admin@fontree.cn", Password: "fontree567", IsProd: true}},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
m := &IRedMail{
IsProd: tt.fields.IsProd,
Username: tt.fields.Username,
Password: tt.fields.Password,
Domain: tt.fields.Domain,
iredCookie: tt.fields.iredCookie,
}
_, err := m.login()
fmt.Println("1------", err)
if (err != nil) != tt.wantErr {
t.Errorf("login() error = %v, wantErr %v", err, tt.wantErr)
return
}
})
}
}
func TestIRedMail_CreateAccount(t *testing.T) {
type fields struct {
IsProd bool
Username string
Password string
Domain string
iredCookie *iredCookie
}
tests := []struct {
name string
fields fields
want []*http.Cookie
want1 string
wantErr bool
}{
// TODO: Add test cases.
{fields: fields{Username: "admin@fontree.cn", Password: "fontree567", IsProd: true}},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
m := &IRedMail{
IsProd: tt.fields.IsProd,
Username: tt.fields.Username,
Password: tt.fields.Password,
Domain: tt.fields.Domain,
iredCookie: tt.fields.iredCookie,
}
err := m.CreateMailAccount(CreateAccountInfo{Cn: "耿阳", Username: "gengyang", Password: "Aa.123456"})
fmt.Println("1------", err)
if (err != nil) != tt.wantErr {
t.Errorf("login() error = %v, wantErr %v", err, tt.wantErr)
return
}
})
}
}

View File

@ -0,0 +1,254 @@
package external
import (
"crypto/tls"
"errors"
"fmt"
"github.com/PuerkitoBio/goquery"
"io"
"log"
"net/http"
"net/http/cookiejar"
"net/url"
"strings"
"time"
)
const (
LoginSuccessUrl = "https://mail.fontree.cn/iredadmin/dashboard?checknew" //登录后的重定向地址
CreateUrl = "https://mail.fontree.cn/iredadmin/create/user/"
LoginUrl = "https://mail.fontree.cn/iredadmin/login"
)
type iredCookie struct {
Cookie string
Name string
ExpireAt *time.Time
}
type IRedMail struct {
IsProd bool `json:"isProd"`
Username string `json:"username"`
Password string `json:"password"`
Domain string
*iredCookie
}
type CreateAccountInfo struct {
Username string
Password string
Cn string
}
var ReadMail *IRedMail
func LoadEnv(userName, psw, domain string, isProd bool) {
ReadMail = &IRedMail{
IsProd: isProd,
Username: userName,
Password: psw,
Domain: domain,
}
}
//CreateMailAccount 创建电子邮箱账号
func (m *IRedMail) CreateMailAccount(new CreateAccountInfo) error {
if m.IsProd != true {
fmt.Println("过滤创建邮箱帐号")
return nil
}
//0 登陆
err := m.login()
if err != nil {
return err
}
//1 先去解析csrf_token
csrfToken, err := m.getCsrfTokenBeforeAdd()
if err != nil {
return err
}
fmt.Println(csrfToken, err)
//1 先去解析csrf_token
err = m.createAccount(csrfToken, new)
if err != nil {
return err
}
return nil
}
// login 登陆超管
func (m *IRedMail) login() error {
loginUrl := LoginUrl
values := url.Values{}
values.Set("username", m.Username)
values.Set("password", m.Password)
values.Set("form_login", "Login")
values.Set("lang", "en_US")
// 创建一个表单数据
cookieJar, _ := cookiejar.New(nil)
// 忽略HTTPS证书验证
tr := &http.Transport{
TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
}
// 创建一个自定义Transport的HTTP客户端
client := &http.Client{Transport: tr, Jar: cookieJar}
// 发起POST请求
res, err := client.PostForm(loginUrl, values)
if err != nil {
log.Fatal(err)
}
// 发送请求
defer res.Body.Close()
if res.Request.URL.String() != LoginSuccessUrl {
msg := res.Request.URL.Query().Get("msg")
return errors.New("超管登录失败提示:" + msg)
}
for _, cookie := range res.Cookies() {
temp := &iredCookie{
Cookie: cookie.Value,
Name: cookie.Name,
}
m.iredCookie = temp
}
return nil
}
// getCsrfTokenBeforeAdd 登陆前获取token
func (m *IRedMail) getCsrfTokenBeforeAdd() (string, error) {
var csrfToken string
var isExist bool
cookieJar, _ := cookiejar.New(nil)
tr := &http.Transport{
TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
}
// 创建一个HTTP客户端并设置cookie jar
client := &http.Client{
Jar: cookieJar,
Transport: tr,
}
// 创建登录请求
loginURL := CreateUrl + m.Domain
req, err := http.NewRequest("GET", loginURL, nil)
if err != nil {
fmt.Println("创建请求失败:", err)
return "", err
}
// 向请求中添加cookie
cookie := &http.Cookie{
Name: m.iredCookie.Name,
Value: m.iredCookie.Cookie,
}
req.AddCookie(cookie)
// 发送登录请求
res, err := client.Do(req)
if err != nil {
fmt.Println("请求错误", loginURL, err)
return "", err
}
defer res.Body.Close()
if err != nil {
return "", err
}
str, err := io.ReadAll(res.Body)
if err != nil {
return "", err
}
// 解析HTML
doc, err := goquery.NewDocumentFromReader(strings.NewReader(string(str)))
if err != nil {
return "", err
}
doc.Find("input[name='csrf_token']").Each(func(i int, s *goquery.Selection) {
csrfToken, isExist = s.Attr("value")
fmt.Println("查找1---", csrfToken, isExist) // 输出: testUser
})
if isExist == false {
return "", errors.New("没有查找到csrf_token")
}
return csrfToken, nil
}
// createAccount 创建用户mail
func (m *IRedMail) createAccount(csrfToken string, info CreateAccountInfo) error {
cookieJar, _ := cookiejar.New(nil)
values := url.Values{}
values.Set("csrf_token", csrfToken)
values.Set("domainName", m.Domain)
values.Set("username", info.Username)
values.Set("newpw", info.Password)
values.Set("confirmpw", info.Password)
values.Set("cn", info.Cn)
values.Set("preferredLanguage", "zh_CN")
values.Set("mailQuota", "1024")
values.Set("submit_add_user", "Add")
tr := &http.Transport{
TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
}
// 创建一个HTTP客户端并设置cookie jar
client := &http.Client{
Jar: cookieJar,
Transport: tr,
//CheckRedirect:
}
// 创建登录请求
loginURL := CreateUrl + m.Domain
req, err := http.NewRequest("POST", loginURL, strings.NewReader(values.Encode()))
if err != nil {
fmt.Println("创建请求失败:", err)
return err
}
req.Header.Set("content-type", "application/x-www-form-urlencoded")
// 向请求中添加cookie
cookie := &http.Cookie{
Name: m.Name,
Value: m.Cookie,
}
req.AddCookie(cookie)
// 发送登录请求
res, err := client.Do(req)
if err != nil {
fmt.Println("请求错误", loginURL, err)
return err
}
defer res.Body.Close()
msg := res.Request.URL.Query().Get("msg")
if msg != "CREATED" {
return errors.New("生成mail账号失败:" + msg)
}
return nil
}

View File

@ -0,0 +1,76 @@
package external
import (
"testing"
)
func TestIRedMail_login(t *testing.T) {
type fields struct {
Username string
Password string
}
tests := []struct {
name string
fields fields
want string
wantErr bool
}{
// TODO: Add test cases.
{fields: fields{Username: "postmaster@fontree.cn", Password: "Zaq12wsx"}},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
m := &IRedMail{
Username: tt.fields.Username,
Password: tt.fields.Password,
}
err := m.login()
if (err != nil) != tt.wantErr {
t.Errorf("login() error = %v, wantErr %v", err, tt.wantErr)
return
}
})
}
}
func TestIRedMail_CreateMailAccount(t *testing.T) {
type fields struct {
Username string
Password string
Domain string
iredCookie *iredCookie
}
type args struct {
new CreateAccountInfo
}
tests := []struct {
name string
fields fields
args args
wantErr bool
}{
// TODO: Add test cases.
{args: args{new: CreateAccountInfo{Username: "gengyang", Password: "Aa.123456", Cn: "耿阳"}}, fields: fields{
Username: "postmaster@fontree.cn",
Password: "Zaq12wsx",
Domain: "fontree.cn",
}},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
m := &IRedMail{
Username: tt.fields.Username,
Password: tt.fields.Password,
Domain: tt.fields.Domain,
iredCookie: tt.fields.iredCookie,
}
err := m.CreateMailAccount(tt.args.new)
if (err != nil) != tt.wantErr {
t.Errorf("CreateMailAccount() error = %v, wantErr %v", err, tt.wantErr)
return
}
})
}
}

63
pkg/m/msg.go Normal file
View File

@ -0,0 +1,63 @@
package m
import "github.com/fonchain_enterprise/utils/aes"
var Encryption aes.Encryption
var JWTSecret = []byte("asdfqwer1234")
const (
SERVER_CONFIG = "../conf/conf.ini"
DefaultDomain = "fontree"
)
const (
ArtistTokenTime = 720
TokenTime = 12
RefreshTokenTime = 720
)
const (
SUCCESS = "success"
FAILED = "failed"
ExistFAILED = "exist"
)
const (
Unknown = 0
Unnamed = 1
UnderReview = 2
AuditFailure = 3
Pass = 4
)
const (
ERRORPWD = "账号或密码错误"
ERRORCODE = "账号或验证码错误"
ERRORCONFIG = "配置文件读取错误,请检查文件路径:"
ACCOUNT_EXIST = "账号已存在"
JOB_NUMBER_EXIST = "工号已存在"
Not_Found = "没有找到数据"
Not_Person_Verify = "您未进行实名认证"
Forbidden_Ip = "网络地址被禁用"
Mobile_Sended = "已经发送过,验证码尚可用"
Black_Mobile_Sended = "系统提示:已经发送过,验证码尚可用"
Mobile_Check_Pw_Over = "登陆频率过快,请稍候登陆"
Mobile_Send_Over = "您的手机号当天发送次数过多,请联系管理员通过密码登录"
Mobile_Code_Wrong = "您的手机号验证码错误,请确认之后注册"
Mobile_Wrong = "手机号不合法"
Mobile_Not_Change = "手机号未更改"
Mobile_New_Tel_Over = "新手机号过期"
Mobile_Wrong_Code = "验证码错误"
Mobile_Not_Send = "验证码未发送"
IdNum_Need_RealName = "身份证校验需要您的真实姓名"
EmailCreateWrong = "邮箱创建失败"
AccountDoesNotExist = "账号不存在"
)
const (
SEX_MAN = iota + 1
SEX_WOMAN
)
const (
MailDomain = "fontree.cn"
MailRootUserName = "postmaster@fontree.cn"
MailRootPaw = "Zaq12wsx"
)

72
pkg/model/init.go Normal file
View File

@ -0,0 +1,72 @@
package model
import (
"fmt"
"github.com/fonchain_enterprise/micro-account/cmd/config"
"github.com/fonchain_enterprise/utils/zap_log"
"gorm.io/gorm/logger"
"strings"
"time"
"gorm.io/driver/mysql"
"gorm.io/gorm"
"gorm.io/gorm/schema"
)
var DB *gorm.DB
type MysqlConfig struct {
Db string
DbHost string
DbPort string
DbUser string
DbPassWord string
DbName string
}
func LoadEnv(config MysqlConfig) {
//MySQL数据库
path := strings.Join([]string{config.DbUser, ":", config.DbPassWord, "@tcp(", config.DbHost, ":",
config.DbPort, ")/", config.DbName, "?charset=utf8&parseTime=true&loc=Local"}, "")
fmt.Println(path)
//连接数据库
Database(path)
}
func Database(conn string) {
var ormLogger logger.Interface
if config.AppConfig.System.Mode != "prod" {
ormLogger = logger.Default.LogMode(logger.Info)
} else {
ormLogger = zap_log.NewGormLogger()
}
db, err := gorm.Open(mysql.New(mysql.Config{
DSN: conn, // DSN data source name
DefaultStringSize: 256, // string 类型字段的默认长度
DisableDatetimePrecision: true, // 禁用 datetime 精度MySQL 5.6 之前的数据库不支持
DontSupportRenameIndex: true, // 重命名索引时采用删除并新建的方式MySQL 5.7 之前的数据库和 MariaDB 不支持重命名索引
DontSupportRenameColumn: true, // 用 `change` 重命名列MySQL 8 之前的数据库和 MariaDB 不支持重命名列
SkipInitializeWithVersion: false, // 根据版本自动配置
}), &gorm.Config{
//Logger: log2.NewGormLogger(),
Logger: ormLogger,
NamingStrategy: schema.NamingStrategy{
SingularTable: true,
},
})
if err != nil {
panic(err)
}
sqlDB, _ := db.DB()
sqlDB.SetMaxIdleConns(20) //设置连接池,空闲
sqlDB.SetMaxOpenConns(100) //打开
sqlDB.SetConnMaxLifetime(time.Second * 30)
DB = db
migration()
}

30
pkg/model/login_log.go Normal file
View File

@ -0,0 +1,30 @@
package model
import (
"gorm.io/plugin/soft_delete"
"time"
)
const (
Status_In = 1
Status_Out = 2
Status_Off = 3
)
//LoginLog 用户模型
type LoginLog struct {
ID uint `gorm:"primarykey"`
Domain *string `gorm:"type:varchar(32);column:domain;default:'';comment:domain" json:"domian"` //过期时间
CreatedAt time.Time
UpdatedAt time.Time
DeletedAt soft_delete.DeletedAt `gorm:"column:deleted_at;type:int(11)" json:"deletedAt"`
UserId uint `gorm:"type:int(11);column:user_id;default:0;comment:绑定的用户id" json:"userId"` //绑定的用户id
Uuid string `gorm:"type:char(16);column:uuid;default:'';comment:uuid" json:"uuid"` //绑定的用户id
Ip string `gorm:"type:varchar(50);column:ip;default:'';comment:ip地址" json:"Ip"` //登录的ip
Token string `gorm:"type:text;column:token;default:;comment:token信息" json:"token"` //token
Status uint8 `gorm:"type:tinyint;column:status;default:1;comment:状态(1-登陆中 2-登出)" json:"status"` //status状态
ExpireDate string `gorm:"type:varchar(32);column:expire_date;default:'';comment:token过期日期" json:"expire_date"` //过期时间
LastDate string `gorm:"type:varchar(32);column:last_date;default:'';comment:最后活跃时间" json:"lastDate"` //status状态
LogoutDate string `gorm:"type:varchar(32);column:logout_date;default:'';comment:登出时间" json:"logoutDate"` //status状态
Address string `gorm:"type:varchar(32);column:address;default:'';comment:地址" json:"address"` //status状态
}

80
pkg/model/migration.go Normal file
View File

@ -0,0 +1,80 @@
package model
import (
"fmt"
)
// 类型迁移
func migration() {
err := DB.AutoMigrate()
//err = DBOrder.AutoMigrate(
// &model.Pay{},
//)
if err != nil {
fmt.Println("register table fail")
panic(1)
}
//自动迁移模式
AddTable(&RefreshToken{})
AddTable(&LoginLog{})
AddTable(&User{})
AddTable(&RealName{})
//增加字段
AddColumn(&User{}, "title")
AddColumn(&User{}, "job_num")
AddColumn(&User{}, "birth_date")
AddColumn(&User{}, "sex")
AddColumn(&User{}, "operator")
AddColumn(&User{}, "last_login_date")
AddColumn(&User{}, "ip")
AddColumn(&User{}, "invitation_code")
AddColumn(&User{}, "english_name")
AddColumn(&User{}, "mail_account")
AddColumn(&LoginLog{}, "token")
AddColumn(&LoginLog{}, "status")
AddColumn(&LoginLog{}, "expire_date")
AddColumn(&LoginLog{}, "last_date")
AddColumn(&LoginLog{}, "logout_date")
AddColumn(&LoginLog{}, "address")
AddColumn(&LoginLog{}, "domain")
AddColumn(&LoginLog{}, "uuid")
AddColumn(&User{}, "domain")
AddColumn(&User{}, "left_date")
AddColumn(&User{}, "remark")
AddColumn(&User{}, "recent_img")
AddColumn(&RealName{}, "realid_img_a")
AddColumn(&RealName{}, "realid_img_b")
AddColumn(&RealName{}, "is_real")
AddColumn(&RealName{}, "video")
AddColumn(&User{}, "ic_num")
AddColumn(&User{}, "train")
AddColumn(&User{}, "certificate")
AddColumn(&User{}, "source")
AddColumn(&User{}, "security_code")
AddColumn(&User{}, "block_addr")
}
// 数据迁移
func AddColumn(dst interface{}, column string) {
if DB.Migrator().HasColumn(dst, column) == false {
if err := DB.Migrator().AddColumn(dst, column); err != nil {
fmt.Println(err)
}
}
}
func AddTable(dst interface{}) {
if DB.Migrator().HasTable(dst) == false {
if err := DB.Migrator().CreateTable(dst); err != nil {
fmt.Println(err)
return
}
}
return
}

23
pkg/model/real_name.go Normal file
View File

@ -0,0 +1,23 @@
package model
import (
"gorm.io/plugin/soft_delete"
"time"
)
// RealName 实名认证模型
type RealName struct {
ID uint `gorm:"primarykey"`
CreatedAt time.Time
UpdatedAt time.Time
DeletedAt soft_delete.DeletedAt `gorm:"uniqueIndex:udx_name"`
Name string `gorm:"column:name;comment:姓名" json:"name"`
Sex int `gorm:"column:sex;comment:性别:1男 2女" json:"sex"`
Nationality string `gorm:"column:nationality;comment:国籍" json:"nationality"`
DocumentType int `gorm:"column:document_type;comment:证件类型:1护照 2身份证 3驾驶证 4居住证 5自拍照 6社保卡" json:"documentType"`
CertificatePicture string `gorm:"type:varchar(500);column:certificate_picture;comment:证件照片" json:"certificatePicture"`
Validity string `gorm:"column:validity;comment:证件有效期" json:"validity"`
PlaceOfResidence string `gorm:"column:place_of_residence;comment:居住地" json:"placeOfResidence"`
GroupPhoto string `gorm:"column:group_photo;comment:证件合影" json:"groupPhoto"`
Attachment string `gorm:"column:attachment;comment:附件" json:"attachment"`
}

View File

@ -0,0 +1,23 @@
package model
import (
"time"
)
const (
IsForBid_Yes = 1
IsForBid_No = 2
UseNum_Max = 15
)
//RefreshToken 长期有效刷新token
type RefreshToken struct {
ID uint `gorm:"primarykey"`
CreatedAt time.Time
UpdatedAt time.Time
RefreshToken string `gorm:"uniqueIndex:un_token;type:varchar(256);column:refresh_token;default:'';comment:refresh_token" json:"refreshToken"`
ExpireDate string `gorm:"type:varchar(32);column:expire_date;default:'';comment:token过期日期" json:"expire_date"` //过期时间
UseNum uint8 `gorm:"type:tinyint;column:use_num;default:0;comment:使用次数" json:"useNum"` //使用次数
LastUseDate string `gorm:"type:varchar(32);column:last_use_date;default:'';comment:上次使用的时间" json:"lastUseDate"` //使用次数
IsForbid uint8 `gorm:"type:tinyint;column:status;default:1;comment:状态(1-禁用 2-可用)" json:"IsForbid"` //status状态
}

298
pkg/model/user.go Normal file
View File

@ -0,0 +1,298 @@
package model
import (
"database/sql/driver"
"encoding/json"
"errors"
"fmt"
"github.com/fonchain_enterprise/micro-account/api/account"
"github.com/fonchain_enterprise/micro-account/pkg/cache"
"github.com/fonchain_enterprise/micro-account/pkg/common/redis_key"
"github.com/fonchain_enterprise/micro-account/pkg/common/utils"
"github.com/fonchain_enterprise/micro-account/pkg/common/verifica"
"github.com/fonchain_enterprise/micro-account/pkg/domain"
"github.com/fonchain_enterprise/micro-account/pkg/m"
"github.com/mozillazg/go-pinyin"
"golang.org/x/crypto/bcrypt"
"gorm.io/plugin/soft_delete"
"strconv"
"strings"
"time"
)
type Extend struct {
JumpTo string
Lang string
CanScan bool //是否可以扫码
ResolutionRatio bool //是否固定分辨率
}
type Operator struct {
ID uint32 `json:"ID"`
Name string `json:"name"`
}
// User 用户模型
type User struct {
ID uint `gorm:"primarykey"`
CreatedAt time.Time
UpdatedAt time.Time
DeletedAt soft_delete.DeletedAt `gorm:"column:deleted_at;type:int(11)" json:"deletedAt"`
Domain *string `gorm:"size:50"`
SubNum string `gorm:"column:sub_num;comment:用户编号" json:"subNum"`
TelNum string `gorm:"column:tel_num;comment:" json:"telNum"`
TelAreaCode string `gorm:"column:tel_area_code;comment:手机区号" json:"telAreaCode"`
Status int `gorm:"column:status;comment:状态 1:未实名 2:审核中 3:审核失败 4:审核通过" json:"status"`
RegistrationTime string `gorm:"column:registration_time;comment:注册时间" json:"registrationTime"`
AuditTime string `gorm:"column:audit_time;comment:审核时间" json:"auditTime"`
RealNameID uint
RealName *RealName `gorm:"foreignKey:RealNameID" json:"RealName"`
PasswordDigest string
NotPassRemarks string `gorm:"column:not_pass_remarks;comment:不通过备注" json:"notPassRemarks"`
}
const (
PassWordCost = 12 //密码加密难度
Active string = "active" //激活用户
NOTActive string = "notactive" //未激活用户
USERLEFT string = "left" //离职
)
var SendPhoneNum = map[string]string{}
func SetSendPhoneNUm(IsProd bool) {
if IsProd == true {
SendPhoneNum["13788998899"] = "15895559080"
} else {
SendPhoneNum["13788998899"] = "18362666451"
}
fmt.Println("是否是线上,同时手机号如何翻译", IsProd, SendPhoneNum)
}
func (j *Operator) Scan(src interface{}) error {
return json.Unmarshal(src.([]byte), j)
}
func (j Operator) Value() (driver.Value, error) {
v, err := json.Marshal(j)
return string(v), err
}
func (j *Extend) Scan(src interface{}) error {
return json.Unmarshal(src.([]byte), j)
}
func (j Extend) Value() (driver.Value, error) {
v, err := json.Marshal(j)
return string(v), err
}
func FormatExtend(extend *account.Extend) Extend {
var res Extend
res.JumpTo = extend.JumpTo
res.Lang = extend.Lang
res.ResolutionRatio = extend.ResolutionRatio
res.CanScan = extend.CanScan
return res
}
func FormatOperator(extend *account.Operator) Operator {
var res Operator
res.ID = extend.ID
res.Name = extend.Name
return res
}
// SetPassword 设置密码
//func (user *User) SetPassword(password string) error {
// bytes, err := bcrypt.GenerateFromPassword([]byte(password), PassWordCost)
// if err != nil {
// return err
// }
// user.PasswordDigest = string(bytes)
// return nil
//}
//
//// GetWorkYear 获取工作时间长度
//func (user *User) GetWorkYear() float32 {
// if user.EnterDate == "" {
// return 0
// }
//
// t, err := time.ParseInLocation("2006-01-02", user.EnterDate, time.Local)
// if err != nil {
// return 0
// }
//
// //if user.LeftDate != "" {
// //
// // end, err := time.ParseInLocation("2006-01-02", user.LeftDate, time.Local)
// // if err == nil {
// // return utils.SubYearFromStartAndEnd(t, end)
// // }
// //}
//
// return utils.SubYearFromNowBefore(t)
//}
// ChangeNewTel 修改手机号
func (user *User) ChangeNewTel(code string) error {
nowNewTelKey := redis_key.GetNowNewTelById(*user.Domain, strconv.Itoa(int(user.ID)))
//0 校验当前修改到的手机号 以及账号唯一性
newTelNumObj := cache.RedisClient.Get(nowNewTelKey)
newTelNum := newTelNumObj.Val()
if newTelNum == "" {
return errors.New(m.Mobile_Wrong)
}
var count int64
DB.Model(&User{}).Where(&User{TelNum: newTelNum, Domain: user.Domain}).Count(&count)
if count > 0 {
return errors.New(m.ACCOUNT_EXIST)
}
if newTelNum == user.TelNum {
return nil
}
//检测验证码
str := cache.RedisClient.Get(redis_key.GetChangeTelKey(*user.Domain, newTelNum, strconv.Itoa(int(user.ID))))
if str.Val() == "" {
return errors.New(m.Mobile_Not_Send)
}
if str.Val() != code {
return errors.New(m.Mobile_Wrong_Code)
}
//修改完毕之后删除
domain.DelRecordTelMsgCodeLogin(*user.Domain, newTelNum, strconv.Itoa(int(user.ID)))
err := DB.Model(&user).Updates(&User{TelNum: newTelNum}).Error
return err
}
func (user *User) NowNewTelNum() (string, error) {
str := cache.RedisClient.Get(redis_key.GetNowNewTelById(*user.Domain, strconv.Itoa(int(user.ID))))
if str.Val() == "" {
return "", errors.New(m.Mobile_New_Tel_Over)
}
return str.Val(), nil
}
// SendNewTelMsg 给新手机号发送验证码
func (user *User) SendNewTelMsg(newTelNum, project string, signNo uint) error {
telTodayNum := redis_key.GetAccountKeyCountToday(*user.Domain, newTelNum)
if newTelNum == "" {
return errors.New("新手机号不能为空")
}
if user.TelNum == newTelNum {
return errors.New(m.Mobile_Not_Change)
}
if utils.CheckMobile(newTelNum) == false {
return errors.New(m.Mobile_Wrong)
}
//0 限制频率 (一个账号一分钟少于一次 同一一天最多10条)
fmt.Println(redis_key.GetOneMinuteKey(*user.Domain, newTelNum, strconv.Itoa(int(user.ID))))
str := cache.RedisClient.Get(redis_key.GetOneMinuteKey(*user.Domain, newTelNum, strconv.Itoa(int(user.ID))))
fmt.Println(str)
if str.Val() != "" {
return errors.New(m.Mobile_Sended)
}
if err := domain.CheckMsg(telTodayNum); err != nil {
return errors.New(m.Mobile_Send_Over)
}
//1 执行发送 并且记录code
code, err := verifica.SendMsgV2(newTelNum, project, signNo)
if err != nil {
return err
}
//2 记录发送
err = domain.SetRecordTelMsgCodeLogin(*user.Domain, newTelNum, code, strconv.Itoa(int(user.ID)))
return err
}
// CheckPassword 校验密码
func (user *User) CheckPassword(password string) bool {
err := bcrypt.CompareHashAndPassword([]byte(user.PasswordDigest), []byte(password))
return err == nil
}
func DomainCount(domain string) int64 {
var count int64
//获取自己领导的部门
DB.Model(&User{}).
Where(&User{Domain: &domain}).Count(&count)
return count
}
func RandList(domain string, limit int) ([]*User, int64) {
var list []*User
var count int64
var departmentIds []uint
//获取自己领导的部门
searchObj := DB.Preload("RealName").
Where(&User{Domain: &domain}).
Limit(limit).
Order("rand()")
searchObj.Find(&list, departmentIds)
DB.Model(&User{}).Where(&User{Domain: &domain}).Count(&count)
return list, count
}
func SynInvitationCode(userId uint) error {
//保存实名信息
var user *User
if err := DB.Model(&User{}).First(user, userId).Error; err != nil {
return err
}
updateMap := map[string]interface{}{"invitation_code": utils.DecimalToAny(int(userId))}
return DB.Model(&User{}).Where(&User{ID: userId}).Updates(updateMap).Error
}
func GetEnglishNameByName(nickName string) string {
fmt.Println(strings.ReplaceAll("hello word", " ", ""))
pinyinObj := pinyin.NewArgs()
pinyinObj.Style = pinyin.Normal
pinyinObj.Separator = ""
result := pinyin.Pinyin(strings.ReplaceAll(nickName, " ", ""), pinyinObj)
pinyinStr := ""
for _, s := range result {
fmt.Println(s)
pinyinStr += s[0]
}
return strings.ReplaceAll(pinyinStr, " ", "")
}

186
pkg/model/user_test.go Normal file
View File

@ -0,0 +1,186 @@
package model
import (
"fmt"
"github.com/fonchain_enterprise/micro-account/api/account"
"github.com/fonchain_enterprise/micro-account/pkg/common/utils"
"github.com/fonchain_enterprise/micro-account/pkg/infrsatructure/external"
"github.com/fonchain_enterprise/micro-account/pkg/m"
"testing"
"time"
)
func TestDomainCount(t *testing.T) {
}
func TestSynMailAccount(t *testing.T) {
//数据库
mysqlConfig := MysqlConfig{
Db: "mysql",
DbHost: "rm-bp176edrl1g6kcycblo.mysql.rds.aliyuncs.com",
DbPort: "3306",
DbUser: "fonchain_opv",
DbPassWord: "IhQmhg8HZjDmU=Ove5PnA^D",
DbName: "fontree-account",
}
LoadEnv(mysqlConfig)
external.LoadEnv("postmaster@fontree.cn", "Zaq12wsx", "fontree.cn", true)
var users []User
domain := m.DefaultDomain
DB.Model(&User{}).Where(&User{Domain: &domain}).Where("isNull(mail_account) and id >50 ").Where("status != 'left'").Limit(100).Find(&users)
fmt.Println(users)
if len(users) <= 0 {
return
}
for _, user := range users {
var englishName, mailAccount, mailAccountPrefix string
var num int64
if utils.HasEnglishAndChinese(user.Nickname) {
return
}
englishName = user.Nickname
if utils.HasChinese(user.Nickname) {
englishName = GetEnglishNameByName(user.Nickname)
}
DB.Model(&User{}).Unscoped().Preload("DeletedAt").Where(&User{Domain: user.Domain, EnglishName: englishName}).Count(&num)
if num >= 1 {
mailAccount = fmt.Sprintf("%s%02d@%s", englishName, num+1, m.MailDomain)
mailAccountPrefix = fmt.Sprintf("%s%02d", englishName, num+1)
} else {
mailAccount = fmt.Sprintf("%s@%s", englishName, m.MailDomain)
mailAccountPrefix = fmt.Sprintf("%s", englishName)
}
err := external.ReadMail.CreateMailAccount(external.CreateAccountInfo{Username: mailAccountPrefix, Password: "Aa.123456", Cn: user.Nickname})
if err != nil {
fmt.Println("2------", err)
return
}
if err := DB.Model(&User{}).Where(&User{ID: uint(user.ID)}).UpdateColumns(&User{MailAccount: mailAccount, EnglishName: englishName}).Error; err != nil {
fmt.Println("1------", err)
return
}
fmt.Println("设置成功一个", user.Nickname)
time.Sleep(1 * time.Second)
}
}
func TestGetMemCry(t *testing.T) {
user := &User{
ID: 153,
MnemonicWords: "bbX/2x+VK1zMX/oETDqPyw67Sj16H2ex8J8+tp7gFoSVUpL1UXLAJbqcURigOOZU",
}
fmt.Println(user.GetMemCry())
}
func TestNick(t *testing.T) {
fmt.Println(SendPhoneNum["13788998899"])
if _, ok := SendPhoneNum["13788998899"]; ok {
fmt.Println("1-----", SendPhoneNum["13788998899"])
}
}
func TestGetEnglishNameByName(t *testing.T) {
type args struct {
nickName string
}
tests := []struct {
name string
args args
want string
}{
{args: args{nickName: "阿丽米罕·色依提"}},
// TODO: Add test cases.
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got := GetEnglishNameByName(tt.args.nickName); got != tt.want {
t.Errorf("GetEnglishNameByName() = %v, want %v", got, tt.want)
}
})
}
}
func TestUser_recordTrainVideo(t *testing.T) {
//数据库
mysqlConfig := MysqlConfig{
Db: "mysql",
DbHost: "172.16.100.93",
DbPort: "9061",
DbUser: "root",
DbPassWord: "123456",
DbName: "fontree-account",
}
//http://172.16.100.93:9010/salebot
LoadEnv(mysqlConfig)
external.LoadEnv("postmaster@fontree.cn", "Zaq12wsx", "fontree.cn", true)
var user *User
domain := m.DefaultDomain
DB.Model(&User{}).Where(&User{Domain: &domain, ID: 40}).Find(&user)
var trains []*account.TrainVideo
trains = append(trains, &account.TrainVideo{TrainUUID: "1", TrainDesc: "111--", Video: "x111x"})
trains = append(trains, &account.TrainVideo{TrainUUID: "2", TrainDesc: "2--", Video: "x2x"})
trains = append(trains, &account.TrainVideo{TrainUUID: "4", TrainDesc: "4--", Video: "x4x"})
err := user.recordTrainVideo(trains)
fmt.Println("err", err)
}
func TestSynTrainVideo(t *testing.T) {
//数据库
mysqlConfig := MysqlConfig{
Db: "mysql",
DbHost: "172.16.100.93",
DbPort: "9061",
DbUser: "root",
DbPassWord: "123456",
DbName: "fontree-account",
}
LoadEnv(mysqlConfig)
var users []User
domain := m.DefaultDomain
DB.Model(&User{}).Where(&User{Domain: &domain}).Where("train != ''").Limit(1000).Find(&users)
//fmt.Println(users)
if len(users) <= 0 {
return
}
fmt.Println(len(users))
for _, t1 := range users {
var trains []*account.TrainVideo
trains = append(trains, &account.TrainVideo{TrainUUID: "1", TrainDesc: "市场培训", Video: t1.Train})
err := t1.recordTrainVideo(trains)
if err != nil {
fmt.Println(t1.ID, err)
}
}
}

107
pkg/serializer/user.go Normal file
View File

@ -0,0 +1,107 @@
package serializer
import (
"github.com/fonchain_enterprise/micro-account/api/account"
"github.com/fonchain_enterprise/micro-account/pkg/common/utils"
"github.com/fonchain_enterprise/micro-account/pkg/model"
)
type User struct {
ID uint `json:"id"`
Account string `json:"account"`
NickName string `json:"nickName"`
Type int `json:"type"`
TelNum string `json:"telNum"`
Status string `json:"status"`
Avatar string `json:"avatar"`
CreateAt int64 `json:"createAt"`
RealNameID uint `json:"realNameId"`
RealName string `json:"realName"`
IDNum string `json:"idNum"`
}
// BuildUser 序列化用户
func BuildUser(user *model.User) *account.AccountInfo {
var realName = ""
var IdNum = ""
var videos []*account.TrainVideo
//if user.RealName != nil {
// realName = user.RealName.Name
// IdNum, _ = user.RealName.GetIDNum(user)
//}
//extend := &account.Extend{
// JumpTo: user.Extend.JumpTo,
// Lang: user.Extend.Lang,
// CanScan: user.Extend.CanScan,
// ResolutionRatio: user.Extend.ResolutionRatio,
//}
//
//if user.InvitationCode == "" {
// user.InvitationCode, _ = SynInvitationCode(user.ID)
//}
return &account.AccountInfo{
ID: uint64(user.ID),
TelNum: user.TelNum,
Status: int32(user.Status),
//Avatar: user.AvatarURL(),
CreateAt: user.CreatedAt.Format("2006-01-02 15:04:05"),
RealName: realName,
Domain: *user.Domain,
IDNum: IdNum,
TrainVideos: videos,
UpdatedAt: user.UpdatedAt.Format("2006-01-02 15:04:05"),
}
}
func BuildUsers(items []*model.User) (users []*account.AccountInfo) {
for _, item := range items {
user := BuildUser(item)
users = append(users, user)
}
return users
}
func BuildUserList(user []*model.User) []*account.UserListInfo {
if len(user) == 0 {
return []*account.UserListInfo{}
}
var userList []*account.UserListInfo
for _, i := range user {
userList = append(userList, &account.UserListInfo{
Id: uint64(i.ID),
Status: int32(i.Status),
Name: i.RealName.Name,
Sex: int32(i.RealName.Sex),
Nationality: i.RealName.Nationality,
DocumentType: int32(i.RealName.DocumentType),
CertificatePicture: i.RealName.CertificatePicture,
Validity: i.RealName.Validity,
PlaceOfResidence: i.RealName.PlaceOfResidence,
GroupPhoto: i.RealName.GroupPhoto,
Attachment: i.RealName.Attachment,
RegistrationTime: i.RegistrationTime,
AuditTime: i.AuditTime,
SubNum: i.SubNum,
NotPassRemarks: i.NotPassRemarks,
TelNum: i.TelNum,
})
}
return userList
}
func SynInvitationCode(userId uint) (string, error) {
//保存实名信息
var user *model.User
if err := model.DB.Model(&model.User{}).First(&user, userId).Error; err != nil {
return "", err
}
invitationCode := utils.DecimalToAny(int(userId))
updateMap := map[string]interface{}{"invitation_code": invitationCode}
return invitationCode, model.DB.Model(&model.User{}).Where(&model.User{ID: userId}).Updates(updateMap).Error
}

View File

@ -0,0 +1,31 @@
package serializer
import "testing"
func TestSynInvitationCode(t *testing.T) {
type args struct {
userId uint
}
tests := []struct {
name string
args args
want string
wantErr bool
}{
// TODO: Add test cases.
{name: "1", args: struct{ userId uint }{userId: 1964}, want: "", wantErr: true},
{name: "1", args: struct{ userId uint }{userId: 1978}, want: "", wantErr: true},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got, err := SynInvitationCode(tt.args.userId)
if (err != nil) != tt.wantErr {
t.Errorf("SynInvitationCode() error = %v, wantErr %v", err, tt.wantErr)
return
}
if got != tt.want {
t.Errorf("SynInvitationCode() got = %v, want %v", got, tt.want)
}
})
}
}

905
pkg/service/account.go Normal file
View File

@ -0,0 +1,905 @@
package service
import (
"context"
"dubbo.apache.org/dubbo-go/v3/common/logger"
_ "dubbo.apache.org/dubbo-go/v3/imports"
"errors"
"fmt"
"github.com/fonchain_enterprise/micro-account/api/account"
"github.com/fonchain_enterprise/micro-account/pkg/application"
"github.com/fonchain_enterprise/micro-account/pkg/cache"
"github.com/fonchain_enterprise/micro-account/pkg/common/jwt"
"github.com/fonchain_enterprise/micro-account/pkg/common/page"
"github.com/fonchain_enterprise/micro-account/pkg/common/redis_key"
"github.com/fonchain_enterprise/micro-account/pkg/common/verifica"
"github.com/fonchain_enterprise/micro-account/pkg/domain"
"github.com/fonchain_enterprise/micro-account/pkg/m"
"github.com/fonchain_enterprise/micro-account/pkg/model"
"github.com/fonchain_enterprise/micro-account/pkg/serializer"
"github.com/fonchain_enterprise/utils/mobile"
uuid2 "github.com/google/uuid"
"gorm.io/gorm"
"log"
"strconv"
"strings"
"time"
)
type AccountProvider struct {
account.UnimplementedAccountServer
}
// OffLine 踢出
func (a *AccountProvider) OffLine(ctx context.Context, in *account.CommonRequest) (*account.CommonResponse, error) {
response := &account.CommonResponse{}
err := application.OffByLogId(in.ID)
if err != nil {
return nil, err
}
return response, nil
}
// Logout 登出
func (a *AccountProvider) Logout(ctx context.Context, in *account.DecryptJwtRequest) (*account.CommonResponse, error) {
response := &account.CommonResponse{}
err := application.Logout(in, model.Status_Out)
if err != nil {
return nil, err
}
return response, nil
}
// OnlineLogById 获取某个id的在线数据
func (a *AccountProvider) OnlineLogById(ctx context.Context, in *account.OnlineLogByIdRequest) (*account.LoginLog, error) {
response := &account.LoginLog{}
response, err := application.OnlineLogById(in.ID)
if err != nil {
return response, nil
}
return response, nil
}
// OnlineLog 获取某个人的在线数据
func (a *AccountProvider) OnlineLog(ctx context.Context, in *account.LoginInfosByUserIdRequest) (*account.LoginLogsResponse, error) {
response := &account.LoginLogsResponse{}
response.Data = application.OnlineLogList(in)
return response, nil
}
func (a *AccountProvider) Login(ctx context.Context, in *account.LoginRequest) (*account.TokenInfo, error) {
timeNow := time.Now()
tokenInfo := &account.TokenInfo{IsSampleAddress: true}
//nowIpAddress := ""
var user *model.User
if err := model.DB.Preload("RealName").Where(&model.User{TelNum: in.TelNum, Domain: &in.Domain}).First(&user).Error; err != nil {
return nil, errors.New(m.AccountDoesNotExist)
}
if in.Code == "" && in.Password == "" {
return nil, errors.New(m.ERRORCODE)
}
fmt.Println("---------------add1---", time.Now().Sub(timeNow))
if in.Code != "" {
str := cache.RedisClient.Get(redis_key.GetAccountKey(in.Domain, in.TelNum)) // 登陆检测
code := str.Val()
if code != in.Code {
return nil, errors.New(m.ERRORCODE)
}
}
fmt.Println("---------------add2---", time.Now().Sub(timeNow))
if in.Password != "" {
if !user.CheckPassword(in.Password) { //200毫秒
return nil, errors.New(m.ERRORPWD)
}
}
fmt.Println("---------------add3---", time.Now().Sub(timeNow))
//生成token
tokenTime := m.TokenTime
token, refreshToken, err := jwt.GenerateTotalToken(user.ID, in.Domain, tokenTime, user.TelNum, m.JWTSecret)
if err != nil {
logger.Error(err)
return nil, err
}
fmt.Println("---------------add4---", time.Now().Sub(timeNow))
if err := application.AddRefreshToken(refreshToken); err != nil {
logger.Error(err)
return nil, err
}
tokenInfo.Token = token
tokenInfo.RefreshToken = refreshToken
tokenInfo.AccountInfo = serializer.BuildUser(user)
fmt.Println("---------------add4---", time.Now().Sub(timeNow))
//tokenInfo.AccountInfo.NowLogId = application.LoginAddLog(user, token, in.Ip, nowIpAddress)
fmt.Println("---------------结束", time.Now().Sub(timeNow))
return tokenInfo, nil
}
func (a *AccountProvider) RefreshToken(_ context.Context, in *account.RefreshTokenRequest) (*account.TokenInfo, error) {
response := &account.TokenInfo{}
oldRefreshToken := in.RefreshToken
//验证
claims, err := jwt.ParseRefreshToken(oldRefreshToken, m.JWTSecret)
if err != nil {
return nil, err
}
var user *model.User
if err := model.DB.Preload("RealName").Where(&model.User{ID: claims.ID, Domain: &in.Domain}).First(&user).Error; err != nil {
return nil, errors.New(m.Not_Found)
}
//生成token
token, refreshToken, err := jwt.GenerateTotalToken(user.ID, in.Domain, m.TokenTime, user.TelNum, m.JWTSecret)
if err != nil {
logger.Error(err)
return nil, err
}
//refresh 是否合法
if err := application.CheckRefreshToke(oldRefreshToken); err != nil {
logger.Error(err)
return nil, err
}
//refresh 是否合法
if err := application.AddRefreshToken(refreshToken); err != nil {
logger.Error(err)
return nil, err
}
//nowIpAddress := application.GetIpAddressByIp(in.Ip) //400毫秒
//_ = application.LoginAddLog(user, token, in.Ip, nowIpAddress)
response.Token = token
response.RefreshToken = refreshToken
response.AccountInfo = serializer.BuildUser(user)
return response, nil
}
func (a *AccountProvider) OnlySendMsg(_ context.Context, in *account.SendMsgRequest) (*account.SendMsgStatusResponse, error) {
response := &account.SendMsgStatusResponse{}
//telTodayNum := redis_key.GetAccountKeyCountToday(in.Domain, in.TelNum, in.Scope)
//校验(1-是否已经发送 2-是否今日发送超过指定数量)
/*str := cache.RedisClient.Get(redis_key.GetOnlyAccountKey(in.Domain, in.TelNum))
if str.Val() != "" {
return nil, errors.New(m.Mobile_Sended)
}
*/
if err := domain.CheckMsgPre(in.Domain, in.TelNum, in.Scope); err != nil {
return response, err
}
//执行发送 并且记录code
//code, err := verifica.SendMsg(in.TelNum, in.Project)
//兼容老代码
sigNo := in.SignNo
if sigNo == 0 {
sigNo = verifica.SIG_NO
if in.Project == "seller" {
sigNo = verifica.SIG_NO_SELLER
}
}
if in.MId == 0 {
in.MId = mobile.TMP1
}
code, err := verifica.SendCustomCode(in.TelNum, uint(in.MId), uint(sigNo))
if err != nil {
return nil, err
}
err = domain.SetOnlyRecordTelMsgCode(in.Domain, in.TelNum, code, in.Scope)
if err != nil {
return response, err
}
return response, nil
}
func (a *AccountProvider) OnlyCheckMsg(_ context.Context, in *account.CheckMsgRequest) (*account.SendMsgStatusResponse, error) {
response := &account.SendMsgStatusResponse{}
fmt.Println(in)
str := cache.RedisClient.Get(redis_key.GetOnlyAccountKey(in.Domain, in.TelNum))
code := str.Val()
if code == "" {
return nil, errors.New(m.Mobile_Not_Send)
}
if code != in.GetCode() {
return nil, errors.New(m.Mobile_Wrong_Code)
}
return response, nil
}
// SendMsg 发送验证码
func (a *AccountProvider) SendMsg(_ context.Context, in *account.SendMsgRequest) (*account.SendMsgStatusResponse, error) {
response := &account.SendMsgStatusResponse{}
var user *model.User
if domain.InBlockList(in.Domain, in.TelNum) {
return nil, errors.New(m.Black_Mobile_Sended)
}
if err := model.DB.Where(&model.User{TelNum: in.TelNum, Domain: &in.Domain}).First(&user).Error; err != nil {
return nil, errors.New(m.Not_Found)
}
//此处不再校验验证码有效期
//校验(1-是否已经发送 2-是否今日发送超过指定数量)
/*
str := cache.RedisClient.Get(redis_key.GetAccountKey(in.Domain, in.TelNum)) // 发送验证码
if str.Val() != "" {
return nil, errors.New(m.Mobile_Sended)
}
*/
//是否存活 (1分钟冷却) (1-是否已经发送 2-是否今日发送超过指定数量) 55秒
if err := domain.CodeLive(in.Domain, in.TelNum); err != nil {
return nil, err
}
//今日是否达到上限
if err := domain.CheckMsg(redis_key.GetAccountKeyCountToday(in.Domain, in.TelNum)); err != nil {
return nil, err
}
//执行发送 并且记录code
code, err := verifica.SendMsgV2(in.TelNum, in.Project, uint(in.SignNo))
if err != nil {
return nil, err
}
err = domain.SetRecordTelMsgCode(in.Domain, in.TelNum, code)
if err != nil {
return response, err
}
return response, nil
}
func (a *AccountProvider) SendMsgRegister(_ context.Context, in *account.SendMsgRequest) (*account.SendMsgStatusResponse, error) {
response := &account.SendMsgStatusResponse{}
telTodayNum := redis_key.GetAccountKeyCountToday(in.Domain, in.TelNum)
// 手机号是否存在
var count int64
model.DB.Model(&model.User{}).Where(&model.User{TelNum: in.TelNum, Domain: &in.Domain}).Count(&count)
if count > 0 {
return response, errors.New(m.ACCOUNT_EXIST)
}
//校验(1-是否已经发送 2-是否今日发送超过指定数量)
if err := domain.CodeLive(in.Domain, in.TelNum); err != nil {
return nil, err
}
if err := domain.CheckMsg(telTodayNum); err != nil {
return nil, err
}
//执行发送 并且记录code
code, err := verifica.SendMsgV2(in.TelNum, in.Project, uint(in.SignNo))
if err != nil {
return nil, err
}
err = domain.SetRecordTelMsgCode(in.Domain, in.TelNum, code)
if err != nil {
return response, err
}
return response, nil
}
func (a *AccountProvider) CheckMsg(_ context.Context, in *account.CheckMsgRequest) (*account.SendMsgStatusResponse, error) {
response := &account.SendMsgStatusResponse{}
str := cache.RedisClient.Get(redis_key.GetAccountKey(in.Domain, in.TelNum)) //校验验证码
code := str.Val()
if code == "" {
return nil, errors.New(m.Mobile_Not_Send)
}
if code != in.GetCode() {
return nil, errors.New(m.Mobile_Wrong_Code)
}
return response, nil
}
func (a *AccountProvider) RealName(_ context.Context, in *account.RealNameRequest) (*account.RealNameResponse, error) {
// 检查用户是否存在
var existingUser model.User
if err := model.DB.First(&existingUser, "id = ?", in.Id).Error; err != nil {
return &account.RealNameResponse{Status: m.FAILED}, err
}
// 如果用户已经实名
if existingUser.Status == m.Pass {
return &account.RealNameResponse{Status: m.FAILED}, errors.New("已实名")
}
// 如果实名审核中
if existingUser.Status == m.UnderReview {
return &account.RealNameResponse{Status: m.FAILED}, errors.New("实名审核中,请勿重复提交")
}
// 检查用户是否已关联实名信息
if existingUser.RealNameID == 0 {
// 如果没有找到实名信息,创建一个新的 RealName 记录
newRealName := model.RealName{
Name: in.Name,
Sex: int(in.Sex),
Nationality: in.Nationality,
DocumentType: int(in.DocumentType),
CertificatePicture: in.CertificatePicture,
Validity: in.Validity,
PlaceOfResidence: in.PlaceOfResidence,
GroupPhoto: in.GroupPhoto,
Attachment: in.Attachment,
}
// 创建实名信息
if err := model.DB.Create(&newRealName).Error; err != nil {
return &account.RealNameResponse{Status: m.FAILED}, err
}
// 更新用户的实名信息 ID
existingUser.RealNameID = newRealName.ID
if err := model.DB.Save(&existingUser).Error; err != nil {
return &account.RealNameResponse{Status: m.FAILED}, err
}
// 返回成功
return &account.RealNameResponse{Status: m.SUCCESS}, nil
}
// 如果已存在实名信息,更新该信息
updateData := map[string]interface{}{
"status": m.UnderReview, // 审核中状态
"name": in.Name,
"sex": in.Sex,
"nationality": in.Nationality,
"document_type": in.DocumentType,
"certificate_picture": in.CertificatePicture,
"validity": in.Validity,
"place_of_residence": in.PlaceOfResidence,
"group_photo": in.GroupPhoto,
"attachment": in.Attachment,
}
// 更新 RealName 表中的数据
var existingRealName model.RealName
if err := model.DB.First(&existingRealName, "id = ?", existingUser.RealNameID).Error; err != nil {
return &account.RealNameResponse{Status: m.FAILED}, err
}
if err := model.DB.Model(&existingRealName).Updates(updateData).Error; err != nil {
return &account.RealNameResponse{Status: m.FAILED}, err
}
return &account.RealNameResponse{Status: m.SUCCESS}, nil
}
func (a *AccountProvider) CheckRealName(ctx context.Context, in *account.CheckRealNameRequest) (*account.CheckRealNameResponse, error) {
// 根据用户 ID 查询用户
var user model.User
if err := model.DB.First(&user, "id = ?", in.Id).Error; err != nil {
return &account.CheckRealNameResponse{Status: m.FAILED}, err
}
// 只有当用户处于“审核中”状态时才能进行审核更新
if user.Status != m.UnderReview {
return &account.CheckRealNameResponse{Status: m.FAILED}, errors.New("用户状态异常,无法进行审核")
}
// 根据传入的审核结果更新用户状态和备注
if in.Pass {
user.Status = m.Pass
} else {
user.Status = m.AuditFailure
user.NotPassRemarks = in.NotPassRemarks
}
loc, err := time.LoadLocation("Asia/Shanghai")
if err != nil {
log.Fatalf("加载时区失败: %v", err)
}
user.AuditTime = time.Now().In(loc).Format("2006-01-02 15:04:05")
// 保存更新
if err := model.DB.Save(&user).Error; err != nil {
return &account.CheckRealNameResponse{Status: m.FAILED}, err
}
return &account.CheckRealNameResponse{Status: m.SUCCESS}, nil
}
// Register 注册
func (a *AccountProvider) Register(_ context.Context, in *account.RegistRequest) (*account.RegisterResponse, error) {
var err error
// 验证验证码
if in.Code == "" {
return &account.RegisterResponse{Status: m.Unknown}, errors.New(m.Mobile_Wrong_Code)
}
if err := domain.CheckRegisterCode(in.Domain, in.TelNum, in.Code); err != nil {
return &account.RegisterResponse{Status: m.Unknown}, errors.New(m.Mobile_Code_Wrong)
}
// 手机号是否已注册
var tempUser *model.User
if err := model.DB.Model(&model.User{}).Where(&model.User{TelNum: in.TelNum, Domain: &in.Domain}).First(&tempUser).Error; err == nil {
// 用户已存在
return &account.RegisterResponse{ID: uint64(tempUser.ID), Status: uint64(tempUser.Status)}, nil
} else if err != gorm.ErrRecordNotFound {
// 查询错误
return &account.RegisterResponse{Status: m.Unknown}, err
}
var subNum string
if err := model.DB.Model(&model.User{}).Select("MAX(SUBSTRING(SubNum, 3, 6))").Row().Scan(&subNum); err != nil {
return &account.RegisterResponse{Status: m.Unknown}, err
}
var newNum int
if subNum == "" {
// 如果没有用户,起始编号为 FE00001
newNum = 1
} else {
// 递增现有编号
parsedNum, err := strconv.Atoi(subNum)
if err != nil {
return &account.RegisterResponse{Status: m.Unknown}, err
}
newNum = parsedNum + 1
}
subNum = fmt.Sprintf("FE%05d", newNum)
//数据库中创建该用户记录
loc, err := time.LoadLocation("Asia/Shanghai")
if err != nil {
log.Fatalf("加载时区失败: %v", err)
}
user := model.User{
Domain: &in.Domain,
TelNum: in.TelNum,
Status: m.Unnamed,
TelAreaCode: in.TelAreaCode,
RegistrationTime: time.Now().In(loc).Format("2006-01-02 15:04:05"),
SubNum: subNum,
}
if err = model.DB.Create(&user).Error; err != nil {
return &account.RegisterResponse{Status: 0}, err
}
return &account.RegisterResponse{Status: uint64(user.Status), ID: uint64(user.ID)}, nil
}
// CheckPwd 检测密码是否正确
func (a *AccountProvider) CheckPwd(_ context.Context, in *account.CheckPwdRequest) (*account.UpdateResponse, error) {
response := &account.UpdateResponse{}
claims, err := jwt.ParseToken(in.Token, m.JWTSecret)
if err != nil {
return nil, err
}
//获取该用户信息
var user model.User
if err := model.DB.First(&user, claims.ID).Error; err != nil {
return response, err
}
if in.Password != "" {
if !user.CheckPassword(in.Password) {
return nil, errors.New(m.ERRORPWD)
}
}
return response, nil
}
func (a *AccountProvider) Authentication(_ context.Context, in *account.AuthenticationRequest) (*account.RequestStatus, error) {
claims, err := jwt.ParseToken(in.Token, m.JWTSecret)
if err != nil {
return nil, err
}
//获取该用户信息
var user model.User
if err := model.DB.First(&user, claims.ID).Error; err != nil {
logger.Error(err)
return &account.RequestStatus{Status: m.FAILED}, err
}
var realName model.RealName
//if user.RealNameID != 0 {
// if err := model.DB.First(&realName, user.RealNameID).Error; err != nil {
// logger.Error(err)
// return &account.RequestStatus{Status: m.FAILED}, err
// }
//}
//EncryptedIDNum, errCrypt := encryption.AesEncrypt([]byte(in.IDNum), strconv.Itoa(int(user.ID)))
//if errCrypt != nil {
// return &account.RequestStatus{Status: m.FAILED}, err
//}
realName.Name = in.Name
//realName.IDNum = base64.StdEncoding.EncodeToString(EncryptedIDNum)
//保存实名信息
if err := model.DB.Save(&realName).Error; err != nil {
logger.Error(err)
return &account.RequestStatus{Status: m.FAILED}, err
}
return &account.RequestStatus{Status: m.SUCCESS}, nil
}
func (a *AccountProvider) Info(ctx context.Context, in *account.InfoRequest) (*account.UserInfoResponse, error) {
//获取该用户信息
var user *model.User
if err := model.DB.Where(&model.User{Domain: &in.Domain}).Preload("RealName").First(&user, in.ID).Error; err != nil {
logger.Error(err)
return nil, err
}
response := &account.UserInfoResponse{
Id: uint64(user.ID),
Status: int32(user.Status),
Name: user.RealName.Name,
Sex: int32(user.RealName.Sex),
Nationality: user.RealName.Nationality,
DocumentType: int32(user.RealName.DocumentType),
CertificatePicture: user.RealName.CertificatePicture,
Validity: user.RealName.Validity,
PlaceOfResidence: user.RealName.PlaceOfResidence,
GroupPhoto: user.RealName.GroupPhoto,
Attachment: user.RealName.Attachment,
SubNum: user.SubNum,
NotPassRemarks: user.NotPassRemarks,
}
return response, nil
}
func (a *AccountProvider) UserList(ctx context.Context, in *account.UserListRequest) (*account.UserListResponse, error) {
var count int64
var users []*model.User
modelObj := model.DB.Model(&model.User{}).Preload("RealName")
if in.SubNum != "" {
modelObj.Where("sub_num like ? ", "%"+in.SubNum+"%")
}
if in.RealNameOrNot == 1 {
modelObj.Where("status = 1 ") //未实名
} else if in.RealNameOrNot == 2 {
modelObj.Where("status != 1 ") //已实名
}
if in.Name != "" {
modelObj.Where("real_name.name like ? ", "%"+in.Name+"%")
}
if in.DocumentType != 0 {
modelObj.Where("real_name.document_type = ? ", in.DocumentType)
}
if in.AuditStatus != 0 {
modelObj.Where("status = ? ", in.AuditStatus)
}
modelObj.Count(&count)
if in.Page > 0 && in.PageSize > 0 {
modelObj.Limit(int(in.PageSize)).Offset(page.GetOffset(in.Page, in.PageSize))
}
modelObj.Find(&users)
response := &account.UserListResponse{}
response.UserList = serializer.BuildUserList(users)
response.Page = in.Page
response.PageSize = in.PageSize
response.Count = uint64(count)
return response, nil
}
func (a *AccountProvider) DecryptJwt(_ context.Context, in *account.DecryptJwtRequest) (*account.DecryptJwtResponse, error) {
//默认在线
fmt.Println()
isOffline := false
claims, err := jwt.ParseToken(in.Token, m.JWTSecret)
if err != nil {
return nil, err
}
tokenKey := redis_key.GetTokenInfo(in.Domain, in.Token)
num, err := cache.RedisClient.Exists(tokenKey).Result()
if num <= 0 { //不存在则下线
isOffline = true
}
//获取该用户信息
response := &account.DecryptJwtResponse{
ID: uint64(claims.ID),
Account: claims.Account,
Domain: claims.Domain,
NickName: claims.NickName,
IsOffline: isOffline,
}
//更新下活跃时间
application.UpdateLastDate(in.Token)
return response, nil
}
func (a *AccountProvider) UserByTel(_ context.Context, in *account.UserByTelRequest) (*account.InfoResponse, error) {
response := &account.InfoResponse{IsExist: false}
var user *model.User
if err := model.DB.Model(&model.User{}).Preload("RealName").Where(&model.User{Domain: &in.Domain, TelNum: in.Tel}).First(&user).Error; err != nil {
if err.Error() == "record not found" { //不存在
return response, nil
}
return response, err
}
response.Info = serializer.BuildUser(user)
response.IsExist = true
return response, nil
}
func (a *AccountProvider) UsersByTel(_ context.Context, in *account.UsersByTelRequest) (*account.ListResponse, error) {
response := &account.ListResponse{}
if len(in.Tels) == 0 {
return response, nil
}
var users []*model.User
model.DB.Model(&model.User{}).Where(&model.User{Domain: &in.Domain}).Where("tel_num in (?)", in.Tels).Find(&users)
response.Data = serializer.BuildUsers(users)
response.Count = uint64(len(users))
return response, nil
}
func (a *AccountProvider) ListByIDs(_ context.Context, in *account.ListByIDsRequest) (*account.ListResponse, error) {
var count int64
//获取该用户信息
//var user model.User
var users []*model.User
modelObj := model.DB.Model(&model.User{}).Preload("Clocks.Device")
if len(in.IDs) > 0 {
modelObj.Where("id in ? ", in.IDs)
}
if in.NickName != "" {
modelObj.Where("nickname like ?", "%"+in.NickName+"%")
}
if len(in.InvitationCode) > 0 {
modelObj.Where("invitation_code in (?)", in.InvitationCode)
}
modelObj.Count(&count)
if in.Page > 0 && in.PageSize > 0 {
modelObj.Limit(int(in.PageSize)).Offset(page.GetOffset(in.Page, in.PageSize))
}
if in.OrderType == 1 {
modelObj.Order("id desc")
} else if in.OrderType == 2 {
modelObj.Order("enter_date asc")
}
//modelObj.Find(&users, in.IDs)
modelObj.Find(&users)
response := &account.ListResponse{}
response.Data = serializer.BuildUsers(users)
response.Count = uint64(count)
return response, nil
}
func (a *AccountProvider) RandList(_ context.Context, in *account.ListRequest) (*account.ListResponse, error) {
//获取该用户信息
//var user model.User
users, count := model.RandList(in.Domain, int(in.PageSize))
response := &account.ListResponse{}
response.Data = serializer.BuildUsers(users)
response.Count = uint64(count)
response.AllCount = uint64(model.DomainCount(in.Domain))
return response, nil
}
func (a *AccountProvider) Remove(_ context.Context, in *account.RemoveRequest) (*account.RemoveResponse, error) {
response := &account.RemoveResponse{}
err := model.DB.Transaction(func(tx *gorm.DB) error {
var err error
//删除个人
if err = model.DB.Where(&model.User{Domain: &in.Domain}).Delete(&model.User{}, in.ID).Error; err != nil {
return err
}
return nil
})
return response, err
}
// SendNewTelNumMsg 给新手机号发送验证码
func (a *AccountProvider) SendNewTelNumMsg(_ context.Context, in *account.SendNewTelNumMsgRequest) (*account.SendMsgStatusResponse, error) {
var user *model.User
response := &account.SendMsgStatusResponse{}
if err := model.DB.First(&user, in.ID).Error; err != nil {
return response, errors.New(m.Not_Found)
}
if in.NewTelNum == "" { //新手机号是空,则去redis中查询上次的手机号
newTelNum, err := user.NowNewTelNum()
if err != nil {
return response, err
}
in.NewTelNum = newTelNum
}
err := user.SendNewTelMsg(in.NewTelNum, in.Project, uint(in.SignNo))
return response, err
}
// UpdateTelNum 更新新手机号
func (a *AccountProvider) UpdateTelNum(_ context.Context, in *account.SendNewTelNumMsgRequest) (*account.SendMsgStatusResponse, error) {
var user *model.User
response := &account.SendMsgStatusResponse{}
if err := model.DB.First(&user, in.ID).Error; err != nil {
return response, errors.New(m.Not_Found)
}
err := user.ChangeNewTel(in.Code)
return response, err
}
func (a *AccountProvider) SendCustomMsg(ctx context.Context, in *account.SendCustomMsgRequest) (*account.SendMsgStatusResponse, error) {
response := &account.SendMsgStatusResponse{}
var user *model.User
uuid := uuid2.NewString()
logger.Info(uuid, ",发送自定义短信手机号", in.TelNum, "连接地址", in.Url)
if err := model.DB.Model(&model.User{}).First(&user, in.ID).Error; err != nil {
logger.Info(uuid, ",错误", err.Error())
return nil, errors.New(m.Not_Found)
}
//执行发送 并且记录code
fmt.Println("接收短信", in.Url, in)
in.Url = strings.Replace(in.Url, "|", "||", 1)
telNum := in.TelNum
if _, ok := model.SendPhoneNum[user.TelNum]; ok {
telNum = model.SendPhoneNum[user.TelNum]
}
if telNum == "" {
telNum = user.TelNum
}
err := verifica.SendCustomMsg(telNum, in.Url, uint(in.MId))
return response, err
}
func (a *AccountProvider) SendExCustomMsg(ctx context.Context, in *account.SendCustomMsgRequest) (*account.SendMsgStatusResponse, error) {
response := &account.SendMsgStatusResponse{}
fmt.Println("对外的发送短信参数:", in.TelNum, in.Url, in.MId)
err := verifica.SendCustomSignNoMsg(in.TelNum, in.Url, uint(in.MId), uint(in.SigNo))
return response, err
}
func (a *AccountProvider) MailAccountByNickName(_ context.Context, in *account.MailAccountByNickNameRequest) (*account.MaiAccountResponse, error) {
var err error
response := &account.MaiAccountResponse{}
//response.EnglishName, response.MailAccount, err = model.GetMailAndEnglishNameByNickName(in.NickName, in.Domain, in.ID)
return response, err
}
func (a *AccountProvider) QueryPersonnelWithTheSameName(_ context.Context, req *account.QueryPersonnelWithTheSameNameRequest) (*account.QueryPersonnelWithTheSameNameResponse, error) {
var duplicateNames []string
query := model.DB.Table("user").
Select("nickname").
Group("nickname").
Having("COUNT(nickname) >= ?", 2)
if len(req.Names) != 0 {
query.Where("nickname in (?)", req.Names)
}
if req.Domain != "" {
query.Where("domain = ?", req.Domain)
}
if req.Status != "" {
query.Where("status = ?", req.Status)
}
query.Where("deleted_at = 0")
if err := query.Pluck("nickname", &duplicateNames).Error; err != nil {
return nil, errors.New(m.Not_Found)
}
response := &account.QueryPersonnelWithTheSameNameResponse{
Names: duplicateNames,
Count: uint64(len(duplicateNames)),
}
return response, nil
}
func (a *AccountProvider) UsersByJobNum(_ context.Context, in *account.UsersByJobNumRequest) (*account.ListResponse, error) {
response := &account.ListResponse{}
if len(in.JobNum) == 0 {
return response, nil
}
var users []*model.User
model.DB.Model(&model.User{}).Where(&model.User{Domain: &in.Domain}).Where("job_num in (?)", in.JobNum).Find(&users)
response.Data = serializer.BuildUsers(users)
response.Count = uint64(len(users))
return response, nil
}