Add AMI integration
This commit is contained in:
parent
69c9a0333c
commit
4268e4d7d9
|
@ -53,5 +53,7 @@ namespace PhoneToolMX.Models.ViewModels
|
|||
HoldMusic = extEnt.HoldMusic?.Id,
|
||||
};
|
||||
}
|
||||
// TODO: fix hack
|
||||
public string NotifyOnChange() => (ExtId == 0 ? Id + 1000 : ExtId).ToString();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,10 +6,12 @@ namespace PhoneToolMX.Models.ViewModels
|
|||
public interface IViewModel
|
||||
{
|
||||
public int? Id { get; set; }
|
||||
|
||||
|
||||
public IOwnedModel ToEntity(PTMXContext ctx);
|
||||
public IOwnedModel ToEntity(PTMXContext ctx, IOwnedModel current);
|
||||
|
||||
public IViewModel FromEntity(IOwnedModel entity);
|
||||
|
||||
public string NotifyOnChange();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,7 +8,7 @@ namespace PhoneToolMX.Models.ViewModels
|
|||
public class PhoneVM : IViewModel
|
||||
{
|
||||
public int? Id { get; set; }
|
||||
|
||||
|
||||
[Header("MAC Address")]
|
||||
[Required]
|
||||
[RegularExpression("(?:[0-9a-fA-F]{2}[-:]?){6}", ErrorMessage = "Must be of the form XX:XX:XX:XX:XX:XX, XX-XX-XX-XX-XX-XX, or XXXXXXXXXXXX")]
|
||||
|
@ -66,5 +66,10 @@ namespace PhoneToolMX.Models.ViewModels
|
|||
PrimaryExtension = phoneEnt.PrimaryExtension?.Id,
|
||||
};
|
||||
}
|
||||
|
||||
// a bit of a hack, but we can just choose any extension that belongs to this phone
|
||||
public string NotifyOnChange() => Extensions.Count > 0
|
||||
? (Extensions.First() + 1000).ToString()
|
||||
: null;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
using AsterNET.Manager;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Identity;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
@ -5,6 +6,7 @@ using PhoneToolMX.Data;
|
|||
using PhoneToolMX.Helpers;
|
||||
using PhoneToolMX.Models;
|
||||
using PhoneToolMX.Models.ViewModels;
|
||||
using PhoneToolMX.Services;
|
||||
using System.Security.Authentication;
|
||||
using System.Security.Claims;
|
||||
|
||||
|
@ -118,7 +120,7 @@ namespace PhoneToolMX.Controllers
|
|||
|
||||
SetMessage(
|
||||
FormMessageType.Success,
|
||||
$"{typeof(T).Name} {GetFriendlyName(new TViewModel().FromEntity(entity.Entity))} was created."
|
||||
$"{typeof(T).Name} {GetFriendlyName(entity.Entity)} was created."
|
||||
);
|
||||
|
||||
return RedirectToAction("Edit", new { id = entity.Entity.Id });
|
||||
|
@ -170,9 +172,22 @@ namespace PhoneToolMX.Controllers
|
|||
_context.Set<T>().Update(currentModel);
|
||||
await _context.SaveChangesAsync();
|
||||
|
||||
// Try to notify the relevant endpoint to update its config
|
||||
var amiStatus = "";
|
||||
if (HttpContext.RequestServices.GetService<IAsteriskManager>() is {} ami) {
|
||||
try { await ami.SendNotifyAsync(vm.NotifyOnChange());
|
||||
amiStatus = "Your phone's configuration should be updated shortly.";
|
||||
}
|
||||
catch (BadResponseException e) { amiStatus = $"You'll need to manually update your phone settings (AMI Response: {e.Message})."; }
|
||||
catch (ManagerException e) { amiStatus = $"You'll need to manually update your phone settings (AMI Client Error: {e.Message})."; }
|
||||
catch (Exception e) {
|
||||
amiStatus = $"You'll need to manually update your phone settings (Unknown Error: {e.Message}).";
|
||||
}
|
||||
}
|
||||
|
||||
SetMessage(
|
||||
FormMessageType.Success,
|
||||
$"{typeof(T).Name} {GetFriendlyName(vm)} was updated."
|
||||
$"{typeof(T).Name} {GetFriendlyName(currentModel)} was updated.{" " + amiStatus}"
|
||||
);
|
||||
|
||||
return RedirectToAction("Edit", new { id = entity.Id });
|
||||
|
|
|
@ -10,6 +10,7 @@ using Microsoft.Extensions.Options;
|
|||
using Microsoft.IdentityModel.Protocols.OpenIdConnect;
|
||||
using NuGet.Packaging;
|
||||
using PhoneToolMX.Models;
|
||||
using PhoneToolMX.Services;
|
||||
using System.Net;
|
||||
using System.Security.Authentication;
|
||||
using System.Security.Claims;
|
||||
|
@ -112,6 +113,11 @@ builder.Services.AddAuthorization(opts =>
|
|||
policy => policy.RequireRole("Administrator"));
|
||||
});
|
||||
|
||||
// AMI for PJSIP notifications
|
||||
if (builder.Configuration.GetSection("ami").Exists()) {
|
||||
builder.Services.AddSingleton<IAsteriskManager, AsteriskManager>();
|
||||
}
|
||||
|
||||
var app = builder.Build();
|
||||
|
||||
// Configure the HTTP request pipeline.
|
||||
|
|
36
PhoneToolMX/Services/AsteriskManager.cs
Normal file
36
PhoneToolMX/Services/AsteriskManager.cs
Normal file
|
@ -0,0 +1,36 @@
|
|||
using System.Collections;
|
||||
using System.Net.Security;
|
||||
using System.Net.Sockets;
|
||||
using System.Text;
|
||||
using AsterNET.Manager;
|
||||
|
||||
namespace PhoneToolMX.Services
|
||||
{
|
||||
public class AsteriskManager : IAsteriskManager
|
||||
{
|
||||
private IConfigurationSection amiConf;
|
||||
private ManagerConnection conn;
|
||||
public AsteriskManager(IConfiguration config)
|
||||
{
|
||||
amiConf = config.GetRequiredSection("ami");
|
||||
conn = new ManagerConnection(amiConf["host"],
|
||||
int.Parse(amiConf["port"]),
|
||||
amiConf["username"],
|
||||
amiConf["secret"]);
|
||||
conn.Login();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sends a <c>polycom-check-cfg</c> notification to the requested PJSIP endpoint.
|
||||
/// </summary>
|
||||
/// <param name="endpoint">The PJSIP endpoint to notify, without the <c>PJSIP/</c> prefix.</param>
|
||||
/// <exception cref="BadResponseException">If the request fails, this exception will be thrown.</exception>
|
||||
public async Task SendNotifyAsync(string endpoint)
|
||||
{
|
||||
var response = await conn.SendActionAsync(new PJSIPNotifyAction(endpoint, "polycom-check-cfg"));
|
||||
if (!response.IsSuccess()) {
|
||||
throw new BadResponseException(response.Message);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
7
PhoneToolMX/Services/BadResponseException.cs
Normal file
7
PhoneToolMX/Services/BadResponseException.cs
Normal file
|
@ -0,0 +1,7 @@
|
|||
namespace PhoneToolMX.Services
|
||||
{
|
||||
public class BadResponseException : Exception
|
||||
{
|
||||
public BadResponseException(string message) : base(message) {}
|
||||
}
|
||||
}
|
7
PhoneToolMX/Services/IAsteriskManager.cs
Normal file
7
PhoneToolMX/Services/IAsteriskManager.cs
Normal file
|
@ -0,0 +1,7 @@
|
|||
namespace PhoneToolMX.Services
|
||||
{
|
||||
public interface IAsteriskManager
|
||||
{
|
||||
public Task SendNotifyAsync(string endpoint);
|
||||
}
|
||||
}
|
25
PhoneToolMX/Services/PJSIPNotifyAction.cs
Normal file
25
PhoneToolMX/Services/PJSIPNotifyAction.cs
Normal file
|
@ -0,0 +1,25 @@
|
|||
namespace PhoneToolMX.Services
|
||||
{
|
||||
public class PJSIPNotifyAction : AsterNET.Manager.Action.ManagerAction
|
||||
{
|
||||
|
||||
public override string Action => "PJSIPNotify";
|
||||
|
||||
/// <summary>
|
||||
/// The endpoint to which to send the NOTIFY.
|
||||
/// </summary>
|
||||
public string Endpoint { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The config section name from <c>pjsip_notify.conf</c> to use.
|
||||
/// One of Option or Variable must be specified.
|
||||
/// </summary>
|
||||
public string Option { get; set; }
|
||||
|
||||
public PJSIPNotifyAction(string endpoint, string option)
|
||||
{
|
||||
Endpoint = endpoint;
|
||||
Option = option;
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue