Commit 03339a8d by 1391696987

梧州企业微信登录绩效

parent 17cb0ca0
...@@ -17,6 +17,8 @@ public static void AddAppSettingConfiguration(this IServiceCollection services, ...@@ -17,6 +17,8 @@ public static void AddAppSettingConfiguration(this IServiceCollection services,
services services
.Configure<AppConnection>(configuration.GetSection("AppConnection")) .Configure<AppConnection>(configuration.GetSection("AppConnection"))
.Configure<Wechat>(configuration.GetSection("Wechat"))
.Configure<WzOAuth>(configuration.GetSection("WzOAuth"))
.Configure<Application>(configuration.GetSection("Application")) .Configure<Application>(configuration.GetSection("Application"))
.Configure<HuyiSmsConfig>(configuration.GetSection("HuyiSmsConfig")) .Configure<HuyiSmsConfig>(configuration.GetSection("HuyiSmsConfig"))
.Configure<EmailOptions>(configuration.GetSection("EmailOptions")) .Configure<EmailOptions>(configuration.GetSection("EmailOptions"))
......
...@@ -2,11 +2,14 @@ ...@@ -2,11 +2,14 @@
using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Caching.Memory; using Microsoft.Extensions.Caching.Memory;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options; using Microsoft.Extensions.Options;
using Performance.DtoModels; using Performance.DtoModels;
using Performance.DtoModels.AppSettings; using Performance.DtoModels.AppSettings;
using Performance.EntityModels; using Performance.EntityModels;
using Performance.Infrastructure;
using Performance.Services; using Performance.Services;
using RestSharp;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
...@@ -17,26 +20,36 @@ namespace Performance.Api.Controllers ...@@ -17,26 +20,36 @@ namespace Performance.Api.Controllers
[Route("api/[controller]")] [Route("api/[controller]")]
public class AccountController : Controller public class AccountController : Controller
{ {
private readonly ILogger<AccountController> logger;
private UserService _userService; private UserService _userService;
private RoleService _roleService; private RoleService _roleService;
private IMemoryCache _memoryCache; private IMemoryCache _memoryCache;
private Application _options; private Application _options;
private ClaimService _claim; private ClaimService _claim;
private HospitalService _hospitalService; private HospitalService _hospitalService;
private readonly IOptions<Wechat> _wechat;
private readonly IOptions<WzOAuth> _wzOAuth;
public AccountController(UserService userService, public AccountController(
ILogger<AccountController> logger,
UserService userService,
HospitalService hospitalService, HospitalService hospitalService,
RoleService roleService, RoleService roleService,
IMemoryCache memoryCache, IMemoryCache memoryCache,
IOptions<Application> options, IOptions<Application> options,
ClaimService claim) ClaimService claim,
IOptions<Wechat> wechat,
IOptions<WzOAuth> wzOAuth)
{ {
this.logger = logger;
_userService = userService; _userService = userService;
_roleService = roleService; _roleService = roleService;
_memoryCache = memoryCache; _memoryCache = memoryCache;
_hospitalService = hospitalService; _hospitalService = hospitalService;
_options = options.Value; _options = options.Value;
_claim = claim; _claim = claim;
_wechat = wechat;
_wzOAuth = wzOAuth;
} }
/// <summary> /// <summary>
...@@ -82,6 +95,117 @@ public ApiResponse<JwtToken> Login([FromBody] LoginRequest request) ...@@ -82,6 +95,117 @@ public ApiResponse<JwtToken> Login([FromBody] LoginRequest request)
} }
/// <summary> /// <summary>
/// 微信登录
/// </summary>
/// <param name="code"></param>
/// <returns></returns>
[HttpPost]
[Route("WechatLogin")]
[AllowAnonymous]
public ApiResponse WechatLogin(string code)
{
InterfaceRequest interfaceRequest = new InterfaceRequest()
{
Url = "https://qyapi.weixin.qq.com/cgi-bin/gettoken",
Function = "GatAccess_token"
};
var getAccess_tokenDic = _userService.AccessInterface(interfaceRequest, out string content);
string access_token = "";
if (getAccess_tokenDic.ContainsKey("access_token"))
access_token = getAccess_tokenDic["access_token"].ToString();
interfaceRequest.Url = "https://qyapi.weixin.qq.com/cgi-bin/user/getuserinfo";
interfaceRequest.Function = "GetUserId";
interfaceRequest.Access_token = access_token;
interfaceRequest.Code = code;
var getUserIdDic = _userService.AccessInterface(interfaceRequest, out string conten);
string userId = "";
if (getUserIdDic.ContainsKey("UserId"))
userId = getUserIdDic["UserId"].ToString();
var empCode = _userService.GetWxUserEmpCode(userId);
return new ApiResponse(ResponseType.OK, new { userId, empCode });
}
/// <summary>
/// 梧州Token假接口
/// </summary>
/// <returns></returns>
[HttpPost]
[Route("WuzhouToken")]
[AllowAnonymous]
public dynamic WuzhouToken()
{
string json1 = "{\"success\":true,\"status\":{\"code\":0,\"msg\":\"处理成功。\"},\"extraMsg\":\"\",\"item\":{\"id\":\"9f1e83f1-6a9d-4bc4-8e93-611cb41991ba\",\"timeout\":7200000,\"startTimestamp\":\"2022-06-01 16:47:42.049\"}}";
var dic = JsonHelper.Deserialize<Dictionary<string, object>>(json1);
return dic;
}
/// <summary>
/// 梧州验证登录假接口
/// </summary>
/// <returns></returns>
[HttpPost]
[Route("WuzhouValidPass")]
[AllowAnonymous]
public dynamic WuzhouValidPass()
{
string json1 = "{\"success\":true,\"status\":{\"code\":0,\"msg\":\"处理成功。\"},\"extraMsg\":\"\",\"item\":true}";
var dic = JsonHelper.Deserialize<Dictionary<string, object>>(json1);
return dic;
}
/// <summary>
/// 梧州登录
/// </summary>
/// <param name="request"></param>
/// <returns></returns>
[HttpPost]
[Route("WuzhouLogin")]
[AllowAnonymous]
public dynamic WuzhouLogin([FromBody] WuzhouLoginRequest request)
{
if (string.IsNullOrEmpty(request.EmpCode) ||
string.IsNullOrEmpty(request.Password) ||
string.IsNullOrEmpty(request.SocialCode) ||
string.IsNullOrEmpty(request.Mobile) ||
string.IsNullOrEmpty(request.UserId))
return new ApiResponse(ResponseType.Fail, "请补全数据!");
InterfaceRequest interfaceRequest = new InterfaceRequest()
{
Url = _wzOAuth.Value.GetTokenUrl,
Function = "GetX_Token"
};
var getTokenDic = _userService.AccessInterface(interfaceRequest, out string tokenContent);
string token = "";
if (getTokenDic.GetValue("success", false) == true)
{
var item = getTokenDic["item"];
var itemdic = JsonHelper.Deserialize<Dictionary<string, object>>(item.ToString());
token = itemdic["id"].ToString();
}
else
{
return tokenContent;
}
interfaceRequest.Url = _wzOAuth.Value.ValidPassUrl;
interfaceRequest.Function = "ValidPass";
interfaceRequest.wuzhouLoginRequest = request;
var validPassDic = _userService.AccessInterface(interfaceRequest, out string validPassContent);
if (validPassDic.GetValue("success", false) == true && validPassDic.GetValue("item", false) == true)
_userService.SaveWxUser(request.UserId, request.EmpCode);
return validPassContent;
}
/// <summary>
/// 刷新登录JWT TOKEN /// 刷新登录JWT TOKEN
/// </summary> /// </summary>
/// <returns></returns> /// <returns></returns>
...@@ -149,7 +273,7 @@ public ApiResponse<UserResponse> UpdateSelf([CustomizeValidator(RuleSet = "Self" ...@@ -149,7 +273,7 @@ public ApiResponse<UserResponse> UpdateSelf([CustomizeValidator(RuleSet = "Self"
[HttpPost] [HttpPost]
public ApiResponse<List<UserResponse>> List([FromBody] UserRequest request) public ApiResponse<List<UserResponse>> List([FromBody] UserRequest request)
{ {
var userList = _userService.GetUserList(_claim.GetUserId(),request.Role); var userList = _userService.GetUserList(_claim.GetUserId(), request.Role);
return new ApiResponse<List<UserResponse>>(ResponseType.OK, "ok", userList); return new ApiResponse<List<UserResponse>>(ResponseType.OK, "ok", userList);
} }
...@@ -399,4 +523,4 @@ public ApiResponse BatchSaveUser([CustomizeValidator(RuleSet = "Insert"), FromBo ...@@ -399,4 +523,4 @@ public ApiResponse BatchSaveUser([CustomizeValidator(RuleSet = "Insert"), FromBo
} }
} }
} }
\ No newline at end of file \ No newline at end of file
...@@ -4,7 +4,7 @@ https://go.microsoft.com/fwlink/?LinkID=208121. ...@@ -4,7 +4,7 @@ https://go.microsoft.com/fwlink/?LinkID=208121.
--> -->
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> <Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup> <PropertyGroup>
<DeleteExistingFiles>True</DeleteExistingFiles> <DeleteExistingFiles>False</DeleteExistingFiles>
<ExcludeApp_Data>False</ExcludeApp_Data> <ExcludeApp_Data>False</ExcludeApp_Data>
<LaunchSiteAfterPublish>True</LaunchSiteAfterPublish> <LaunchSiteAfterPublish>True</LaunchSiteAfterPublish>
<LastUsedBuildConfiguration>Release</LastUsedBuildConfiguration> <LastUsedBuildConfiguration>Release</LastUsedBuildConfiguration>
......
...@@ -6,6 +6,16 @@ ...@@ -6,6 +6,16 @@
"Microsoft": "Warning" "Microsoft": "Warning"
} }
}, },
"Wechat": {
"CorpId": "ww58ec167201a95da7",
"CorpSecret": "1rgWzgJBIZ3r0Q2sW1trVw5QdXOHmgUhepk90ecI2rk"
},
"WzOAuth": {
"Code": "CNYICE",
"Token": "9e76f970728c4013a1333a76aa26631e",
"GetTokenUrl": "http://192.168.100.137/oauth/doAuth",
"ValidPassUrl": "http://192.168.100.225:12999/herp/employee/validPass"
},
"AppConnection": { "AppConnection": {
"PerformanceConnectionString": "server=192.168.18.166;database=db_performance;uid=root;pwd=1234qwer;pooling=true;charset=utf8;convert zero datetime=true;port=3306;connection timeout=120;max pool size=512;allow user variables=true;" "PerformanceConnectionString": "server=192.168.18.166;database=db_performance;uid=root;pwd=1234qwer;pooling=true;charset=utf8;convert zero datetime=true;port=3306;connection timeout=120;max pool size=512;allow user variables=true;"
}, },
......
...@@ -5,6 +5,18 @@ ...@@ -5,6 +5,18 @@
"System": "Information" "System": "Information"
} }
}, },
"Wechat": {
"CorpId": "ww58ec167201a95da7",
"CorpSecret": "1rgWzgJBIZ3r0Q2sW1trVw5QdXOHmgUhepk90ecI2rk"
},
"WzOAuth": {
"Code": "CNYICE",
"Token": "9e76f970728c4013a1333a76aa26631e",
//"GetTokenUrl": "http://192.168.100.137/oauth/doAuth",
//"ValidPassUrl": "http://192.168.100.225:12999/herp/employee/validPass"
"GetTokenUrl": "http://localhost:5001/api/Account/WuzhouToken",
"ValidPassUrl": "http://localhost:5001/api/Account/WuzhouValidPass"
},
"AppConnection": { "AppConnection": {
//"PerformanceConnectionString": "server=112.124.13.17;database=db_performance;uid=suvalue;pwd=suvalue2016;pooling=true;charset=utf8;convert zero datetime=true;port=3306;connection timeout=120;max pool size=512;allow user variables=true;", //"PerformanceConnectionString": "server=112.124.13.17;database=db_performance;uid=suvalue;pwd=suvalue2016;pooling=true;charset=utf8;convert zero datetime=true;port=3306;connection timeout=120;max pool size=512;allow user variables=true;",
"PerformanceConnectionString": "server=192.168.18.166;database=db_performance_screen;uid=root;pwd=1234qwer;pooling=true;charset=utf8;convert zero datetime=true;port=3306;connection timeout=120;max pool size=512;allow user variables=true;" "PerformanceConnectionString": "server=192.168.18.166;database=db_performance_screen;uid=root;pwd=1234qwer;pooling=true;charset=utf8;convert zero datetime=true;port=3306;connection timeout=120;max pool size=512;allow user variables=true;"
......
...@@ -4,6 +4,16 @@ ...@@ -4,6 +4,16 @@
"Default": "Warning" "Default": "Warning"
} }
}, },
"Wechat": {
"CorpId": "ww58ec167201a95da7",
"CorpSecret": "1rgWzgJBIZ3r0Q2sW1trVw5QdXOHmgUhepk90ecI2rk"
},
"WzOAuth": {
"Code": "CNYICE",
"Token": "9e76f970728c4013a1333a76aa26631e",
"GetTokenUrl": "http://192.168.100.137/oauth/doAuth",
"ValidPassUrl": "http://192.168.100.225:12999/herp/employee/validPass"
},
//连接字符串 //连接字符串
"AppConnection": { "AppConnection": {
"PerformanceConnectionString": "server=116.62.245.55;database=db_performance;uid=suvalue;pwd=suvalue2017;pooling=true;charset=utf8;convert zero datetime=true;port=3306;connection timeout=120;max pool size=512;allow user variables=true;" "PerformanceConnectionString": "server=116.62.245.55;database=db_performance;uid=suvalue;pwd=suvalue2017;pooling=true;charset=utf8;convert zero datetime=true;port=3306;connection timeout=120;max pool size=512;allow user variables=true;"
......
...@@ -24,6 +24,32 @@ ...@@ -24,6 +24,32 @@
<param name="request"></param> <param name="request"></param>
<returns></returns> <returns></returns>
</member> </member>
<member name="M:Performance.Api.Controllers.AccountController.WechatLogin(System.String)">
<summary>
微信登录
</summary>
<param name="code"></param>
<returns></returns>
</member>
<member name="M:Performance.Api.Controllers.AccountController.WuzhouToken">
<summary>
梧州Token假接口
</summary>
<returns></returns>
</member>
<member name="M:Performance.Api.Controllers.AccountController.WuzhouValidPass">
<summary>
梧州验证登录假接口
</summary>
<returns></returns>
</member>
<member name="M:Performance.Api.Controllers.AccountController.WuzhouLogin(Performance.DtoModels.WuzhouLoginRequest)">
<summary>
梧州登录
</summary>
<param name="request"></param>
<returns></returns>
</member>
<member name="M:Performance.Api.Controllers.AccountController.Refresh"> <member name="M:Performance.Api.Controllers.AccountController.Refresh">
<summary> <summary>
刷新登录JWT TOKEN 刷新登录JWT TOKEN
......
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Performance.DtoModels.AppSettings
{
public class Wechat
{
public string CorpId { get; set; }
public string CorpSecret { get; set; }
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Performance.DtoModels.AppSettings
{
public class WzOAuth
{
public string Code { get; set; }
public string Token { get; set; }
public string GetTokenUrl { get; set; }
public string ValidPassUrl { get; set; }
}
}
...@@ -19,7 +19,24 @@ public class LoginRequest ...@@ -19,7 +19,24 @@ public class LoginRequest
public string AppName { get; set; } public string AppName { get; set; }
public string Device { get; set; } public string Device { get; set; }
} }
public class InterfaceRequest
{
public string Url { get; set; }
public string Function { get; set; }
public string Access_token { get; set; }
public string Code { get; set; }
public string X_Token { get; set; }
public WuzhouLoginRequest wuzhouLoginRequest { get; set; }
}
public class WuzhouLoginRequest
{
public string UserId { get; set; }
public string EmpCode { get; set; }
public string Password { get; set; }
public string SocialCode { get; set; }
public string Mobile { get; set; }
}
public class LoginRequestValidator : AbstractValidator<LoginRequest> public class LoginRequestValidator : AbstractValidator<LoginRequest>
{ {
public LoginRequestValidator() public LoginRequestValidator()
......
namespace Performance.DtoModels
{
internal class key
{
}
}
\ No newline at end of file
...@@ -249,5 +249,6 @@ public PerformanceDbContext(DbContextOptions<PerformanceDbContext> options) ...@@ -249,5 +249,6 @@ public PerformanceDbContext(DbContextOptions<PerformanceDbContext> options)
public virtual DbSet<per_attendance> per_attendance { get; set; } public virtual DbSet<per_attendance> per_attendance { get; set; }
public virtual DbSet<per_attendance_type> per_attendance_type { get; set; } public virtual DbSet<per_attendance_type> per_attendance_type { get; set; }
public virtual DbSet<per_attendance_vacation> per_attendance_vacation { get; set; } public virtual DbSet<per_attendance_vacation> per_attendance_vacation { get; set; }
public virtual DbSet<wx_user> wx_user { get; set; }
} }
} }

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Performance.EntityModels.Entity
{
public class wx_user
{
public int Id { get; set; }
public string UserId { get; set; }
public string PersonnelNumber { get; set; }
public DateTime? CreateTime { get; set; }
}
}
using Performance.EntityModels;
using Performance.EntityModels.Entity;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Performance.Repository.Repository
{
public class PerforWxUserRepository : PerforRepository<wx_user>
{
public PerforWxUserRepository(PerformanceDbContext context) : base(context)
{
}
}
}
using AutoMapper; using AutoMapper;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options; using Microsoft.Extensions.Options;
using Newtonsoft.Json.Linq; using Newtonsoft.Json.Linq;
using Performance.DtoModels; using Performance.DtoModels;
using Performance.DtoModels.AppSettings; using Performance.DtoModels.AppSettings;
using Performance.EntityModels; using Performance.EntityModels;
using Performance.EntityModels.Entity;
using Performance.Infrastructure; using Performance.Infrastructure;
using Performance.Repository; using Performance.Repository;
using Performance.Repository.Repository;
using RestSharp;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
...@@ -16,6 +20,7 @@ namespace Performance.Services ...@@ -16,6 +20,7 @@ namespace Performance.Services
{ {
public class UserService : IAutoInjection public class UserService : IAutoInjection
{ {
private ILogger<UserService> logger;
private Application application; private Application application;
private PerforUserRepository _userRepository; private PerforUserRepository _userRepository;
private readonly IMapper _mapper; private readonly IMapper _mapper;
...@@ -32,8 +37,12 @@ public class UserService : IAutoInjection ...@@ -32,8 +37,12 @@ public class UserService : IAutoInjection
private PerforPerallotRepository _perallotRepository; private PerforPerallotRepository _perallotRepository;
private PerforPerdeptdicRepository _perdeptdicRepository; private PerforPerdeptdicRepository _perdeptdicRepository;
private readonly PerforCofaccountingRepository perforCofaccountingRepository; private readonly PerforCofaccountingRepository perforCofaccountingRepository;
private readonly PerforWxUserRepository perforWxUserRepository;
private readonly IOptions<Wechat> _wechat;
private readonly IOptions<WzOAuth> _wzOAuth;
public UserService( public UserService(
ILogger<UserService> logger,
IMapper mapper, IMapper mapper,
IOptions<Application> application, IOptions<Application> application,
PerforSmsRepository smsRepository, PerforSmsRepository smsRepository,
...@@ -49,8 +58,12 @@ public class UserService : IAutoInjection ...@@ -49,8 +58,12 @@ public class UserService : IAutoInjection
PerforResaccountRepository resaccountRepository, PerforResaccountRepository resaccountRepository,
PerforPerallotRepository perallotRepository, PerforPerallotRepository perallotRepository,
PerforPerdeptdicRepository perdeptdicRepository, PerforPerdeptdicRepository perdeptdicRepository,
PerforCofaccountingRepository perforCofaccountingRepository) PerforCofaccountingRepository perforCofaccountingRepository,
PerforWxUserRepository perforWxUserRepository,
IOptions<Wechat> wechat,
IOptions<WzOAuth> wzOAuth)
{ {
this.logger = logger;
this.application = application.Value; this.application = application.Value;
this._userRepository = userRepository; this._userRepository = userRepository;
_mapper = mapper; _mapper = mapper;
...@@ -67,8 +80,89 @@ public class UserService : IAutoInjection ...@@ -67,8 +80,89 @@ public class UserService : IAutoInjection
this._perallotRepository = perallotRepository; this._perallotRepository = perallotRepository;
this._perdeptdicRepository = perdeptdicRepository; this._perdeptdicRepository = perdeptdicRepository;
this.perforCofaccountingRepository = perforCofaccountingRepository; this.perforCofaccountingRepository = perforCofaccountingRepository;
this.perforWxUserRepository = perforWxUserRepository;
_wechat = wechat;
_wzOAuth = wzOAuth;
}
/// <summary>
/// 访问接口
/// </summary>
/// <param name="interfaceRequest"></param>
/// <param name="content"></param>
/// <returns></returns>
public Dictionary<string, object> AccessInterface(InterfaceRequest interfaceRequest, out string content)
{
var restClient = new RestClient(interfaceRequest.Url);
restClient.Timeout = -1;
var request = new RestRequest(Method.POST);
switch (interfaceRequest.Function)
{
case "GatAccess_token":
request.AddQueryParameter("CorpId", _wechat.Value.CorpId);
request.AddQueryParameter("CorpSecret", _wechat.Value.CorpSecret);
break;
case "GetUserId":
request.AddQueryParameter("access_token", interfaceRequest.Access_token);
request.AddQueryParameter("code", interfaceRequest.Code);
break;
case "GetX_Token":
request.AddQueryParameter("Code", _wzOAuth.Value.Code);
request.AddQueryParameter("Token", _wzOAuth.Value.Token);
break;
case "ValidPass":
request.AddHeader("x-token", interfaceRequest.X_Token);
request.AddQueryParameter("empCode", interfaceRequest.wuzhouLoginRequest.EmpCode);
request.AddQueryParameter("password", interfaceRequest.wuzhouLoginRequest.Password);
request.AddQueryParameter("socialCode", interfaceRequest.wuzhouLoginRequest.SocialCode);
request.AddQueryParameter("mobile", interfaceRequest.wuzhouLoginRequest.Mobile);
break;
}
IRestResponse response = restClient.Execute(request);
content = response.Content;
if (response.StatusCode == System.Net.HttpStatusCode.OK)
{
return JsonHelper.Deserialize<Dictionary<string, object>>(response.Content);
}
else
{
logger.LogError($"接口请求错误:{response.StatusCode},{response.Content}");
return null;
} }
}
/// <summary>
/// 获取微信绑定用户的工号
/// </summary>
/// <param name="userId"></param>
/// <returns></returns>
public string GetWxUserEmpCode(string userId)
{
var wxUser = perforWxUserRepository.GetEntity(t => t.UserId == userId);
if (wxUser == null)
return "";
return wxUser.PersonnelNumber;
}
/// <summary>
/// 如果数据库里不存在该用户则添加
/// </summary>
/// <param name="userId"></param>
/// <param name="empCode"></param>
/// <returns></returns>
public bool SaveWxUser(string userId, string empCode)
{
if (string.IsNullOrEmpty(GetWxUserEmpCode(userId)))
{
var wx_user = new wx_user()
{
UserId = userId,
PersonnelNumber = empCode,
CreateTime = DateTime.Now
};
return perforWxUserRepository.Add(wx_user);
}
return false;
}
/// <summary> /// <summary>
/// 登录 /// 登录
/// </summary> /// </summary>
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment