feature: add email address to organisation address (resolves #156)

This commit is contained in:
Gary Sharp
2024-12-15 17:08:49 +11:00
parent b15917254f
commit fb6432a5c8
6 changed files with 758 additions and 611 deletions
@@ -58,19 +58,5 @@ namespace Disco.Data.Configuration.Modules
} }
} }
internal static void MigrateDatabase(DiscoDataContext Database)
{
// Migrate all organisation addresses to JSON
if (Database.ConfigurationItems.Count(i => i.Scope == scope && !i.Value.StartsWith("{")) > 0)
{
var items = Database.ConfigurationItems.Where(i => i.Scope == scope && !i.Value.StartsWith("{")).ToList();
items.ForEach(i =>
{
i.Value = JsonConvert.SerializeObject(OrganisationAddress.FromConfigurationEntry(int.Parse(i.Key), i.Value));
});
Database.SaveChanges();
}
}
} }
} }
-10
View File
@@ -20,8 +20,6 @@ namespace Disco.Data.Repository
Database.SaveChanges(); Database.SaveChanges();
// Migration Maintenance // Migration Maintenance
Database.MigrateConfiguration();
Database.MigratePreDomainObjects(); Database.MigratePreDomainObjects();
} }
@@ -312,14 +310,6 @@ namespace Disco.Data.Repository
} }
// End Added: 2013-02-07 G# // End Added: 2013-02-07 G#
public static void MigrateConfiguration(this DiscoDataContext Database)
{
// Organisation Addresses - Force all to JSON serializing
Configuration.Modules.OrganisationAddressesConfiguration.MigrateDatabase(Database);
Database.SaveChanges();
}
#region Migrate Users SQL #region Migrate Users SQL
private const string MigratePreDomainUsers_Sql = @"INSERT INTO [Users] SELECT @IdNew, u.DisplayName, u.Surname, u.GivenName, u.PhoneNumber, u.EmailAddress FROM [Users] u WHERE [Id]=@IdExisting; private const string MigratePreDomainUsers_Sql = @"INSERT INTO [Users] SELECT @IdNew, u.DisplayName, u.Surname, u.GivenName, u.PhoneNumber, u.EmailAddress FROM [Users] u WHERE [Id]=@IdExisting;
+3 -49
View File
@@ -1,12 +1,9 @@
using System; using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations;
using System.Text;
namespace Disco.Models.BI.Config namespace Disco.Models.BI.Config
{ {
public class OrganisationAddress public class OrganisationAddress
{ {
public int? Id { get; set; } public int? Id { get; set; }
[Required] [Required]
public string Name { get; set; } public string Name { get; set; }
@@ -23,54 +20,11 @@ namespace Disco.Models.BI.Config
[Required] [Required]
public string ShortName { get; set; } public string ShortName { get; set; }
// Added 2012-12-11 G#
// http://discoict.com.au/forum/support/2012/12/address-details.aspx
public string PhoneNumber { get; set; } public string PhoneNumber { get; set; }
public string FaxNumber { get; set; } public string FaxNumber { get; set; }
// End Added 2012-12-11 G# public string EmailAddress { get; set; }
public string ToConfigurationEntry()
{
StringBuilder entryBuilder = new StringBuilder();
entryBuilder.AppendLine(Name.Trim());
entryBuilder.AppendLine(Address.Trim());
entryBuilder.AppendLine(Suburb.Trim());
entryBuilder.AppendLine(Postcode.Trim());
entryBuilder.AppendLine(State.Trim());
entryBuilder.AppendLine(Country.Trim());
if (!string.IsNullOrEmpty(ShortName))
{
entryBuilder.AppendLine(ShortName.Trim());
}
return entryBuilder.ToString();
}
public static OrganisationAddress FromConfigurationEntry(int Id, string Entry)
{
string[] entryLines = Entry.Split(new string[] { Environment.NewLine }, StringSplitOptions.None);
if (entryLines.Length >= 6)
{
return new OrganisationAddress()
{
Id = Id,
Name = entryLines[0].Trim(),
Address = entryLines[1].Trim(),
Suburb = entryLines[2].Trim(),
Postcode = entryLines[3].Trim(),
State = entryLines[4].Trim(),
Country = entryLines[5].Trim(),
ShortName = (entryLines.Length > 6 ? entryLines[6].Trim() : string.Empty)
};
}
throw new ArgumentException("Invalid Configuration Address Entry", "entry");
}
public override string ToString() public override string ToString()
{ => $"{Name} ({ShortName})";
return string.Format("{0} ({1})", this.Name, this.ShortName);
}
} }
} }
@@ -149,7 +149,7 @@ namespace Disco.Web.Areas.API.Controllers
#endregion #endregion
#region Organisation Addresses #region Organisation Addresses
[DiscoAuthorize(Claims.Config.Organisation.ConfigureAddresses)] [HttpPost, ValidateAntiForgeryToken, DiscoAuthorize(Claims.Config.Organisation.ConfigureAddresses)]
public virtual ActionResult UpdateOrganisationAddress(Disco.Models.BI.Config.OrganisationAddress organisationAddress, bool redirect = false) public virtual ActionResult UpdateOrganisationAddress(Disco.Models.BI.Config.OrganisationAddress organisationAddress, bool redirect = false)
{ {
if (organisationAddress == null) if (organisationAddress == null)
@@ -185,15 +185,15 @@ namespace Disco.Web.Areas.API.Controllers
return Json(em.ToString(), JsonRequestBehavior.AllowGet); return Json(em.ToString(), JsonRequestBehavior.AllowGet);
} }
} }
[DiscoAuthorize(Claims.Config.Organisation.ConfigureAddresses)] [HttpPost, ValidateAntiForgeryToken, DiscoAuthorize(Claims.Config.Organisation.ConfigureAddresses)]
public virtual ActionResult DeleteOrganisationAddress(int Id, bool redirect = false) public virtual ActionResult DeleteOrganisationAddress(int id, bool redirect = false)
{ {
// Remove References in Device Profiles // Remove References in Device Profiles
Database.DeviceProfiles Database.DeviceProfiles
.Where(dp => dp.DefaultOrganisationAddress == Id).ToList() .Where(dp => dp.DefaultOrganisationAddress == id).ToList()
.ForEach(dp => dp.DefaultOrganisationAddress = null); .ForEach(dp => dp.DefaultOrganisationAddress = null);
Database.DiscoConfiguration.OrganisationAddresses.RemoveAddress(Id); Database.DiscoConfiguration.OrganisationAddresses.RemoveAddress(id);
Database.SaveChanges(); Database.SaveChanges();
if (redirect) if (redirect)
@@ -12,9 +12,11 @@
<h2>Details</h2> <h2>Details</h2>
<table> <table>
<tr> <tr>
<th style="width: 160px">Name: <th style="width: 160px">
Name:
</th> </th>
<td>@if (Authorization.Has(Claims.Config.Organisation.ConfigureName)) <td>
@if (Authorization.Has(Claims.Config.Organisation.ConfigureName))
{ {
@Html.EditorFor(m => m.OrganisationName) @Html.EditorFor(m => m.OrganisationName)
@AjaxHelpers.AjaxLoader() @AjaxHelpers.AjaxLoader()
@@ -37,7 +39,8 @@
</td> </td>
</tr> </tr>
<tr> <tr>
<th style="width: 160px">Logo: <th style="width: 160px">
Logo:
@if (Authorization.Has(Claims.Config.Organisation.ConfigureLogo)) @if (Authorization.Has(Claims.Config.Organisation.ConfigureLogo))
{ {
<br /> <br />
@@ -52,9 +55,11 @@
</td> </td>
</tr> </tr>
<tr> <tr>
<th style="width: 160px">Multi-Site Mode: <th style="width: 160px">
Multi-Site Mode:
</th> </th>
<td>@if (Authorization.Has(Claims.Config.Organisation.ConfigureMultiSiteMode)) <td>
@if (Authorization.Has(Claims.Config.Organisation.ConfigureMultiSiteMode))
{ {
@Html.EditorFor(m => m.MultiSiteMode) @Html.LabelFor(m => m.MultiSiteMode) @Html.EditorFor(m => m.MultiSiteMode) @Html.LabelFor(m => m.MultiSiteMode)
@AjaxHelpers.AjaxLoader() @AjaxHelpers.AjaxLoader()
@@ -72,7 +77,7 @@
} }
else else
{ {
<input name="MultiSiteMode" class="check-box" id="MultiSiteMode" type="checkbox" @(Model.MultiSiteMode ? new HtmlString("checked=\"checked\" ") : new HtmlString(string.Empty))disabled="disabled"> @Html.LabelFor(m => m.MultiSiteMode) <input name="MultiSiteMode" class="check-box" id="MultiSiteMode" type="checkbox" @(Model.MultiSiteMode ? new HtmlString("checked=\"checked\" ") : new HtmlString(string.Empty)) disabled="disabled"> @Html.LabelFor(m => m.MultiSiteMode)
} }
@if (Model.OrganisationAddresses.Count > 1) @if (Model.OrganisationAddresses.Count > 1)
{ {
@@ -85,12 +90,13 @@
</td> </td>
</tr> </tr>
<tr> <tr>
<th style="width: 160px">Addresses: <th style="width: 160px">
Addresses:
@if (canConfigAddresses) @if (canConfigAddresses)
{ {
<br /> <br />
<br /> <br />
<a href="#" id="createAddress" class="button">Create</a> <button id="createAddress" class="button">Create</button>
} }
</th> </th>
<td> <td>
@@ -98,9 +104,11 @@
{ {
<table id="organisationAddresses"> <table id="organisationAddresses">
<tr> <tr>
<th>Name <th>
Name
</th> </th>
<th>Address <th>
Address
</th> </th>
<th></th> <th></th>
</tr> </tr>
@@ -108,19 +116,30 @@
{ {
<tr data-addressid="@item.Id"> <tr data-addressid="@item.Id">
<td> <td>
<span class="name">@Html.DisplayFor(modelItem => item.Name)</span> (<span class="shortName">@Html.DisplayFor(modelItem => item.ShortName)</span>) <span>@Html.DisplayFor(modelItem => item.Name)</span> (<span>@Html.DisplayFor(modelItem => item.ShortName)</span>)
</td> </td>
<td> <td>
<span class="address">@Html.DisplayFor(modelItem => item.Address)</span><br /> <span>@Html.DisplayFor(modelItem => item.Address)</span>
<span class="suburb">@Html.DisplayFor(modelItem => item.Suburb)</span> <span class="postcode">@Html.DisplayFor(modelItem => item.Postcode)</span><br /> <br /><span>@Html.DisplayFor(modelItem => item.Suburb)</span> <span>@Html.DisplayFor(modelItem => item.Postcode)</span>
<span class="state">@Html.DisplayFor(modelItem => item.State)</span> <span class="country">@Html.DisplayFor(modelItem => item.Country)</span><br /> <br /><span>@Html.DisplayFor(modelItem => item.State)</span> <span>@Html.DisplayFor(modelItem => item.Country)</span>
<span class="smallMessage">Phone:</span> <span class="phoneNumber">@Html.DisplayFor(modelItem => item.PhoneNumber)</span><br /> @if (!string.IsNullOrWhiteSpace(item.PhoneNumber))
<span class="smallMessage">Fax:</span> <span class="faxNumber">@Html.DisplayFor(modelItem => item.FaxNumber)</span> {
<br /><span class="smallMessage">Phone:</span> <span>@Html.DisplayFor(modelItem => item.PhoneNumber)</span>
}
@if (!string.IsNullOrWhiteSpace(item.FaxNumber))
{
<br /><span class="smallMessage">Fax:</span> <span>@Html.DisplayFor(modelItem => item.FaxNumber)</span>
}
@if (!string.IsNullOrWhiteSpace(item.EmailAddress))
{
<br /><span>@Html.DisplayFor(modelItem => item.EmailAddress)</span>
}
</td> </td>
<td> <td>
@if (canConfigAddresses) @if (canConfigAddresses)
{ {
<i class="fa fa-edit information edit" title="Edit Address"></i> <i class="fa fa-times-circle warning delete" title="Delete Address"></i> <i class="fa fa-edit information edit" title="Edit Address"></i> <i class="fa fa-times-circle warning delete" title="Delete Address"></i>
<script class="addressJson" type="application/json">@Html.Raw(Json.Encode(item))</script>
} }
</td> </td>
</tr> </tr>
@@ -137,7 +156,7 @@
</div> </div>
@if (Authorization.Has(Claims.Config.Organisation.ConfigureLogo)) @if (Authorization.Has(Claims.Config.Organisation.ConfigureLogo))
{ {
<div id="dialogUpdateOrganisationLogo" title="Update Organisation Logo"> <div id="dialogUpdateOrganisationLogo" title="Update Organisation Logo" class="dialog">
@using (Html.BeginForm(MVC.API.System.OrganisationLogo(true, null, null), FormMethod.Post, new { enctype = "multipart/form-data" })) @using (Html.BeginForm(MVC.API.System.OrganisationLogo(true, null, null), FormMethod.Post, new { enctype = "multipart/form-data" }))
{ {
<h3>Update Organisation Logo</h3> <h3>Update Organisation Logo</h3>
@@ -146,8 +165,7 @@
checked="checked" /><label for="updateOrganisationLogoResetLogo">Remove Logo</label> checked="checked" /><label for="updateOrganisationLogoResetLogo">Remove Logo</label>
</div> </div>
<div style="margin-top: 5px; border-top: 1px dashed #aaa; padding-top: 5px;"> <div style="margin-top: 5px; border-top: 1px dashed #aaa; padding-top: 5px;">
<input id="updateOrganisationLogoUploadLogo" type="radio" name="ResetLogo" value="false" /><label <input id="updateOrganisationLogoUploadLogo" type="radio" name="ResetLogo" value="false" /><label for="updateOrganisationLogoUploadLogo">Upload Logo</label>
for="updateOrganisationLogoUploadLogo">Upload Logo</label>
<div id="updateOrganisationLogoUploadLogoContainer" style="display: none; padding: 4px 0 0 14px;"> <div id="updateOrganisationLogoUploadLogoContainer" style="display: none; padding: 4px 0 0 14px;">
<input id="updateOrganisationLogoUploadLogoImage" type="file" name="Image" /> <input id="updateOrganisationLogoUploadLogoImage" type="file" name="Image" />
<span id="updateOrganisationLogoUploadLogoImageRequired" class="field-validation-valid field-validation-error">* Required</span> <span id="updateOrganisationLogoUploadLogoImageRequired" class="field-validation-valid field-validation-error">* Required</span>
@@ -203,202 +221,197 @@
} }
@if (canConfigAddresses) @if (canConfigAddresses)
{ {
<div id="dialogConfirmRemove" title="Delete this Address?"> <div id="dialogConfirmRemove" title="Delete this Address?" class="dialog">
<p> <p>
<i class="fa fa-exclamation-triangle fa-lg warning"></i> <i class="fa fa-exclamation-triangle fa-lg warning"></i>
This item will be permanently deleted and cannot be recovered. This item will be permanently deleted.
</p> </p>
<p> <p>
<strong>Are you sure?</strong> <strong>Are you sure?</strong>
</p> </p>
@using (Html.BeginForm(MVC.API.System.DeleteOrganisationAddress()))
{
@Html.AntiForgeryToken()
<input name="Id" value="" type="hidden" />
<input name="redirect" value="true" type="hidden" />
}
</div> </div>
<div id="dialogEdit" title="Edit/Create Address"> <div id="dialogEdit" title="Edit/Create Address" class="dialog">
@using (Html.BeginForm(MVC.API.System.UpdateOrganisationAddress()))
{
@Html.AntiForgeryToken()
<input name="redirect" value="true" type="hidden" />
<input name="Id" value="" type="hidden" data-bind />
<table> <table>
<tr> <tr>
<td>Short&nbsp;Name <td>
<label for="editShortName">Short&nbsp;Name&nbsp;*</label>
</td> </td>
<td> <td>
<input id="editShortName" type="text" /> <input id="editShortName" name="ShortName" type="text" required data-bind />
</td> </td>
</tr> </tr>
<tr> <tr>
<td>Name <td>
<label for="editName">Name&nbsp;*</label>
</td> </td>
<td> <td>
<input id="editName" type="text" /> <input id="editName" name="Name" type="text" required data-bind />
</td> </td>
</tr> </tr>
<tr> <tr>
<td>Address <td>
<label for="editAddress">Address&nbsp;*</label>
</td> </td>
<td> <td>
<input id="editAddress" type="text" /> <input id="editAddress" name="Address" type="text" required data-bind />
</td> </td>
</tr> </tr>
<tr> <tr>
<td>Suburb <td>
<label for="editSuburb">Suburb&nbsp;*</label>
</td> </td>
<td> <td>
<input id="editSuburb" type="text" /> <input id="editSuburb" name="Suburb" type="text" required data-bind />
</td> </td>
</tr> </tr>
<tr> <tr>
<td>Postcode <td>
<label for="editPostcode">Postcode&nbsp;*</label>
</td> </td>
<td> <td>
<input id="editPostcode" type="text" /> <input id="editPostcode" name="Postcode" type="text" required data-bind />
</td> </td>
</tr> </tr>
<tr> <tr>
<td>State <td>
<label for="editState">State&nbsp;*</label>
</td> </td>
<td> <td>
<input id="editState" type="text" /> <input id="editState" name="State" type="text" required data-bind />
</td> </td>
</tr> </tr>
<tr> <tr>
<td>Country <td>
<label for="editCountry">Country&nbsp;*</label>
</td> </td>
<td> <td>
<input id="editCountry" type="text" /> <input id="editCountry" name="Country" type="text" required data-bind />
</td> </td>
</tr> </tr>
<tr> <tr>
<td>Phone Number <td>
<label for="editPhoneNumber">Phone Number</label>
</td> </td>
<td> <td>
<input id="editPhoneNumber" type="text" /> <input id="editPhoneNumber" name="PhoneNumber" type="text" data-bind />
</td> </td>
</tr> </tr>
<tr> <tr>
<td>Fax Number <td>
<label for="editFaxNumber">Fax Number</label>
</td> </td>
<td> <td>
<input id="editFaxNumber" type="text" /> <input id="editFaxNumber" name="FaxNumber" type="text" data-bind />
</td>
</tr>
<tr>
<td>
<label for="editEmailAddress">Email Address</label>
</td>
<td>
<input id="editEmailAddress" name="EmailAddress" type="text" data-bind />
</td> </td>
</tr> </tr>
</table> </table>
}
</div> </div>
<script type="text/javascript"> <script type="text/javascript">
$(function () { $(function () {
$("#dialogConfirmRemove").dialog({ let $addressEditDialog = null;
let $addressRemoveDialog = null;
$('#organisationAddresses').find('i.delete').click(function () {
const id = $(this).closest('tr').attr('data-addressid');
if (id) {
if ($addressRemoveDialog === null) {
$addressRemoveDialog = $("#dialogConfirmRemove").dialog({
resizable: false, resizable: false,
modal: true, modal: true,
autoOpen: false, autoOpen: false,
buttons: { buttons: {
"Delete": function () { "Delete": function () {
return null; const $this = $(this);
$this.dialog("disable");
$this.dialog("option", "buttons", null);
$this.find('form').trigger('submit');
}, },
Cancel: function () { Cancel: function () {
$(this).dialog("close"); $(this).dialog("close");
} }
} }
}); });
$('#organisationAddresses').find('i.delete').click(function () { }
var componentRow = $(this).closest('tr'); const $dialog = $addressRemoveDialog;
var id = componentRow.attr('data-addressid'); $dialog.find('input[name="Id"]').val(id);
if (id) { $dialog.dialog('open');
var dialog = $("#dialogConfirmRemove");
var buttons = dialog.dialog("option", "buttons");
buttons['Delete'] = function () { $(this).dialog("disable"); window.location.href = '@(Url.Action(MVC.API.System.DeleteOrganisationAddress()))' + '?redirect=true&id=' + id; };
var buttons = dialog.dialog("option", "buttons", buttons);
dialog.dialog('open');
} }
}); });
var editAddress = function (element) { function editAddress(e) {
var id = '', shortName = '', name = '', address = '', suburb = '', postcode = '', state = '', country = '', phoneNumber = '', faxNumber = ''; if ($addressEditDialog === null) {
var dialog = $('#dialogEdit'); $addressEditDialog = $("#dialogEdit").dialog({
if (element) {
id = element.attr('data-addressid');
shortName = element.find('.shortName').text();
name = element.find('.name').text();
address = element.find('.address').text();
suburb = element.find('.suburb').text();
postcode = element.find('.postcode').text();
state = element.find('.state').text();
country = element.find('.country').text();
phoneNumber = element.find('.phoneNumber').text();
faxNumber = element.find('.faxNumber').text();
dialog.attr('data-addressid', id);
dialog.dialog('option', 'title', 'Edit Address: ' + name);
} else {
dialog.attr('data-addressid', null);
dialog.dialog('option', 'title', 'Create Address');
}
$('#editShortName').val(shortName);
$('#editName').val(name);
$('#editAddress').val(address);
$('#editSuburb').val(suburb);
$('#editPostcode').val(postcode);
$('#editState').val(state);
$('#editCountry').val(country);
$('#editPhoneNumber').val(phoneNumber);
$('#editFaxNumber').val(faxNumber);
dialog.dialog('open');
}
$('#organisationAddresses').find('i.edit').click(function () {
var componentRow = $(this).closest('tr');
editAddress(componentRow);
});
$('#createAddress').click(function () {
editAddress();
return false;
});
var submitAddress = function () {
var dialog = $('#dialogEdit');
var data = {
Id: dialog.attr('data-addressid'),
ShortName: $('#editShortName').val(),
Name: $('#editName').val(),
Address: $('#editAddress').val(),
Suburb: $('#editSuburb').val(),
Postcode: $('#editPostcode').val(),
State: $('#editState').val(),
Country: $('#editCountry').val(),
PhoneNumber: $('#editPhoneNumber').val(),
FaxNumber: $('#editFaxNumber').val()
};
$.ajax({
url: '@(Url.Action(MVC.API.System.UpdateOrganisationAddress()))',
dataType: 'json',
data: data,
type: 'post',
success: function (d) {
if (d == 'OK') {
window.location.href = '@(Url.Action(MVC.Config.Organisation.Index()))';
} else {
alert('Unable to update address:\n' + d);
dialog.dialog('enable');
}
},
error: function (jqXHR, textStatus, errorThrown) {
alert('Unable to update address:\n' + textStatus);
dialog.dialog('enable');
}
});
};
$("#dialogEdit").dialog({
resizable: false, resizable: false,
modal: true, modal: true,
autoOpen: false, autoOpen: false,
width: 350, width: 350,
buttons: { buttons: {
"Save": function () { "Save": function () {
submitAddress(); const $form = $addressEditDialog.find('form');
if ($form[0].reportValidity()) {
const $this = $(this);
$this.dialog("disable");
$this.dialog("option", "buttons", null);
$form.trigger('submit');
}
}, },
Cancel: function () { Cancel: function () {
$(this).dialog("close"); $(this).dialog("close");
} }
} }
}); });
$addressEditDialog.find('form').removeAttr('novalidate');
}
const $dialog = $addressEditDialog;
if (e && e.currentTarget) {
const address = JSON.parse($(e.currentTarget).closest('tr').find('script.addressJson').html());
$dialog.dialog('option', 'title', 'Edit Address: ' + address.Name);
$dialog.find('input[data-bind]').each(function () {
const $this = $(this);
const name = $this.attr('name');
if (address[name]) {
$this.val(address[name]);
} else {
$this.val('');
}
});
} else {
$dialog.dialog('option', 'title', 'Create Address');
$dialog.find('input[data-bind]').val('');
}
$dialog.dialog('open');
$dialog.find('input[type="text"]').first().focus();
}
$('#organisationAddresses').on('click', 'i.edit', editAddress)
$('#createAddress').on('click', function (e) {
e.preventDefault();
editAddress();
return false;
});
}); });
</script> </script>
} }
File diff suppressed because it is too large Load Diff