v1.3.0 Restructure Saxonite workspace and upgrade to .NET 10 (#1)
Move Saxonite’s projects into a dedicated `Workspace` folder and align the solution with .NET 10 and the current Common workspace. Update encryption integration, test project structure and coverage, and repository guidance and upgrade notes. - Relocate application and library projects while retaining Git rename history. - Split tests into Admin, Online, and Shared projects; add representative behavioral and serialization tests. - Update Common integration, application version, and repository documentation. Application version: 1.3.0 Reviewed-on: #1 Co-authored-by: andy <andy@sarand.com>
This commit was merged in pull request #1.
This commit is contained in:
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"version": 1,
|
||||
"isRoot": true,
|
||||
"tools": {
|
||||
"dotnet-ef": {
|
||||
"version": "5.0.5",
|
||||
"commands": [
|
||||
"dotnet-ef"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,938 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<root>
|
||||
<!--
|
||||
Microsoft ResX Schema
|
||||
|
||||
Version 2.0
|
||||
|
||||
The primary goals of this format is to allow a simple XML format
|
||||
that is mostly human readable. The generation and parsing of the
|
||||
various data types are done through the TypeConverter classes
|
||||
associated with the data types.
|
||||
|
||||
Example:
|
||||
|
||||
... ado.net/XML headers & schema ...
|
||||
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||
<resheader name="version">2.0</resheader>
|
||||
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
|
||||
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
|
||||
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
|
||||
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
|
||||
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
|
||||
<value>[base64 mime encoded serialized .NET Framework object]</value>
|
||||
</data>
|
||||
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
||||
<comment>This is a comment</comment>
|
||||
</data>
|
||||
|
||||
There are any number of "resheader" rows that contain simple
|
||||
name/value pairs.
|
||||
|
||||
Each data row contains a name, and value. The row also contains a
|
||||
type or mimetype. Type corresponds to a .NET class that support
|
||||
text/value conversion through the TypeConverter architecture.
|
||||
Classes that don't support this are serialized and stored with the
|
||||
mimetype set.
|
||||
|
||||
The mimetype is used for serialized objects, and tells the
|
||||
ResXResourceReader how to depersist the object. This is currently not
|
||||
extensible. For a given mimetype the value must be set accordingly:
|
||||
|
||||
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||
that the ResXResourceWriter will generate, however the reader can
|
||||
read any of the formats listed below.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.binary.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.soap.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||
value : The object must be serialized into a byte array
|
||||
: using a System.ComponentModel.TypeConverter
|
||||
: and then encoded with base64 encoding.
|
||||
-->
|
||||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
||||
<xsd:element name="root" msdata:IsDataSet="true">
|
||||
<xsd:complexType>
|
||||
<xsd:choice maxOccurs="unbounded">
|
||||
<xsd:element name="metadata">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" use="required" type="xsd:string" />
|
||||
<xsd:attribute name="type" type="xsd:string" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="assembly">
|
||||
<xsd:complexType>
|
||||
<xsd:attribute name="alias" type="xsd:string" />
|
||||
<xsd:attribute name="name" type="xsd:string" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="data">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
|
||||
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="resheader">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:choice>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:schema>
|
||||
<resheader name="resmimetype">
|
||||
<value>text/microsoft-resx</value>
|
||||
</resheader>
|
||||
<resheader name="version">
|
||||
<value>2.0</value>
|
||||
</resheader>
|
||||
<resheader name="reader">
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<data name="account.activate.caption" xml:space="preserve">
|
||||
<value>Account Activation</value>
|
||||
</data>
|
||||
<data name="account.activate.email.subject" xml:space="preserve">
|
||||
<value>Account Activation</value>
|
||||
</data>
|
||||
<data name="account.activate.info" xml:space="preserve">
|
||||
<value>An activation email will be sent to the selected user inviting them to assign a password and access the platform.</value>
|
||||
</data>
|
||||
<data name="account.activate.notify" xml:space="preserve">
|
||||
<value>Member account has been activated and welcome email sent.</value>
|
||||
</data>
|
||||
<data name="account.caption.image.upload" xml:space="preserve">
|
||||
<value>Image Upload</value>
|
||||
</data>
|
||||
<data name="account.caption.profile" xml:space="preserve">
|
||||
<value>My Profile</value>
|
||||
</data>
|
||||
<data name="account.caption.profile.contact" xml:space="preserve">
|
||||
<value>My Details</value>
|
||||
</data>
|
||||
<data name="account.caption.profile.eligibility" xml:space="preserve">
|
||||
<value>Eligibility</value>
|
||||
</data>
|
||||
<data name="account.caption.profile.eligibility.add" xml:space="preserve">
|
||||
<value>Add Eligibility</value>
|
||||
</data>
|
||||
<data name="account.caption.profile.eligibility.remove" xml:space="preserve">
|
||||
<value>Remove Eligibility</value>
|
||||
</data>
|
||||
<data name="account.caption.profile.eligibility.update" xml:space="preserve">
|
||||
<value>Update Eligibility</value>
|
||||
</data>
|
||||
<data name="account.caption.profile.organisations" xml:space="preserve">
|
||||
<value>My Organisations</value>
|
||||
</data>
|
||||
<data name="account.caption.profile.sport" xml:space="preserve">
|
||||
<value>My Sport</value>
|
||||
</data>
|
||||
<data name="account.caption.profile.sport.add" xml:space="preserve">
|
||||
<value>Add Sport</value>
|
||||
</data>
|
||||
<data name="account.caption.profile.sport.update" xml:space="preserve">
|
||||
<value>My Sport</value>
|
||||
</data>
|
||||
<data name="account.caption.profile.sports" xml:space="preserve">
|
||||
<value>My Sports</value>
|
||||
</data>
|
||||
<data name="account.caption.profile.sports.experience" xml:space="preserve">
|
||||
<value>Sport Experience</value>
|
||||
</data>
|
||||
<data name="activity.caption.activities" xml:space="preserve">
|
||||
<value>Activities</value>
|
||||
</data>
|
||||
<data name="activity.caption.activity" xml:space="preserve">
|
||||
<value>Activity</value>
|
||||
</data>
|
||||
<data name="article.caption.article" xml:space="preserve">
|
||||
<value>Article</value>
|
||||
</data>
|
||||
<data name="article.caption.article.create" xml:space="preserve">
|
||||
<value>Create Article</value>
|
||||
</data>
|
||||
<data name="article.caption.article.update" xml:space="preserve">
|
||||
<value>Update Article</value>
|
||||
</data>
|
||||
<data name="article.caption.articles" xml:space="preserve">
|
||||
<value>Articles</value>
|
||||
</data>
|
||||
<data name="caption.contact.method" xml:space="preserve">
|
||||
<value>Contact Method</value>
|
||||
</data>
|
||||
<data name="caption.feedback" xml:space="preserve">
|
||||
<value>Feedback</value>
|
||||
</data>
|
||||
<data name="caption.member.create" xml:space="preserve">
|
||||
<value>Add Member</value>
|
||||
</data>
|
||||
<data name="caption.member.update" xml:space="preserve">
|
||||
<value>Update Member</value>
|
||||
</data>
|
||||
<data name="caption.my.eligibility" xml:space="preserve">
|
||||
<value>My Eligibility</value>
|
||||
</data>
|
||||
<data name="caption.show.info" xml:space="preserve">
|
||||
<value>Show info</value>
|
||||
</data>
|
||||
<data name="caption.user.config" xml:space="preserve">
|
||||
<value>User Configuration</value>
|
||||
</data>
|
||||
<data name="caption.user.report.create" xml:space="preserve">
|
||||
<value>Create User Report</value>
|
||||
</data>
|
||||
<data name="caption.user.report.update" xml:space="preserve">
|
||||
<value>Update User Report</value>
|
||||
</data>
|
||||
<data name="caption.version.history" xml:space="preserve">
|
||||
<value>Version History</value>
|
||||
</data>
|
||||
<data name="company.name" xml:space="preserve">
|
||||
<value>Solum Forti</value>
|
||||
</data>
|
||||
<data name="copyright.symbol.year.html" xml:space="preserve">
|
||||
<value>&copy; {0}</value>
|
||||
</data>
|
||||
<data name="dialog.title.alert" xml:space="preserve">
|
||||
<value>Alert</value>
|
||||
</data>
|
||||
<data name="dialog.title.confirm" xml:space="preserve">
|
||||
<value>Confirm</value>
|
||||
</data>
|
||||
<data name="dialog.title.progress" xml:space="preserve">
|
||||
<value>Progress</value>
|
||||
</data>
|
||||
<data name="dialog.title.signout" xml:space="preserve">
|
||||
<value>Sign-out</value>
|
||||
</data>
|
||||
<data name="home.caption.activities" xml:space="preserve">
|
||||
<value>Activities</value>
|
||||
</data>
|
||||
<data name="home.caption.application" xml:space="preserve">
|
||||
<value>Online</value>
|
||||
</data>
|
||||
<data name="home.caption.home" xml:space="preserve">
|
||||
<value>Home</value>
|
||||
</data>
|
||||
<data name="home.caption.welcome" xml:space="preserve">
|
||||
<value>Welcome</value>
|
||||
</data>
|
||||
<data name="home.organisation.request.action" xml:space="preserve">
|
||||
<value>Register Your Organisation</value>
|
||||
</data>
|
||||
<data name="home.organisation.request.para1" xml:space="preserve">
|
||||
<value>Do you belong to a club or association that would benefit from participating on this platform?</value>
|
||||
</data>
|
||||
<data name="home.organisation.request.para2" xml:space="preserve">
|
||||
<value>Sign-up now with a few details and we'll let you know when you can login and get going.</value>
|
||||
</data>
|
||||
<data name="info.char.available" xml:space="preserve">
|
||||
<value>[1 char available]</value>
|
||||
</data>
|
||||
<data name="info.chars.available" xml:space="preserve">
|
||||
<value>[{0} chars available]</value>
|
||||
</data>
|
||||
<data name="info.profile.eligibility" xml:space="preserve">
|
||||
<value>You can identify the countries that you are eligible to participate for by adding references to your parentage and passport/visas.</value>
|
||||
</data>
|
||||
<data name="label. registered" xml:space="preserve">
|
||||
<value>Registered</value>
|
||||
</data>
|
||||
<data name="label.about" xml:space="preserve">
|
||||
<value>About</value>
|
||||
</data>
|
||||
<data name="label.account" xml:space="preserve">
|
||||
<value>My Account</value>
|
||||
</data>
|
||||
<data name="label.actions" xml:space="preserve">
|
||||
<value>Actions</value>
|
||||
</data>
|
||||
<data name="label.activate" xml:space="preserve">
|
||||
<value>Activate</value>
|
||||
</data>
|
||||
<data name="label.add" xml:space="preserve">
|
||||
<value>Add</value>
|
||||
</data>
|
||||
<data name="label.address" xml:space="preserve">
|
||||
<value>Address</value>
|
||||
</data>
|
||||
<data name="label.address.lines" xml:space="preserve">
|
||||
<value>Address lines</value>
|
||||
</data>
|
||||
<data name="label.alternatively" xml:space="preserve">
|
||||
<value>Alternatively</value>
|
||||
</data>
|
||||
<data name="label.any" xml:space="preserve">
|
||||
<value>Any</value>
|
||||
</data>
|
||||
<data name="label.application" xml:space="preserve">
|
||||
<value>Application</value>
|
||||
</data>
|
||||
<data name="label.article" xml:space="preserve">
|
||||
<value>Article</value>
|
||||
</data>
|
||||
<data name="label.associations" xml:space="preserve">
|
||||
<value>Associations</value>
|
||||
</data>
|
||||
<data name="label.at" xml:space="preserve">
|
||||
<value>At</value>
|
||||
</data>
|
||||
<data name="label.average" xml:space="preserve">
|
||||
<value>Average</value>
|
||||
</data>
|
||||
<data name="label.awards" xml:space="preserve">
|
||||
<value>Awards</value>
|
||||
</data>
|
||||
<data name="label.bio" xml:space="preserve">
|
||||
<value>Bio</value>
|
||||
</data>
|
||||
<data name="label.calendar" xml:space="preserve">
|
||||
<value>Calendar</value>
|
||||
</data>
|
||||
<data name="label.cancel" xml:space="preserve">
|
||||
<value>Cancel</value>
|
||||
</data>
|
||||
<data name="label.category" xml:space="preserve">
|
||||
<value>Category</value>
|
||||
</data>
|
||||
<data name="label.clear" xml:space="preserve">
|
||||
<value>Clear</value>
|
||||
</data>
|
||||
<data name="label.close" xml:space="preserve">
|
||||
<value>Close</value>
|
||||
</data>
|
||||
<data name="label.club" xml:space="preserve">
|
||||
<value>Club</value>
|
||||
</data>
|
||||
<data name="label.comment" xml:space="preserve">
|
||||
<value>Comment</value>
|
||||
</data>
|
||||
<data name="label.contact" xml:space="preserve">
|
||||
<value>Contact</value>
|
||||
</data>
|
||||
<data name="label.contact.details" xml:space="preserve">
|
||||
<value>Contact details</value>
|
||||
</data>
|
||||
<data name="label.contact.method" xml:space="preserve">
|
||||
<value>Contact method</value>
|
||||
</data>
|
||||
<data name="label.contacts" xml:space="preserve">
|
||||
<value>Contacts</value>
|
||||
</data>
|
||||
<data name="label.copy" xml:space="preserve">
|
||||
<value>Copy</value>
|
||||
</data>
|
||||
<data name="label.country" xml:space="preserve">
|
||||
<value>Country</value>
|
||||
</data>
|
||||
<data name="label.create" xml:space="preserve">
|
||||
<value>Create</value>
|
||||
</data>
|
||||
<data name="label.created" xml:space="preserve">
|
||||
<value>Created</value>
|
||||
</data>
|
||||
<data name="label.date" xml:space="preserve">
|
||||
<value>Date</value>
|
||||
</data>
|
||||
<data name="label.date.of.birth" xml:space="preserve">
|
||||
<value>Date of birth</value>
|
||||
</data>
|
||||
<data name="label.day" xml:space="preserve">
|
||||
<value>Day</value>
|
||||
</data>
|
||||
<data name="label.delete" xml:space="preserve">
|
||||
<value>Delete</value>
|
||||
</data>
|
||||
<data name="label.details" xml:space="preserve">
|
||||
<value>Details</value>
|
||||
</data>
|
||||
<data name="label.discipline" xml:space="preserve">
|
||||
<value>Discipline</value>
|
||||
</data>
|
||||
<data name="label.download" xml:space="preserve">
|
||||
<value>Download</value>
|
||||
</data>
|
||||
<data name="label.drag.image.here" xml:space="preserve">
|
||||
<value>Drag your image here.</value>
|
||||
</data>
|
||||
<data name="label.duration" xml:space="preserve">
|
||||
<value>Duration</value>
|
||||
</data>
|
||||
<data name="label.edit" xml:space="preserve">
|
||||
<value>Edit</value>
|
||||
</data>
|
||||
<data name="label.effective" xml:space="preserve">
|
||||
<value>Effective</value>
|
||||
</data>
|
||||
<data name="label.eligibility" xml:space="preserve">
|
||||
<value>Eligibility</value>
|
||||
</data>
|
||||
<data name="label.email" xml:space="preserve">
|
||||
<value>Email</value>
|
||||
</data>
|
||||
<data name="label.email.address" xml:space="preserve">
|
||||
<value>Email address</value>
|
||||
</data>
|
||||
<data name="label.ends" xml:space="preserve">
|
||||
<value>Ends</value>
|
||||
</data>
|
||||
<data name="label.events" xml:space="preserve">
|
||||
<value>Events</value>
|
||||
</data>
|
||||
<data name="label.excellent" xml:space="preserve">
|
||||
<value>Excellent</value>
|
||||
</data>
|
||||
<data name="label.experience" xml:space="preserve">
|
||||
<value>Experience</value>
|
||||
</data>
|
||||
<data name="label.expires" xml:space="preserve">
|
||||
<value>Expires</value>
|
||||
</data>
|
||||
<data name="label.expires.on" xml:space="preserve">
|
||||
<value>Expires on</value>
|
||||
</data>
|
||||
<data name="label.expiry" xml:space="preserve">
|
||||
<value>Expiry</value>
|
||||
</data>
|
||||
<data name="label.facebook" xml:space="preserve">
|
||||
<value>Facebook</value>
|
||||
</data>
|
||||
<data name="label.facilities" xml:space="preserve">
|
||||
<value>Facilities</value>
|
||||
</data>
|
||||
<data name="label.feedback" xml:space="preserve">
|
||||
<value>Feedback</value>
|
||||
</data>
|
||||
<data name="label.finishes" xml:space="preserve">
|
||||
<value>Finishes</value>
|
||||
</data>
|
||||
<data name="label.first" xml:space="preserve">
|
||||
<value>First</value>
|
||||
</data>
|
||||
<data name="label.first.name" xml:space="preserve">
|
||||
<value>First name</value>
|
||||
</data>
|
||||
<data name="label.follow" xml:space="preserve">
|
||||
<value>Follow</value>
|
||||
</data>
|
||||
<data name="label.forgotten.password" xml:space="preserve">
|
||||
<value>Forgotten password?</value>
|
||||
</data>
|
||||
<data name="label.from" xml:space="preserve">
|
||||
<value>From</value>
|
||||
</data>
|
||||
<data name="label.gender" xml:space="preserve">
|
||||
<value>Gender</value>
|
||||
</data>
|
||||
<data name="label.good" xml:space="preserve">
|
||||
<value>Good</value>
|
||||
</data>
|
||||
<data name="label.headline" xml:space="preserve">
|
||||
<value>Headline</value>
|
||||
</data>
|
||||
<data name="label.home" xml:space="preserve">
|
||||
<value>Home</value>
|
||||
</data>
|
||||
<data name="label.image" xml:space="preserve">
|
||||
<value>Image</value>
|
||||
</data>
|
||||
<data name="label.info" xml:space="preserve">
|
||||
<value>Info</value>
|
||||
</data>
|
||||
<data name="label.keep.signed.in" xml:space="preserve">
|
||||
<value>Remember Me</value>
|
||||
</data>
|
||||
<data name="label.last" xml:space="preserve">
|
||||
<value>Last</value>
|
||||
</data>
|
||||
<data name="label.last.name" xml:space="preserve">
|
||||
<value>Last name</value>
|
||||
</data>
|
||||
<data name="label.league" xml:space="preserve">
|
||||
<value>League</value>
|
||||
</data>
|
||||
<data name="label.location" xml:space="preserve">
|
||||
<value>Location</value>
|
||||
</data>
|
||||
<data name="label.logo" xml:space="preserve">
|
||||
<value>Logo</value>
|
||||
</data>
|
||||
<data name="label.main" xml:space="preserve">
|
||||
<value>Main</value>
|
||||
</data>
|
||||
<data name="label.member" xml:space="preserve">
|
||||
<value>Member</value>
|
||||
</data>
|
||||
<data name="label.members" xml:space="preserve">
|
||||
<value>Members</value>
|
||||
</data>
|
||||
<data name="label.method" xml:space="preserve">
|
||||
<value>Method</value>
|
||||
</data>
|
||||
<data name="label.mobile" xml:space="preserve">
|
||||
<value>Mobile</value>
|
||||
</data>
|
||||
<data name="label.month" xml:space="preserve">
|
||||
<value>Month</value>
|
||||
</data>
|
||||
<data name="label.my.organisations" xml:space="preserve">
|
||||
<value>My Organisations</value>
|
||||
</data>
|
||||
<data name="label.my.sports" xml:space="preserve">
|
||||
<value>My Sports</value>
|
||||
</data>
|
||||
<data name="label.name" xml:space="preserve">
|
||||
<value>Name</value>
|
||||
</data>
|
||||
<data name="label.next" xml:space="preserve">
|
||||
<value>Next</value>
|
||||
</data>
|
||||
<data name="label.no" xml:space="preserve">
|
||||
<value>No</value>
|
||||
</data>
|
||||
<data name="label.not.specified" xml:space="preserve">
|
||||
<value>Not specified</value>
|
||||
</data>
|
||||
<data name="label.occurs" xml:space="preserve">
|
||||
<value>Occurs</value>
|
||||
</data>
|
||||
<data name="label.office" xml:space="preserve">
|
||||
<value>Office</value>
|
||||
</data>
|
||||
<data name="label.officiating" xml:space="preserve">
|
||||
<value>Officiating</value>
|
||||
</data>
|
||||
<data name="label.ok" xml:space="preserve">
|
||||
<value>OK</value>
|
||||
</data>
|
||||
<data name="label.on" xml:space="preserve">
|
||||
<value>On</value>
|
||||
</data>
|
||||
<data name="label.opportunities" xml:space="preserve">
|
||||
<value>Opportunities</value>
|
||||
</data>
|
||||
<data name="label.opportunity" xml:space="preserve">
|
||||
<value>Opportunity</value>
|
||||
</data>
|
||||
<data name="label.organisation" xml:space="preserve">
|
||||
<value>Organisation</value>
|
||||
</data>
|
||||
<data name="label.organsiation.details" xml:space="preserve">
|
||||
<value>Organisation details</value>
|
||||
</data>
|
||||
<data name="label.outline" xml:space="preserve">
|
||||
<value>Outline</value>
|
||||
</data>
|
||||
<data name="label.page.info" xml:space="preserve">
|
||||
<value>Page {0} of {1}</value>
|
||||
</data>
|
||||
<data name="label.participating" xml:space="preserve">
|
||||
<value>Participating</value>
|
||||
</data>
|
||||
<data name="label.password" xml:space="preserve">
|
||||
<value>Password</value>
|
||||
</data>
|
||||
<data name="label.password.confirm" xml:space="preserve">
|
||||
<value>Confirm password</value>
|
||||
</data>
|
||||
<data name="label.password.current" xml:space="preserve">
|
||||
<value>Current password</value>
|
||||
</data>
|
||||
<data name="label.period" xml:space="preserve">
|
||||
<value>Period</value>
|
||||
</data>
|
||||
<data name="label.phone" xml:space="preserve">
|
||||
<value>Phone</value>
|
||||
</data>
|
||||
<data name="label.position" xml:space="preserve">
|
||||
<value>Position</value>
|
||||
</data>
|
||||
<data name="label.postal.code" xml:space="preserve">
|
||||
<value>Postal code</value>
|
||||
</data>
|
||||
<data name="label.preparing" xml:space="preserve">
|
||||
<value>Preparing</value>
|
||||
</data>
|
||||
<data name="label.previous" xml:space="preserve">
|
||||
<value>Previous</value>
|
||||
</data>
|
||||
<data name="label.province" xml:space="preserve">
|
||||
<value>Province</value>
|
||||
</data>
|
||||
<data name="label.publication" xml:space="preserve">
|
||||
<value>Publication</value>
|
||||
</data>
|
||||
<data name="label.publish" xml:space="preserve">
|
||||
<value>Publish</value>
|
||||
</data>
|
||||
<data name="label.published" xml:space="preserve">
|
||||
<value>Published</value>
|
||||
</data>
|
||||
<data name="label.raised" xml:space="preserve">
|
||||
<value>Raised</value>
|
||||
</data>
|
||||
<data name="label.raised.by" xml:space="preserve">
|
||||
<value>Raised by</value>
|
||||
</data>
|
||||
<data name="label.reference" xml:space="preserve">
|
||||
<value>Reference</value>
|
||||
</data>
|
||||
<data name="label.refresh" xml:space="preserve">
|
||||
<value>Refresh</value>
|
||||
</data>
|
||||
<data name="label.region" xml:space="preserve">
|
||||
<value>Region</value>
|
||||
</data>
|
||||
<data name="label.region.selected" xml:space="preserve">
|
||||
<value>Selected region</value>
|
||||
</data>
|
||||
<data name="label.regions.available" xml:space="preserve">
|
||||
<value>Available regions</value>
|
||||
</data>
|
||||
<data name="label.remove" xml:space="preserve">
|
||||
<value>Remove</value>
|
||||
</data>
|
||||
<data name="label.report" xml:space="preserve">
|
||||
<value>Report</value>
|
||||
</data>
|
||||
<data name="label.roles" xml:space="preserve">
|
||||
<value>Roles</value>
|
||||
</data>
|
||||
<data name="label.save" xml:space="preserve">
|
||||
<value>Save</value>
|
||||
</data>
|
||||
<data name="label.search" xml:space="preserve">
|
||||
<value>Search</value>
|
||||
</data>
|
||||
<data name="label.security" xml:space="preserve">
|
||||
<value>Security</value>
|
||||
</data>
|
||||
<data name="label.select" xml:space="preserve">
|
||||
<value>Select</value>
|
||||
</data>
|
||||
<data name="label.selected.count" xml:space="preserve">
|
||||
<value>{0} selected</value>
|
||||
</data>
|
||||
<data name="label.selected.none" xml:space="preserve">
|
||||
<value>none selected</value>
|
||||
</data>
|
||||
<data name="label.speciality" xml:space="preserve">
|
||||
<value>Speciality</value>
|
||||
</data>
|
||||
<data name="label.sport" xml:space="preserve">
|
||||
<value>Sport</value>
|
||||
</data>
|
||||
<data name="label.sport.selected" xml:space="preserve">
|
||||
<value>Selected sport</value>
|
||||
</data>
|
||||
<data name="label.sports.available" xml:space="preserve">
|
||||
<value>Available sports</value>
|
||||
</data>
|
||||
<data name="label.starts" xml:space="preserve">
|
||||
<value>Starts</value>
|
||||
</data>
|
||||
<data name="label.strength" xml:space="preserve">
|
||||
<value>Strength</value>
|
||||
</data>
|
||||
<data name="label.summary" xml:space="preserve">
|
||||
<value>Summary</value>
|
||||
</data>
|
||||
<data name="label.support" xml:space="preserve">
|
||||
<value>Support</value>
|
||||
</data>
|
||||
<data name="label.team" xml:space="preserve">
|
||||
<value>Team</value>
|
||||
</data>
|
||||
<data name="label.time" xml:space="preserve">
|
||||
<value>Time</value>
|
||||
</data>
|
||||
<data name="label.title" xml:space="preserve">
|
||||
<value>Title</value>
|
||||
</data>
|
||||
<data name="label.to" xml:space="preserve">
|
||||
<value>To</value>
|
||||
</data>
|
||||
<data name="label.town" xml:space="preserve">
|
||||
<value>Town</value>
|
||||
</data>
|
||||
<data name="label.twitter" xml:space="preserve">
|
||||
<value>Twitter</value>
|
||||
</data>
|
||||
<data name="label.type" xml:space="preserve">
|
||||
<value>Type</value>
|
||||
</data>
|
||||
<data name="label.until" xml:space="preserve">
|
||||
<value>Until</value>
|
||||
</data>
|
||||
<data name="label.update" xml:space="preserve">
|
||||
<value>Update</value>
|
||||
</data>
|
||||
<data name="label.upload" xml:space="preserve">
|
||||
<value>Upload</value>
|
||||
</data>
|
||||
<data name="label.user" xml:space="preserve">
|
||||
<value>User</value>
|
||||
</data>
|
||||
<data name="label.users" xml:space="preserve">
|
||||
<value>Users</value>
|
||||
</data>
|
||||
<data name="label.value" xml:space="preserve">
|
||||
<value>Value</value>
|
||||
</data>
|
||||
<data name="label.very.good" xml:space="preserve">
|
||||
<value>Very Good</value>
|
||||
</data>
|
||||
<data name="label.view" xml:space="preserve">
|
||||
<value>View</value>
|
||||
</data>
|
||||
<data name="label.views" xml:space="preserve">
|
||||
<value>Views</value>
|
||||
</data>
|
||||
<data name="label.website" xml:space="preserve">
|
||||
<value>Website</value>
|
||||
</data>
|
||||
<data name="label.wikipedia" xml:space="preserve">
|
||||
<value>Wikipedia</value>
|
||||
</data>
|
||||
<data name="label.year" xml:space="preserve">
|
||||
<value>Year</value>
|
||||
</data>
|
||||
<data name="label.yes" xml:space="preserve">
|
||||
<value>Yes</value>
|
||||
</data>
|
||||
<data name="msg.confirm.item.remove" xml:space="preserve">
|
||||
<value>Are you sure that this item should be removed?</value>
|
||||
</data>
|
||||
<data name="msg.data.noneFound" xml:space="preserve">
|
||||
<value>No matching data has been found.</value>
|
||||
</data>
|
||||
<data name="msg.data.querying" xml:space="preserve">
|
||||
<value>Querying data. Please wait ...</value>
|
||||
</data>
|
||||
<data name="msg.data.refreshing" xml:space="preserve">
|
||||
<value>Refreshing data. Please wait ...</value>
|
||||
</data>
|
||||
<data name="msg.error.item.delete.failed" xml:space="preserve">
|
||||
<value>Item deletion failed</value>
|
||||
</data>
|
||||
<data name="msg.error.item.duplicate" xml:space="preserve">
|
||||
<value>A duplicate item already exists.</value>
|
||||
</data>
|
||||
<data name="msg.error.item.id.not.found" xml:space="preserve">
|
||||
<value>Item not found for specified Id</value>
|
||||
</data>
|
||||
<data name="msg.error.item.id.not.specified" xml:space="preserve">
|
||||
<value>Item Id not specified</value>
|
||||
</data>
|
||||
<data name="msg.error.item.insert.failed" xml:space="preserve">
|
||||
<value>Item creation failed</value>
|
||||
</data>
|
||||
<data name="msg.error.item.update.failed" xml:space="preserve">
|
||||
<value>Item update failed</value>
|
||||
</data>
|
||||
<data name="msg.error.system" xml:space="preserve">
|
||||
<value>System error encountered.</value>
|
||||
</data>
|
||||
<data name="msg.item.created" xml:space="preserve">
|
||||
<value>Item has been created.</value>
|
||||
</data>
|
||||
<data name="msg.item.removed" xml:space="preserve">
|
||||
<value>Item has been removed.</value>
|
||||
</data>
|
||||
<data name="msg.item.updated" xml:space="preserve">
|
||||
<value>Item has been updated.</value>
|
||||
</data>
|
||||
<data name="msg.organisation.request.success" xml:space="preserve">
|
||||
<value>Thank you for registering your organisation.
|
||||
You will be contacted by email once the details have been confirmed.
|
||||
You will then be able to publicise your sporting activities.</value>
|
||||
</data>
|
||||
<data name="msg.something.gone.wrong" xml:space="preserve">
|
||||
<value>Unfortunately, something has gone wrong.\n\nYou will be returned to the home page.</value>
|
||||
</data>
|
||||
<data name="msg.upload.file.select" xml:space="preserve">
|
||||
<value>Please select a file to upload.</value>
|
||||
</data>
|
||||
<data name="msg.upload.file.size.max" xml:space="preserve">
|
||||
<value>Maximum image file size is {0}.</value>
|
||||
</data>
|
||||
<data name="msg.upload.file.type.invalid" xml:space="preserve">
|
||||
<value>Unsupported file type: {0}.</value>
|
||||
</data>
|
||||
<data name="msg.upload.file.uploading" xml:space="preserve">
|
||||
<value>Uploading {0}.</value>
|
||||
</data>
|
||||
<data name="msg.upload.image.invalid" xml:space="preserve">
|
||||
<value>Invalid image file uploaded</value>
|
||||
</data>
|
||||
<data name="msg.upload.image.invalid.content.type" xml:space="preserve">
|
||||
<value>Invalid image content type.</value>
|
||||
</data>
|
||||
<data name="msg.upload.image.invalid.mime" xml:space="preserve">
|
||||
<value>Invalid image mime type.</value>
|
||||
</data>
|
||||
<data name="msg.upload.image.resize.failed" xml:space="preserve">
|
||||
<value>Image resize failed.</value>
|
||||
</data>
|
||||
<data name="msg.upload.image.single" xml:space="preserve">
|
||||
<value>Only one image can be uploaded.</value>
|
||||
</data>
|
||||
<data name="msg.validation.duplicate.value" xml:space="preserve">
|
||||
<value>Value is already in use</value>
|
||||
</data>
|
||||
<data name="msg.validation.invalid.length" xml:space="preserve">
|
||||
<value>Value must be {0} characters</value>
|
||||
</data>
|
||||
<data name="msg.validation.invalid.value" xml:space="preserve">
|
||||
<value>Invalid value</value>
|
||||
</data>
|
||||
<data name="msg.validation.mandatory.value" xml:space="preserve">
|
||||
<value>Mandatory value</value>
|
||||
</data>
|
||||
<data name="msg.validation.maximum.length" xml:space="preserve">
|
||||
<value>Value must not exceed {0} characters</value>
|
||||
</data>
|
||||
<data name="msg.warn.password.invalid" xml:space="preserve">
|
||||
<value>Password must be a minimum of {0} characters with upper and lower case letters, at least one number and special character unless at least {1} characters long.</value>
|
||||
</data>
|
||||
<data name="organisation.caption.event" xml:space="preserve">
|
||||
<value>Event</value>
|
||||
</data>
|
||||
<data name="organisation.caption.event.create" xml:space="preserve">
|
||||
<value>Create Event</value>
|
||||
</data>
|
||||
<data name="organisation.caption.event.update" xml:space="preserve">
|
||||
<value>Update event</value>
|
||||
</data>
|
||||
<data name="organisation.caption.events" xml:space="preserve">
|
||||
<value>Events</value>
|
||||
</data>
|
||||
<data name="organisation.caption.opportunities" xml:space="preserve">
|
||||
<value>Organisation Opportunities</value>
|
||||
</data>
|
||||
<data name="organisation.caption.opportunity" xml:space="preserve">
|
||||
<value>Organisation Opportunity</value>
|
||||
</data>
|
||||
<data name="organisation.caption.opportunity.create" xml:space="preserve">
|
||||
<value>Create Opportunity</value>
|
||||
</data>
|
||||
<data name="organisation.caption.opportunity.update" xml:space="preserve">
|
||||
<value>Update Opportunity</value>
|
||||
</data>
|
||||
<data name="organisation.caption.organisation.request" xml:space="preserve">
|
||||
<value>Request Organisation</value>
|
||||
</data>
|
||||
<data name="organisation.caption.organisation.select" xml:space="preserve">
|
||||
<value>Select Organisation</value>
|
||||
</data>
|
||||
<data name="organisation.caption.organisations" xml:space="preserve">
|
||||
<value>Organisations</value>
|
||||
</data>
|
||||
<data name="organisation.member.remove" xml:space="preserve">
|
||||
<value>Remove Member</value>
|
||||
</data>
|
||||
<data name="organisation.member.remove.confirm" xml:space="preserve">
|
||||
<value>Are you sure that this member should be removed from the organisation?</value>
|
||||
</data>
|
||||
<data name="organisation.member.select.roles" xml:space="preserve">
|
||||
<value>Member Roles</value>
|
||||
</data>
|
||||
<data name="organisation.members" xml:space="preserve">
|
||||
<value>Organisation Members</value>
|
||||
</data>
|
||||
<data name="organisation.members.msg.remove.own.admin.role" xml:space="preserve">
|
||||
<value>You cannot remove your own 'Member Admin' role.</value>
|
||||
</data>
|
||||
<data name="policies.caption.privacy" xml:space="preserve">
|
||||
<value>Privacy</value>
|
||||
</data>
|
||||
<data name="policies.caption.privacy.policy" xml:space="preserve">
|
||||
<value>Privacy Policy</value>
|
||||
</data>
|
||||
<data name="reference.caption.country.select" xml:space="preserve">
|
||||
<value>Select Country</value>
|
||||
</data>
|
||||
<data name="reference.caption.province.select" xml:space="preserve">
|
||||
<value>Select Province</value>
|
||||
</data>
|
||||
<data name="reference.caption.region.select" xml:space="preserve">
|
||||
<value>Select Region</value>
|
||||
</data>
|
||||
<data name="reference.caption.regions" xml:space="preserve">
|
||||
<value>Regions</value>
|
||||
</data>
|
||||
<data name="reference.caption.sport.select" xml:space="preserve">
|
||||
<value>Select Sport</value>
|
||||
</data>
|
||||
<data name="security.caption.change.password" xml:space="preserve">
|
||||
<value>Change Password</value>
|
||||
</data>
|
||||
<data name="security.caption.request.password" xml:space="preserve">
|
||||
<value>Request Password</value>
|
||||
</data>
|
||||
<data name="security.caption.signin" xml:space="preserve">
|
||||
<value>Sign-in</value>
|
||||
</data>
|
||||
<data name="security.caption.signout" xml:space="preserve">
|
||||
<value>Sign-out</value>
|
||||
</data>
|
||||
<data name="security.change.password.current.invalid" xml:space="preserve">
|
||||
<value>Current password does not match.</value>
|
||||
</data>
|
||||
<data name="security.change.password.not.changed" xml:space="preserve">
|
||||
<value>Your new password must be different from the previous.</value>
|
||||
</data>
|
||||
<data name="security.msg.change.password.failed" xml:space="preserve">
|
||||
<value>Failed to change password.</value>
|
||||
</data>
|
||||
<data name="security.msg.request.password.email.sent" xml:space="preserve">
|
||||
<value>If your email address matches an active user account, you will shortly receive an email with instructions for changing your password.</value>
|
||||
</data>
|
||||
<data name="security.msg.request.password.saved" xml:space="preserve">
|
||||
<value>Password has been updated</value>
|
||||
</data>
|
||||
<data name="security.msg.signin.invalid" xml:space="preserve">
|
||||
<value>Incorrect account credentials entered.</value>
|
||||
</data>
|
||||
<data name="security.msg.signout.confirm" xml:space="preserve">
|
||||
<value>Are you sure that you want to sign-out?</value>
|
||||
</data>
|
||||
<data name="security.msg.warn.sessionExpired" xml:space="preserve">
|
||||
<value>Your session has expired.</value>
|
||||
</data>
|
||||
<data name="support.caption.user.report" xml:space="preserve">
|
||||
<value>User Report</value>
|
||||
</data>
|
||||
<data name="support.caption.user.reports" xml:space="preserve">
|
||||
<value>User Reports</value>
|
||||
</data>
|
||||
</root>
|
||||
@@ -0,0 +1,43 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore;
|
||||
using Microsoft.AspNetCore.Hosting;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.Hosting;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace Saxonite.Net.Core.Web.Online.App
|
||||
{
|
||||
//=======================================================================
|
||||
public class Program
|
||||
{
|
||||
//-------------------------------------------------------------------
|
||||
public static void Main(string[] args)
|
||||
{
|
||||
try
|
||||
{
|
||||
CreateHostBuilder(args).Build().Run();
|
||||
}
|
||||
finally
|
||||
{
|
||||
// Cleanup - globals, async processes etc.
|
||||
if (SaxApplication_Online.AppInstance != null)
|
||||
SaxApplication_Online.AppInstance.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
public static IHostBuilder CreateHostBuilder(string[] args) =>
|
||||
Host.CreateDefaultBuilder(args)
|
||||
.ConfigureWebHostDefaults(webBuilder =>
|
||||
{
|
||||
webBuilder.UseStartup<SaxStartup_Online>();
|
||||
});
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
}
|
||||
//=======================================================================
|
||||
}
|
||||
@@ -0,0 +1,145 @@
|
||||
using Microsoft.AspNetCore.Hosting;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Sarand.Net.Standard.Dbas.Base;
|
||||
using Sarand.Net.Standard.Dbas.Data;
|
||||
using Sarand.Net.Standard.Base.Core;
|
||||
using Sarand.Net.Standard.Base.Dbas;
|
||||
using Sarand.Net.Standard.Base.Email;
|
||||
using Sarand.Net.Standard.Base.IO;
|
||||
using Saxonite.Net.Standard.Base.App;
|
||||
using Saxonite.Net.Standard.Base.Consoles;
|
||||
using Saxonite.Net.Core.Web.Online.Consoles;
|
||||
using Saxonite.Net.Core.Web.Base.App;
|
||||
using Saxonite.Net.Core.Web.Base.Helpers;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Saxonite.Net.Standard.Dbas.App;
|
||||
using Microsoft.Extensions.Hosting;
|
||||
using Sarand.Net.Standard.Base.App;
|
||||
using Sarand.Net.Standard.Base.Utils;
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
namespace Saxonite.Net.Core.Web.Online.App
|
||||
{
|
||||
//=======================================================================
|
||||
public class SaxApplication_Online : SaxApplication_Web
|
||||
{
|
||||
//-------------------------------------------------------------------
|
||||
// Data members.
|
||||
private Dictionary<String, SaxAppConfig> appConfigs = new Dictionary<string, SaxAppConfig>();
|
||||
private Dictionary<String, SaxEmailConfig> emailConfigs = new Dictionary<string, SaxEmailConfig>();
|
||||
// Session contexts.
|
||||
protected class SessionContextData_Online : SessionContextData_Web
|
||||
{
|
||||
public SessionContextData_Online(SaxSessionContext_Web sessionContext) : base(sessionContext) { }
|
||||
}
|
||||
private readonly Dictionary<int, SessionContextData_Online> sessionContexts = new Dictionary<int, SessionContextData_Online>();
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Construction.
|
||||
public SaxApplication_Online(IConfiguration configuration) : base(Sax.Application.Online)
|
||||
{
|
||||
InitialiseTemporaryLoggingFolder();
|
||||
try
|
||||
{
|
||||
AppInstance = this;
|
||||
Configuration = configuration;
|
||||
ConsoleHelper_Online = new SaxConsoleHelper_Online(this);
|
||||
}
|
||||
catch (Exception exc)
|
||||
{
|
||||
SaLogger.Error($"{GetType().Name}.CTR {ExceptionUtil.GetErrorStateMessage(exc)}");
|
||||
throw;
|
||||
}
|
||||
}
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing)
|
||||
{
|
||||
// Clear globals.
|
||||
AppInstance = null;
|
||||
// Console helper.
|
||||
if (ConsoleHelper_Online != null)
|
||||
ConsoleHelper_Online.Dispose();
|
||||
ConsoleHelper_Online = null;
|
||||
}
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Globals.
|
||||
public static SaxApplication_Online AppInstance { get; private set; }
|
||||
public override SaxConsoleHelper ConsoleHelper { get { return ConsoleHelper_Online; } }
|
||||
public SaxConsoleHelper_Online ConsoleHelper_Online { get; private set; }
|
||||
// Database.
|
||||
public override ISacsDatabase GetDatabase(SaxSessionContext sessionContext, Sax.Database databaseType)
|
||||
{
|
||||
return sessionContexts.GetValue(sessionContext.Index, null)?.Databases.GetValue(databaseType, null) ?? null;
|
||||
}
|
||||
// Configuration.
|
||||
public override SaxAppConfig AppConfig { get { return appConfigs.Values.ToList().getConfigForApplication(); } }
|
||||
public override SaxEmailConfig EmailConfig { get { return emailConfigs.Values.ToList().getConfigForSession(AppConfig); } }
|
||||
public override String SessionCookieName { get { return Sax.Config.Online.Session.Cookie.Name; } }
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Initialisation.
|
||||
/// <summary>Initialise environment - from Startup.</summary>
|
||||
internal void InitWebHostEnvironment(IWebHostEnvironment env)
|
||||
{
|
||||
InitEnvironment(env);
|
||||
}
|
||||
/// <summary>Initialise environment - from internal (above) or unit tests.</summary>
|
||||
protected void InitEnvironment(IWebHostEnvironment env)
|
||||
{
|
||||
base.InitEnvironment(env, "Sax-Web-Onl");
|
||||
|
||||
try
|
||||
{
|
||||
// Application configuration.
|
||||
appConfigs = SaxAppConfigHelper.ExtractAppConfigs(SaxConfiguration.GetSection("AppConfigs"));
|
||||
emailConfigs = SaxEmailConfigHelper.ExtractEmailConfigs(SaxConfiguration.GetSection("EmailConfigs"));
|
||||
|
||||
// Ensure root log folder ends with 'Online' folder.
|
||||
LoggingRootFolder = AppConfig.Logging.RootFolder;
|
||||
if (!StringUtil.IsBlank(LoggingRootFolder) && !Regex.IsMatch(LoggingRootFolder, "[\\\\/]Online$", RegexOptions.IgnoreCase))
|
||||
LoggingRootFolder = StringUtil.CombineFilePath(LoggingRootFolder, "Online");
|
||||
|
||||
// Application instance.
|
||||
if (AppConfig.Instance.EqualsCI("Dev")) instanceType = Sax.InstanceType.Dev;
|
||||
else if (AppConfig.Instance.ContainsCI("Q")) instanceType = Sax.InstanceType.QC;
|
||||
else if (AppConfig.Instance.ContainsCI("UAT")) instanceType = Sax.InstanceType.UAT;
|
||||
else if (AppConfig.Instance.EqualsCI("PreProd")) instanceType = Sax.InstanceType.UAT;
|
||||
|
||||
// Initialise hard-coded logging path.
|
||||
if (StringUtil.IsEmpty(LoggingRootFolder))
|
||||
{
|
||||
if (SaxSystem.ComputerName.EqualsCI("WIN-BPCLM1QUOMT"))
|
||||
LoggingRootFolder = @"D:\Saxonite\Logs\" + (Development ? "Dev" : "Test");
|
||||
}
|
||||
if (DirectoryUtil.DirectoryExists(LoggingRootFolder))
|
||||
SaLogger.LogFolder = LoggingRootFolder;
|
||||
LogApplicationStart(SysUtil.Fn);
|
||||
|
||||
// Session context - only one context available/necessary (for now).
|
||||
SessionContextData_Online sessionContextData = new SessionContextData_Online(new SaxSessionContext_Web(100, ApplicationType));
|
||||
ConfigureDatabaseConnection(sessionContextData, Sax.Database.Core);
|
||||
ConfigureDatabaseConnection(sessionContextData, Sax.Database.Reference);
|
||||
ConfigureDatabaseConnection(sessionContextData, Sax.Database.Support);
|
||||
sessionContexts.Add(sessionContextData.SessionContext.Index, sessionContextData);
|
||||
SessionContext = sessionContextData.SessionContext;
|
||||
|
||||
// Data Cache console - to initialise refresh. Must be done for every Session Context.
|
||||
SaxDataCacheConsole dataCacheConsole = SaxGlobals.ConsoleHelper.GetDataCacheConsole(SessionContext);
|
||||
}
|
||||
catch (Exception exc)
|
||||
{
|
||||
SaLogger.Error(SysUtil.Fn + " " + ExceptionUtil.GetLogMessage(exc));
|
||||
}
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
}
|
||||
//=======================================================================
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
using Microsoft.AspNetCore.Html;
|
||||
using Microsoft.AspNetCore.Mvc.Localization;
|
||||
using Microsoft.Extensions.Localization;
|
||||
using Saxonite.Net.Core.Web.Base.App;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Resources;
|
||||
using System.Web;
|
||||
|
||||
namespace Saxonite.Net.Core.Web
|
||||
{
|
||||
// <summary>
|
||||
/// Dummy classes to group shared resources - named as per '.resx' file in root namespace.
|
||||
/// <para>Required to create the IStringLocalizer instance using the type from the class.</para>
|
||||
/// <para>Name of the class is used as the prefix for localisation filenames.</para>
|
||||
/// <para>Resource files are in the Localization ResourcesPath in Startup.cs.</para>
|
||||
/// </summary>
|
||||
public class SaxOnlineProperties { }
|
||||
// Class must be in Root/Default Namespace to reference properties with same name.
|
||||
// NB 'Assembly name' must be the same as 'Default Namespace' until 'Root Namespace' can be set (.Net Core 2.1?).
|
||||
// Ref. Project Properties - Application.
|
||||
}
|
||||
|
||||
namespace Saxonite.Net.Core.Web.Online.App
|
||||
{
|
||||
//=======================================================================
|
||||
public class SaxLocaliser_Online : SaxLocaliser
|
||||
{
|
||||
//-------------------------------------------------------------------
|
||||
// Data members.
|
||||
private readonly IStringLocalizer<SaxOnlineProperties> webAppProperties;
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
/// <summary>
|
||||
/// Localisers are supplied using construction injection.
|
||||
/// </summary>
|
||||
public SaxLocaliser_Online(IStringLocalizer<SaxOnlineProperties> webAppProperties)
|
||||
{
|
||||
this.webAppProperties = webAppProperties;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Properties.
|
||||
public override IStringLocalizer MainProperties { get { return webAppProperties; } }
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
}
|
||||
//=======================================================================
|
||||
}
|
||||
@@ -0,0 +1,189 @@
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using Sarand.Net.Standard.Base.App;
|
||||
using Sarand.Net.Standard.Base.Bus;
|
||||
using Sarand.Net.Standard.Base.Core;
|
||||
using Sarand.Net.Standard.Base.Helpers;
|
||||
using Saxonite.Net.Core.Web.Base.App;
|
||||
using Saxonite.Net.Core.Web.Online.Controllers;
|
||||
using Saxonite.Net.Standard.Base.App;
|
||||
using Saxonite.Net.Standard.Base.Bus;
|
||||
using Saxonite.Net.Standard.Base.Data;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Runtime.Serialization;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Saxonite.Net.Core.Web.Online.App
|
||||
{
|
||||
//=======================================================================
|
||||
public class SaxSessionData_Online : SaxSessionData_Web
|
||||
{
|
||||
//-------------------------------------------------------------------
|
||||
// Construction.
|
||||
[JsonConstructor]
|
||||
private SaxSessionData_Online(long sessionIdx, int itemIdx, SaxSessionContext sessionContext) :
|
||||
base(sessionIdx, itemIdx, sessionContext)
|
||||
{ }
|
||||
/// <summary>
|
||||
/// SessionData construction.
|
||||
/// <para>SessionContext and UserAccount must be supplied.</para>
|
||||
/// <para>Organisation is optional.</para>
|
||||
/// </summary>
|
||||
public SaxSessionData_Online(SaxSessionContext sessionContext, SaxUserAccount userAccount, List<SaxUserRole> userRoles) :
|
||||
base(sessionContext, userAccount, userRoles)
|
||||
{
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Contact details.
|
||||
private class UserData_Online : UserData
|
||||
{
|
||||
public UserData_Online(SaxSessionContext sessionContext, SaxUserAccount userAccount, List<SaxUserRole> userRoles) :
|
||||
base(sessionContext, userAccount, userRoles)
|
||||
{ }
|
||||
public UserData_Online(UserData userData) :
|
||||
base(userData)
|
||||
{ }
|
||||
public new bool RefreshUserData(SaxUserAccount userAccount)
|
||||
{
|
||||
return base.RefreshUserData(userAccount);
|
||||
}
|
||||
}
|
||||
protected override UserData CreateUserData(SaxSessionContext sessionContext, SaxUserAccount userAccount, List<SaxUserRole> userRoles) { return new UserData_Online(sessionContext, userAccount, userRoles); }
|
||||
/// <summary>User - JSON deserialisation route.</summary>
|
||||
public new UserData User { get { return base.User; } set { SetUser(new UserData_Online(value)); } }
|
||||
|
||||
/// <summary>
|
||||
/// Update the user's contect details against the session.
|
||||
/// <para>- User Account must match that already against the session.</para>
|
||||
/// </summary>
|
||||
public bool RefreshUser(SaxUserAccount userAccount)
|
||||
{
|
||||
UserData_Online user = User as UserData_Online;
|
||||
if (user != null)
|
||||
return user.RefreshUserData(userAccount);
|
||||
return false;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// User Config - user's application settings.
|
||||
public class UserConfigData
|
||||
{
|
||||
/// <summary>Online Profile Config data.</summary>
|
||||
public SaxConfigData.ProfileData Profile{ get; set; } = new SaxConfigData.ProfileData();
|
||||
}
|
||||
/// <summary>User Configuration.</summary>
|
||||
public UserConfigData UserConfig { get; set; } = new UserConfigData();
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// User Profile.
|
||||
// Protected constructors & setters for JSON deserialisation.
|
||||
public class UserProfileData
|
||||
{
|
||||
public UserProfileData() { }
|
||||
// Sports.
|
||||
public class SportData
|
||||
{
|
||||
[JsonConstructor]
|
||||
public SportData(SysId sportId, SaStatus status)
|
||||
{
|
||||
SportId = sportId;
|
||||
Status = status;
|
||||
}
|
||||
public SysId SportId { get; protected set; }
|
||||
public SaStatus Status { get; protected set; }
|
||||
}
|
||||
private class SportData_Online : SportData
|
||||
{
|
||||
// Internal class to allow values to be updated.
|
||||
public SportData_Online(SysId sportId, SaStatus status) : base(sportId, status) { }
|
||||
public SportData_Online(SportData sportData) : base(sportData.SportId, sportData.Status) { }
|
||||
public void SetSportId(SysId sportId) { SportId = sportId; }
|
||||
public void SetStatus(SaStatus status) { Status = status; }
|
||||
}
|
||||
[JsonIgnore]
|
||||
private readonly List<SportData_Online> sports = new List<SportData_Online>();
|
||||
[JsonIgnore]
|
||||
public int SportCount { get { return sports.Count; } }
|
||||
public List<SportData> Sports { get { return new List<SportData>(sports); } protected set { sports.Clear(); sports.AddRange(value.Select(item => new SportData_Online(item))); } }
|
||||
public void AddSport(SysId sportId, SaStatus status)
|
||||
{
|
||||
if (!SysId.IsValid(sportId)) throw new NotSupportedException("Session Profile Sport must have a valid Id");
|
||||
SportData_Online sport = this.sports.Find(item => item.SportId == sportId);
|
||||
if (sport != null)
|
||||
{
|
||||
sport.SetStatus(status);
|
||||
}
|
||||
else
|
||||
this.sports.Add(new SportData_Online(sportId, status));
|
||||
}
|
||||
public void ClearSports()
|
||||
{
|
||||
this.sports.Clear();
|
||||
}
|
||||
}
|
||||
public UserProfileData Profile { get; protected set; } = new UserProfileData();
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Filter properties.
|
||||
public class FilterData
|
||||
{
|
||||
/// <summary>Id for currently selected Organisation.</summary>
|
||||
public SysId OrganisationId { get; set; }
|
||||
/// <summary>Display text for currently selected Organisation.</summary>
|
||||
public String OrganisationCaption { get; set; }
|
||||
/// <summary>
|
||||
/// Store the properties for the currently selected Organisation.
|
||||
/// </summary>
|
||||
public bool SetOrganisation(SaxOrganisation organisation)
|
||||
{
|
||||
if (organisation == null) return false;
|
||||
if (!organisation.IsStatusActive) return false;
|
||||
OrganisationId = organisation.Id;
|
||||
OrganisationCaption = organisation.Name;
|
||||
return true;
|
||||
}
|
||||
/// <summary>Id for currently selected Organisation of which the user is a member.</summary>
|
||||
public SysId OrganisationIdMember { get; set; }
|
||||
/// <summary>Display text for currently selected Organisation of which the user is a member.</summary>
|
||||
public String OrganisationCaptionMember { get; set; }
|
||||
/// <summary>
|
||||
/// Store the properties for the currently selected Organisation for which the User is a member.
|
||||
/// </summary>
|
||||
public bool SetMemberOrganisation(SaxOrganisation organisation)
|
||||
{
|
||||
if (organisation == null) return false;
|
||||
if (!organisation.IsStatusActive) return false;
|
||||
OrganisationIdMember = organisation.Id;
|
||||
OrganisationCaptionMember = organisation.Name;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
public FilterData Filter { get; private set; } = new FilterData();
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
//-------------------------------------------------------------------
|
||||
// JSON Deserialisation.
|
||||
[JsonExtensionData]
|
||||
#pragma warning disable IDE0044 // Add readonly modifier
|
||||
private IDictionary<string, JToken> _additionalData = null;
|
||||
#pragma warning restore IDE0044 // Add readonly modifier
|
||||
[OnDeserialized]
|
||||
private void OnDeserialized(StreamingContext context)
|
||||
{
|
||||
if (_additionalData != null)
|
||||
{
|
||||
foreach (String name in _additionalData.Keys)
|
||||
{
|
||||
JToken value = _additionalData[name];
|
||||
SaLogger.Info("OnDeserialized Name: " + name + ". Value: " + value.ToString());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
}
|
||||
//=======================================================================
|
||||
}
|
||||
@@ -0,0 +1,81 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Net.Http;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Builder;
|
||||
using Microsoft.AspNetCore.Hosting;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.HttpsPolicy;
|
||||
using Microsoft.AspNetCore.Localization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.AspNetCore.Mvc.Razor;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Net.Http.Headers;
|
||||
using Saxonite.Net.Standard.Base.App;
|
||||
using Saxonite.Net.Core.Web.Base.Middleware;
|
||||
using Microsoft.AspNetCore.Internal;
|
||||
using Saxonite.Net.Core.Web.Base.App;
|
||||
using Microsoft.Extensions.Hosting;
|
||||
using Sarand.Net.Standard.Base.Core;
|
||||
|
||||
namespace Saxonite.Net.Core.Web.Online.App
|
||||
{
|
||||
//=======================================================================
|
||||
public class SaxStartup_Online : SaxStartup
|
||||
{
|
||||
//-------------------------------------------------------------------
|
||||
// Data members.
|
||||
private SaxApplication_Online application = null;
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Construction.
|
||||
public SaxStartup_Online(IConfiguration configuration) : base(configuration)
|
||||
{
|
||||
// Initialise application.
|
||||
application = new SaxApplication_Online(Configuration);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// This method gets called by the runtime. Use this method to add services to the container.
|
||||
public void ConfigureServices(IServiceCollection services)
|
||||
{
|
||||
// Common configuration.
|
||||
ConfigureServicesConfig configureServicesConfig = new ConfigureServicesConfig();
|
||||
configureServicesConfig.services = services;
|
||||
configureServicesConfig.sessionCookieName = Sax.Config.Online.Session.Cookie.Name;
|
||||
configureServicesConfig.sessionCookieHttpOnly = Sax.Config.Online.Session.Cookie.HttpOnly;
|
||||
configureServicesConfig.sessionIdleTimeout = Sax.Config.Online.Session.Cookie.IdleTimeout;
|
||||
ConfigureServices(configureServicesConfig);
|
||||
|
||||
// Application localisation.
|
||||
services.AddSingleton<SaxLocaliser, SaxLocaliser_Online>();
|
||||
|
||||
services.Configure<CookiePolicyOptions>(options =>
|
||||
{
|
||||
// This lambda determines whether user consent for non-essential cookies is needed for a given request.
|
||||
options.CheckConsentNeeded = context => true;
|
||||
options.MinimumSameSitePolicy = Microsoft.AspNetCore.Http.SameSiteMode.None;
|
||||
});
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
|
||||
public void Configure(IApplicationBuilder app, IHostApplicationLifetime hostApplicationLifetime, IWebHostEnvironment env)
|
||||
{
|
||||
application.InitWebHostEnvironment(env);
|
||||
|
||||
// Common configuration.
|
||||
ConfigureConfig configureConfig = new ConfigureConfig();
|
||||
configureConfig.app = app;
|
||||
configureConfig.hostApplicationLifetime = hostApplicationLifetime;
|
||||
configureConfig.env = env;
|
||||
Configure(configureConfig);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
}
|
||||
//=======================================================================
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
using Sarand.Net.Standard.Base.App;
|
||||
using Saxonite.Net.Core.Web.Base.Consoles;
|
||||
using Saxonite.Net.Standard.Base.App;
|
||||
using Saxonite.Net.Standard.Base.Consoles;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace Saxonite.Net.Core.Web.Online.Consoles
|
||||
{
|
||||
//=======================================================================
|
||||
public class SaxActivityConsole_Online : SaxActivityConsole_Web
|
||||
{
|
||||
//-------------------------------------------------------------------
|
||||
// Data members.
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
public SaxActivityConsole_Online(SaxSessionContext sessionContext) :
|
||||
base(sessionContext)
|
||||
{
|
||||
String fn = GetType().Name + ".CTR";
|
||||
SaLogger.Info(fn + "");
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Utilities.
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
}
|
||||
//=======================================================================
|
||||
}
|
||||
@@ -0,0 +1,88 @@
|
||||
using Sarand.Net.Standard.Base.Utils;
|
||||
using Saxonite.Net.Core.Web.Base.Consoles;
|
||||
using Saxonite.Net.Core.Web.Online.App;
|
||||
using Saxonite.Net.Standard.Base.App;
|
||||
using Saxonite.Net.Standard.Base.Consoles;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Saxonite.Net.Core.Web.Online.Consoles
|
||||
{
|
||||
//=======================================================================
|
||||
public class SaxConsoleHelper_Online : SaxConsoleHelper_Web
|
||||
{
|
||||
//-------------------------------------------------------------------
|
||||
// Data members.
|
||||
private readonly SaxApplication_Online app;
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// construction.
|
||||
public SaxConsoleHelper_Online(SaxApplication_Online app)
|
||||
{
|
||||
this.app = app;
|
||||
}
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing)
|
||||
{
|
||||
// Data cache consoles.
|
||||
foreach (SaxDataCacheConsole_Online dataCacheConsole in dataCacheConsoles.Values)
|
||||
dataCacheConsole.Dispose();
|
||||
dataCacheConsoles.Clear();
|
||||
// Session data consoles.
|
||||
foreach (SaxSessionDataConsole_Online sessionDataConsole in sessionDataConsoles.Values)
|
||||
sessionDataConsole.Dispose();
|
||||
sessionDataConsoles.Clear();
|
||||
}
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Data cache console.
|
||||
private readonly Dictionary<ushort, SaxDataCacheConsole_Online> dataCacheConsoles = new Dictionary<ushort, SaxDataCacheConsole_Online>();
|
||||
public override SaxDataCacheConsole GetDataCacheConsole(SaxSessionContext sessionContext)
|
||||
{
|
||||
if (sessionContext == null) throw new NotSupportedException($"{SysUtil.Fn} Session Context must be specified.");
|
||||
SaxDataCacheConsole_Online dataCacheConsole = dataCacheConsoles.GetValueOrDefault(sessionContext.Index, null);
|
||||
if (dataCacheConsole == null)
|
||||
{
|
||||
dataCacheConsole = dataCacheConsoles[sessionContext.Index] = new SaxDataCacheConsole_Online(sessionContext);
|
||||
}
|
||||
return dataCacheConsole;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Session Data console.
|
||||
private readonly Dictionary<ushort, SaxSessionDataConsole_Online> sessionDataConsoles = new Dictionary<ushort, SaxSessionDataConsole_Online>();
|
||||
public override SaxSessionDataConsole GetSessionDataConsole(SaxSessionContext sessionContext)
|
||||
{
|
||||
if (sessionContext == null) throw new NotSupportedException($"{SysUtil.Fn} Session Context must be specified.");
|
||||
SaxSessionDataConsole_Online sessionDataConsole = sessionDataConsoles.GetValueOrDefault(sessionContext.Index, null);
|
||||
if (sessionDataConsole == null)
|
||||
{
|
||||
sessionDataConsole = sessionDataConsoles[sessionContext.Index] = new SaxSessionDataConsole_Online(sessionContext);
|
||||
}
|
||||
return sessionDataConsole;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Activity console.
|
||||
public override SaxActivityConsole CreateActivityConsole(SaxSessionContext sessionContext)
|
||||
{
|
||||
return new SaxActivityConsole_Online(sessionContext);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Email console.
|
||||
public override SaxEmailConsole CreateEmailConsole(SaxSessionContext sessionContext)
|
||||
{
|
||||
SaxEmailConsole emailConsole = new SaxEmailConsole_Web(app.EmailConfig);
|
||||
return emailConsole;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
}
|
||||
//=======================================================================
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
using Sarand.Net.Standard.Base.App;
|
||||
using Saxonite.Net.Core.Web.Base.Consoles;
|
||||
using Saxonite.Net.Standard.Base.App;
|
||||
using Saxonite.Net.Standard.Base.Consoles;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace Saxonite.Net.Core.Web.Online.Consoles
|
||||
{
|
||||
//=======================================================================
|
||||
public class SaxDataCacheConsole_Online : SaxDataCacheConsole_Web
|
||||
{
|
||||
//-------------------------------------------------------------------
|
||||
private System.Timers.Timer refreshTimer;
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Construction.
|
||||
public SaxDataCacheConsole_Online(SaxSessionContext sessionContext) :
|
||||
base(sessionContext)
|
||||
{
|
||||
String fn = GetType().Name + ".CTR";
|
||||
RegionsSupported = true;
|
||||
SportsSupported = true;
|
||||
|
||||
// Initialise refresh timer.
|
||||
refreshTimer = new System.Timers.Timer(Math.Max(2, Sax.Config.Online.DataCache.RefreshIntervalSecs.Initial) * 1000);
|
||||
refreshTimer.Elapsed += RefreshTimer_Elapsed;
|
||||
refreshTimer.Start();
|
||||
SaLogger.Info(fn + " Refresh timer initialised. Interval: " + refreshTimer.Interval, true);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Utilities.
|
||||
protected override void ForceRefresh()
|
||||
{
|
||||
String fn = GetType().Name + ".ForceRefresh";
|
||||
SaLogger.Warn(fn + " Refresh timer initialised", true);
|
||||
RefreshData();
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Refresh data cache.
|
||||
private void RefreshTimer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
|
||||
{
|
||||
refreshTimer.Stop();
|
||||
RefreshData();
|
||||
}
|
||||
private void RefreshData()
|
||||
{
|
||||
refreshTimer.Stop();
|
||||
|
||||
if (RegionsSupported) RefreshRegions();
|
||||
if (SportsSupported) RefreshSports();
|
||||
|
||||
refreshTimer.Interval = Math.Max(10, Sax.Config.Online.DataCache.RefreshIntervalSecs.Periodic) * 1000;
|
||||
refreshTimer.Start();
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
}
|
||||
//=======================================================================
|
||||
}
|
||||
@@ -0,0 +1,119 @@
|
||||
using Sarand.Net.Standard.Base.App;
|
||||
using Sarand.Net.Standard.Base.Bus;
|
||||
using Sarand.Net.Standard.Base.Core;
|
||||
using Sarand.Net.Standard.Base.Utils;
|
||||
using Saxonite.Net.Core.Web.Base.Consoles;
|
||||
using Saxonite.Net.Standard.Base.App;
|
||||
using Saxonite.Net.Standard.Base.Bus;
|
||||
using Saxonite.Net.Standard.Base.Consoles;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace Saxonite.Net.Core.Web.Online.Consoles
|
||||
{
|
||||
//=======================================================================
|
||||
public class SaxSessionDataConsole_Online : SaxSessionDataConsole_Web
|
||||
{
|
||||
//-------------------------------------------------------------------
|
||||
// Definitions.
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Data members.
|
||||
private static SaxSessionDataConsole_Online console = null;
|
||||
private System.Timers.Timer commitTimer = null;
|
||||
/// <summary>Latest time that a user was active on the online system - awaiting commit to the database.</summary>
|
||||
private SacsQueueDictionary<SysId, SaxUserOnline.DataProperties> usersActiveAt = new SacsQueueDictionary<SysId, SaxUserOnline.DataProperties>();
|
||||
private DateTime lastDataCommit = DateTime.MinValue;
|
||||
private int commitBatchSize = 32;
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Construction.
|
||||
public SaxSessionDataConsole_Online(SaxSessionContext sessionContext) :
|
||||
base(sessionContext)
|
||||
{
|
||||
String fn = GetType().Name + ".CTR";
|
||||
if (console != null)
|
||||
{
|
||||
SaLogger.Info(fn + " Instance already exists");
|
||||
throw new InvalidOperationException(GetType().Name + " - instance already exists.");
|
||||
}
|
||||
console = this;
|
||||
SaLogger.Info(fn + "");
|
||||
|
||||
// Initilise commit timer.
|
||||
commitTimer = new System.Timers.Timer(Math.Max(2, Sax.Config.Online.DataCache.RefreshIntervalSecs.Initial) * 1000);
|
||||
commitTimer.Elapsed += CommitTimer_Elapsed;
|
||||
commitTimer.Start();
|
||||
}
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing)
|
||||
{
|
||||
if (Object.ReferenceEquals(console, this))
|
||||
console = null;
|
||||
}
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Properties.
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Utilities.
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Record User Online activity.
|
||||
//-------------------------------------------------------------------
|
||||
public override bool RecordUserActive(SysId userAccountId, DateTime activeAt)
|
||||
{
|
||||
if (!SysId.IsValid(userAccountId) || !DateUtil.IsValid(activeAt)) return false;
|
||||
usersActiveAt.SetEntry(userAccountId, new SaxUserOnline.DataProperties() { UserAccountId = userAccountId, OnlineAt = activeAt });
|
||||
return true;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Commit User Online activity.
|
||||
//-------------------------------------------------------------------
|
||||
public override DateTime LastDataCommit()
|
||||
{
|
||||
lock (usersActiveAt)
|
||||
return lastDataCommit;
|
||||
}
|
||||
private void CommitTimer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
|
||||
{
|
||||
commitTimer.Stop();
|
||||
CommitData();
|
||||
}
|
||||
private void CommitData()
|
||||
{
|
||||
String fn = GetType().Name + ".CommitData";
|
||||
commitTimer.Stop();
|
||||
|
||||
// Extract data to be committed.
|
||||
List<KeyValuePair<SysId, SaxUserOnline.DataProperties>> usersActiveAtToCommit = usersActiveAt.RemoveTopEntries(commitBatchSize);
|
||||
|
||||
// Reset the timer.
|
||||
int intervalSecs = Sax.Config.Online.Session.DataCommit.IntervalSecs.NoDataWaiting;
|
||||
if (usersActiveAt.Count > 0)
|
||||
{
|
||||
// Additional Data is waiting to be committed.
|
||||
intervalSecs = Sax.Config.Online.Session.DataCommit.IntervalSecs.DataWaiting;
|
||||
}
|
||||
commitTimer.Interval = Math.Max(1, intervalSecs) * 1000;
|
||||
commitTimer.Start();
|
||||
|
||||
// Commit the data.
|
||||
if (usersActiveAtToCommit.Count > 0)
|
||||
{
|
||||
if (SacsSystem.DebugMode)
|
||||
SaLogger.Info(fn + " Entries to commit: " + usersActiveAtToCommit.Count);
|
||||
Internals.AccountMgr.CommitUsersOnline(usersActiveAtToCommit.Select(ItemId => ItemId.Value).ToList());
|
||||
}
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
}
|
||||
//=======================================================================
|
||||
}
|
||||
@@ -0,0 +1,426 @@
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Saxonite.Net.Core.Web.Online.Models;
|
||||
using Saxonite.Net.Core.Web.Base.App;
|
||||
using Saxonite.Net.Core.Web.Base.Controllers;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Saxonite.Net.Standard.Base.Bus;
|
||||
using Sarand.Net.Standard.Base.App;
|
||||
using Sarand.Net.Standard.Base.Bus;
|
||||
using Sarand.Net.Standard.Base.Utils;
|
||||
using Saxonite.Net.Standard.Base.App;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Sarand.Net.Standard.Base.Helpers;
|
||||
using System.IO;
|
||||
using System.Drawing;
|
||||
using Sarand.Net.Standard.Base.Core;
|
||||
using Saxonite.Net.Standard.Base.Data;
|
||||
using static Saxonite.Net.Standard.Base.App.Sax.Config;
|
||||
|
||||
namespace Saxonite.Net.Core.Web.Online.Controllers
|
||||
{
|
||||
//=======================================================================
|
||||
// Online Account Controller - Contact - Ajax actions.
|
||||
//=======================================================================
|
||||
partial class AccountController
|
||||
{
|
||||
//-------------------------------------------------------------------
|
||||
// Common response data.
|
||||
private class ContactResponseData
|
||||
{
|
||||
public String EmailAddress { get; set; }
|
||||
public String DisplayName { get; set; }
|
||||
public String Title { get; set; }
|
||||
public String FirstName { get; set; }
|
||||
public String LastName { get; set; }
|
||||
public String About { get; set; }
|
||||
public byte Gender { get; set; }
|
||||
public String GenderCaption { get; set; }
|
||||
public byte DobDay { get; set; }
|
||||
public byte DobMonth { get; set; }
|
||||
public short DobYear { get; set; }
|
||||
public bool? HasImage { get; set; } = null;
|
||||
// Regions.
|
||||
public String RegionIdCountry { get; set; }
|
||||
public String RegionCaptionCountry { get; set; }
|
||||
public String RegionIdProvince { get; set; }
|
||||
public String RegionCaptionProvince { get; set; }
|
||||
public String LocationCaption { get; set; }
|
||||
}
|
||||
private void PopulateContactResponseData(SaxModel_Online model, ContactResponseData data, SaxUserAccount userAccount)
|
||||
{
|
||||
data.EmailAddress = userAccount.EmailAddress;
|
||||
data.DisplayName = userAccount.GetDisplayName();
|
||||
data.Title = userAccount.Title;
|
||||
data.FirstName = userAccount.FirstName;
|
||||
data.LastName = userAccount.LastName;
|
||||
data.About = userAccount.About;
|
||||
data.Gender = (byte)userAccount.Gender;
|
||||
data.GenderCaption = Localiser.GetGenderCaption(userAccount.Gender);
|
||||
data.DobDay = (byte)(userAccount.DateOfBirthDay ?? 0);
|
||||
data.DobMonth = (byte)(userAccount.DateOfBirthMonth ?? 0);
|
||||
data.DobYear = (short)(userAccount.DateOfBirthYear ?? 0);
|
||||
if (ItemDataMgr.ItemHasActiveImage(userAccount.GetItemId(), Sax.ImageType.Avatar))
|
||||
data.HasImage = true;
|
||||
// Regions.
|
||||
data.RegionIdCountry = model.GetEncryptedRegionId(userAccount.RegionIdCountry);
|
||||
data.RegionIdProvince = model.GetEncryptedRegionId(userAccount.RegionIdProvince);
|
||||
data.RegionCaptionCountry = Localiser.GetRegionName(Internals.GetRegion(userAccount.RegionIdCountry));
|
||||
data.RegionCaptionProvince = Localiser.GetRegionName(Internals.GetRegion(userAccount.RegionIdProvince));
|
||||
List<String> locations = new List<string>() { data.RegionCaptionProvince, data.RegionCaptionCountry };
|
||||
data.LocationCaption = locations.Concat(", ", "", "", true, true);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Utilites.
|
||||
private ItemId GetUserItemId(SysId userAccountId)
|
||||
{
|
||||
return new ItemId((short)Sax.DataItemType.UserAccount, userAccountId);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Account - Get Contact Details.
|
||||
//-------------------------------------------------------------------
|
||||
private class AjaxResponse_AccountContactData : AjaxResponse_Data
|
||||
{
|
||||
// Construction.
|
||||
public AjaxResponse_AccountContactData(SaxModel_Online model) : base(model) { }
|
||||
// Contact details.
|
||||
public ContactResponseData Contact { get; set; }
|
||||
// Reference data.
|
||||
public List<CodeDesc> Genders { get; } = new List<CodeDesc>();
|
||||
public List<CodeDesc> Months { get; } = new List<CodeDesc>();
|
||||
public List<String> ImageContentTypes { get; set; }
|
||||
}
|
||||
// Ajax request.
|
||||
[HttpPost]
|
||||
[Route("Account/Ajax/GetProfileContact")]
|
||||
public IActionResult GetProfileContact(Model_Account model)
|
||||
{
|
||||
String fn = GetType().Name + ".GetProfileContact";
|
||||
AjaxResponse_AccountContactData responseData = new AjaxResponse_AccountContactData(model);
|
||||
String messageTitle = Localiser["account.caption.profile.contact"];
|
||||
|
||||
// Validate session and referrer.
|
||||
if (!ValidReferer) return Forbid();
|
||||
if (!ValidUserSession) return GetAjaxResult_InvalidSession(responseData);
|
||||
RefreshModel(model);
|
||||
|
||||
// Record disposable items as they are created so all can be disposed when needed.
|
||||
using (DisposableCollection<IDisposable> disposableItems = new DisposableCollection<IDisposable>())
|
||||
{
|
||||
|
||||
// Reference data - Genders.
|
||||
responseData.Genders.Add("", Localiser["label.not.specified"]);
|
||||
foreach (TypeCodeDesc gender in Internals.GenderCodes)
|
||||
responseData.Genders.Add(gender.Type.ToString(), Localiser.GetGenderCaption((Sax.Gender)gender.Type));
|
||||
|
||||
// Reference data - Months.
|
||||
for (int month = 1; month <= 12; month++)
|
||||
responseData.Months.Add(month.ToString(), DateUtil.Format(new DateTime(DateTime.Today.Year, month, 1), "MMMM", SessionCulture));
|
||||
|
||||
// Reference data - Image content types.
|
||||
responseData.ImageContentTypes = SaxItemImage.GetValidContentTypes(Sax.DataItemType.UserAccount);
|
||||
|
||||
// Retrieve user details.
|
||||
SaxUserAccount userAccount = AccountMgr.GetUserAccountById(SessionUserAccountId);
|
||||
disposableItems.Add(userAccount);
|
||||
if (userAccount == null)
|
||||
{
|
||||
SaLogger.Warn(fn + " Failed to retrieve user account for Id: " + SysId.ToString(SessionUserAccountId));
|
||||
return Json(responseData.SetGoHome(messageTitle, Localiser["msg.something.gone.wrong"]));
|
||||
}
|
||||
|
||||
// Logically delete any previous 'Uploaded' Avatar image.
|
||||
ItemId userItemId = userAccount.GetItemId();
|
||||
SaxItemImage itemImageAvatarUploaded = ItemDataMgr.GetItemImage(userItemId, Sax.ImageType.Avatar_Upload, SaxItemImage.StatusCat.ActiveOnly);
|
||||
disposableItems.Add(itemImageAvatarUploaded);
|
||||
if (itemImageAvatarUploaded != null)
|
||||
{
|
||||
itemImageAvatarUploaded.Status = SaStatus.Deleted;
|
||||
if (!ItemDataMgr.UpdateItemImage(itemImageAvatarUploaded, DbUpdateInfo))
|
||||
SaLogger.Warn(fn + " Failed to logically delete uploaded avatar image - " + ItemDataMgr.ErrorStateMessage);
|
||||
}
|
||||
|
||||
|
||||
// Populate data to response.
|
||||
responseData.Contact = new ContactResponseData();
|
||||
PopulateContactResponseData(model, responseData.Contact, userAccount);
|
||||
}
|
||||
responseData.Success = true;
|
||||
return Json(responseData);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Account - Upload Contact Image.
|
||||
// Ref. http://www.binaryintellect.net/articles/474dc031-087f-4b81-b994-9ca2adb949d6.aspx
|
||||
//-------------------------------------------------------------------
|
||||
private class AjaxResponse_UploadContactImage : AjaxResponse_Data
|
||||
{
|
||||
// Construction.
|
||||
public AjaxResponse_UploadContactImage(SaxModel_Online model) : base(model) { }
|
||||
// Upload message.
|
||||
public String UploadMsg { get; set; }
|
||||
}
|
||||
// Ajax request.
|
||||
[HttpPost]
|
||||
[Route("Account/Ajax/UploadContactImage")]
|
||||
public IActionResult UploadContactImage(Model_Account model)
|
||||
{
|
||||
String fn = GetType().Name + ".UploadContactImage";
|
||||
AjaxResponse_UploadContactImage responseData = new AjaxResponse_UploadContactImage(model);
|
||||
String messageTitle = Localiser["account.caption.profile.contact"];
|
||||
|
||||
// Validate session and referrer.
|
||||
if (!ValidReferer) return Forbid();
|
||||
if (!ValidUserSession) return GetAjaxResult_InvalidSession(responseData);
|
||||
RefreshModel(model);
|
||||
|
||||
// Record disposable items as they are created so all can be disposed when needed.
|
||||
using (DisposableCollection<IDisposable> disposableItems = new DisposableCollection<IDisposable>())
|
||||
{
|
||||
|
||||
// Validate number of images.
|
||||
if (model.AccountContactImage.IsEmpty())
|
||||
{
|
||||
SaLogger.Warn(fn + " No image file supplied for upload");
|
||||
return Json(responseData);
|
||||
}
|
||||
if (model.AccountContactImage.Count != 1)
|
||||
{
|
||||
SaLogger.Warn(fn + " Invalid number of image files uploaded: " + model.AccountContactImage.Count);
|
||||
return Json(responseData.SetControlError("AccountContactImage", Localiser["msg.upload.image.single"]));
|
||||
}
|
||||
IFormFile file = model.AccountContactImage[0];
|
||||
|
||||
// Image properties.
|
||||
byte[] imageData = null;
|
||||
using (MemoryStream fileStream = new MemoryStream())
|
||||
{
|
||||
file.CopyTo(fileStream);
|
||||
imageData = fileStream.ToArray();
|
||||
}
|
||||
|
||||
// Validate content type.
|
||||
if (StringUtil.IsEmpty(file.ContentType) || !SaxItemImage.GetValidContentTypes(Sax.DataItemType.UserAccount).ContainsCI(file.ContentType))
|
||||
return Json(responseData.SetControlError("AccountContactImage", Localiser["msg.upload.image.invalid.content.type"]));
|
||||
Sarand.Net.Standard.Base.Core.Sacs.MimeType mimeTypeExpected = SacsContentTypeHelper.GetMimeTypeFromContentType(file.ContentType);
|
||||
|
||||
// Validate the image.
|
||||
ImageUtils.ImageConfig imageConfig = null;
|
||||
if (mimeTypeExpected == Sarand.Net.Standard.Base.Core.Sacs.MimeType.Svg)
|
||||
imageConfig = ImageUtils.VerifySvgImageData(imageData);
|
||||
else
|
||||
imageConfig = ImageUtils.VerifyImageData(imageData);
|
||||
if (!imageConfig.ValidImage)
|
||||
return Json(responseData.SetControlError("AccountContactImage", Localiser["msg.upload.image.invalid"]));
|
||||
|
||||
// Validate mime type.
|
||||
if (!SaxItemImage.GetValidMimeTypes(Sax.DataItemType.UserAccount).Contains(imageConfig.MimeType))
|
||||
return Json(responseData.SetControlError("AccountContactImage", Localiser["msg.upload.image.invalid.mime"]));
|
||||
if (imageConfig.MimeType != mimeTypeExpected)
|
||||
{
|
||||
SaLogger.Warn($"{SysUtil.Fn} Image upload - inconsistent Mime. Filename: {file.FileName}. Mime: {imageConfig.MimeType}. Expected Mime: {mimeTypeExpected}.");
|
||||
return Json(responseData.SetControlError("OrganisationLogoImage", Localiser["msg.upload.image.invalid"]));
|
||||
}
|
||||
|
||||
// Resize the image if required.
|
||||
if (!ImageUtils.ConstrainImage(imageConfig, Sax.Config.User.Image.WidthMax, Sax.Config.User.Image.HeightMax))
|
||||
return Json(responseData.SetControlError("AccountContactImage", Localiser["msg.upload.image.resize.failed"]));
|
||||
|
||||
// Image belongs to the user's account.
|
||||
ItemId userItemId = GetUserItemId(SessionUserAccountId);
|
||||
|
||||
// Store uploaded image as 'Upload' Avatar - awaiting confirmation that the contact details are to be saved.
|
||||
SaxItemImage itemImage = ItemDataMgr.GetItemImage(userItemId, Sax.ImageType.Avatar_Upload, SaxItemImage.StatusCat.Any);
|
||||
if (itemImage == null)
|
||||
itemImage = ItemDataMgr.CreateItemImage(userItemId, Sax.ImageType.Avatar_Upload);
|
||||
disposableItems.Add(itemImage);
|
||||
itemImage.Filename = file.FileName;
|
||||
itemImage.Mime = SacsContentTypeHelper.GetMimeTypeFromContentType(file.ContentType).ToString().ToLower();
|
||||
itemImage.ContentType = file.ContentType;
|
||||
itemImage.ImageData = imageConfig.ImageData;
|
||||
itemImage.Width = imageConfig.Width;
|
||||
itemImage.Height = imageConfig.Height;
|
||||
itemImage.Status = SaxItemImage.DefaultStatus;
|
||||
|
||||
if (!SysId.IsValid(itemImage.Id))
|
||||
{
|
||||
if (!ItemDataMgr.InsertItemImage(itemImage, DbUpdateInfo))
|
||||
{
|
||||
SaLogger.Warn(fn + " Failed to insert uploaded image - " + ItemDataMgr.ErrorStateMessage);
|
||||
return Json(responseData.SetControlError("AccountContactImage", Localiser["msg.error.item.insert.failed"]));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!ItemDataMgr.UpdateItemImage(itemImage, DbUpdateInfo))
|
||||
{
|
||||
SaLogger.Warn(fn + " Failed to update uploaded image - " + ItemDataMgr.ErrorStateMessage);
|
||||
return Json(responseData.SetControlError("AccountContactImage", Localiser["msg.error.item.insert.failed"]));
|
||||
}
|
||||
}
|
||||
|
||||
// Complete response.
|
||||
//responseData.SetNotifyMessage(messageTitle, "Image uploaded.");
|
||||
}
|
||||
responseData.Success = true;
|
||||
return Json(responseData);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Account - Store Contact Details.
|
||||
//-------------------------------------------------------------------
|
||||
private class AjaxResponse_StoreAccountContactDetails : AjaxResponse_Data
|
||||
{
|
||||
// Construction.
|
||||
public AjaxResponse_StoreAccountContactDetails(SaxModel_Online model) : base(model) { }
|
||||
// Contact details.
|
||||
public ContactResponseData Contact { get; set; }
|
||||
}
|
||||
// Ajax request.
|
||||
[HttpPost]
|
||||
[Route("Account/Ajax/StoreProfileContact")]
|
||||
public IActionResult StoreProfileContact(Model_Account model)
|
||||
{
|
||||
String fn = GetType().Name + ".StoreProfileContact";
|
||||
AjaxResponse_StoreAccountContactDetails responseData = new AjaxResponse_StoreAccountContactDetails(model);
|
||||
String messageTitle = Localiser["account.caption.profile.contact"];
|
||||
|
||||
// Validate session and referrer.
|
||||
if (!ValidReferer) return Forbid();
|
||||
if (!ValidUserSession) return GetAjaxResult_InvalidSession(responseData);
|
||||
RefreshModel(model);
|
||||
|
||||
// Record disposable items as they are created so all can be disposed when needed.
|
||||
using (DisposableCollection<IDisposable> disposableItems = new DisposableCollection<IDisposable>())
|
||||
{
|
||||
|
||||
// Validate data.
|
||||
model.ValidateContactDetails(responseData);
|
||||
if (responseData.HasControlErrors())
|
||||
return Json(responseData);
|
||||
|
||||
// Retrieve user details.
|
||||
SaxUserAccount userAccount = AccountMgr.GetUserAccountById(SessionUserAccountId);
|
||||
disposableItems.Add(userAccount);
|
||||
if (userAccount == null)
|
||||
{
|
||||
SaLogger.Warn(fn + " Failed to retrieve user account for Id: " + SysId.ToString(SessionUserAccountId));
|
||||
return Json(responseData.SetGoHome(messageTitle, Localiser["msg.something.gone.wrong"]));
|
||||
}
|
||||
if (!userAccount.EmailAddress.EqualsCI(SessionData.User.EmailAddress))
|
||||
{
|
||||
SaLogger.Warn(fn + " Unable to update user account '" + userAccount.EmailAddress + ". Email doesn't match session: " + SessionData.User.EmailAddress);
|
||||
return Json(responseData.SetGoHome(messageTitle, Localiser["msg.something.gone.wrong"]));
|
||||
}
|
||||
|
||||
// Populate user properties.
|
||||
userAccount.Changed = false;
|
||||
if (model.AccountTitle != null)
|
||||
userAccount.Title = model.AccountTitle;
|
||||
if (model.AccountFirstName != null)
|
||||
userAccount.FirstName = model.AccountFirstName;
|
||||
if (model.AccountLastName != null)
|
||||
userAccount.LastName = model.AccountLastName;
|
||||
if (model.AccountAbout != null)
|
||||
userAccount.About = model.AccountAbout;
|
||||
if (model.AccountGender != null)
|
||||
userAccount.Gender = model.GetAccountGender();
|
||||
// Date of birth.
|
||||
if (model.AccountDobYear != null)
|
||||
userAccount.DateOfBirthYear = StringUtil.ToShort(model.AccountDobYear);
|
||||
if (userAccount.DateOfBirthYear > 0)
|
||||
{
|
||||
if (model.AccountDobMonth != null)
|
||||
userAccount.DateOfBirthMonth = (byte)StringUtil.ToShort(model.AccountDobMonth);
|
||||
if (userAccount.DateOfBirthMonth > 0)
|
||||
{
|
||||
if (model.AccountDobDay != null)
|
||||
userAccount.DateOfBirthDay = (byte)StringUtil.ToShort(model.AccountDobDay);
|
||||
}
|
||||
else userAccount.DateOfBirthDay = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
userAccount.DateOfBirthMonth = 0;
|
||||
userAccount.DateOfBirthDay = 0;
|
||||
}
|
||||
// Regions.
|
||||
if (model.AccountRegionIdCountry != null)
|
||||
userAccount.RegionIdCountry = model.ExtractSysId(model.AccountRegionIdCountry);
|
||||
if (model.AccountRegionIdProvince != null)
|
||||
userAccount.RegionIdProvince = model.ExtractSysId(model.AccountRegionIdProvince);
|
||||
|
||||
// Update User Account.
|
||||
if (userAccount.Changed) SaLogger.Info(fn + " Updating user account '" + userAccount.EmailAddress + "'. Id: " + SysId.ToString(userAccount.Id), true);
|
||||
if (AccountMgr.UpdateUserAccount(userAccount, DbUpdateInfo))
|
||||
{
|
||||
// ToDo Refresh Session with updated organisation details.
|
||||
}
|
||||
else
|
||||
{
|
||||
SaLogger.Warn(fn + " Failed to update user account '" + userAccount.EmailAddress + "': " + AccountMgr.ErrorStateMessage);
|
||||
return Json(responseData.SetPopupMessage(messageTitle, Localiser["msg.error.item.update.failed"]));
|
||||
}
|
||||
|
||||
// Refresh profile contact details to session.
|
||||
RefreshSessionProfileContact(userAccount);
|
||||
|
||||
// Check for uploaded profile image.
|
||||
ItemId userItemId = userAccount.GetItemId();
|
||||
SaxItemImage itemImageAvatarUploaded = ItemDataMgr.GetItemImage(userItemId, Sax.ImageType.Avatar_Upload, SaxItemImage.StatusCat.ActiveOnly);
|
||||
disposableItems.Add(itemImageAvatarUploaded);
|
||||
if (itemImageAvatarUploaded != null)
|
||||
{
|
||||
// Retrieve current Avatar image.
|
||||
SaxItemImage itemImageAvatar = ItemDataMgr.GetItemImage(userItemId, Sax.ImageType.Avatar, SaxItemImage.StatusCat.Any);
|
||||
if (itemImageAvatar == null)
|
||||
itemImageAvatar = ItemDataMgr.CreateItemImage(userItemId, Sax.ImageType.Avatar);
|
||||
disposableItems.Add(itemImageAvatar);
|
||||
// Copy properties from uploaded image.
|
||||
itemImageAvatar.Filename = itemImageAvatarUploaded.Filename;
|
||||
itemImageAvatar.Mime = itemImageAvatarUploaded.Mime;
|
||||
itemImageAvatar.ContentType = itemImageAvatarUploaded.ContentType;
|
||||
itemImageAvatar.Width = itemImageAvatarUploaded.Width;
|
||||
itemImageAvatar.Height = itemImageAvatarUploaded.Height;
|
||||
itemImageAvatar.ImageData = itemImageAvatarUploaded.ImageData;
|
||||
itemImageAvatar.Status = SaxItemImage.DefaultStatus;
|
||||
if (!SysId.IsValid(itemImageAvatar.Id))
|
||||
{
|
||||
if (!ItemDataMgr.InsertItemImage(itemImageAvatar, DbUpdateInfo))
|
||||
{
|
||||
SaLogger.Warn(fn + " Failed to insert avatar image - " + ItemDataMgr.ErrorStateMessage);
|
||||
return Json(responseData.SetControlError("AccountContactImage", Localiser["msg.error.item.insert.failed"]));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!ItemDataMgr.UpdateItemImage(itemImageAvatar, DbUpdateInfo))
|
||||
{
|
||||
SaLogger.Warn(fn + " Failed to update avatar image - " + ItemDataMgr.ErrorStateMessage);
|
||||
return Json(responseData.SetControlError("AccountContactImage", Localiser["msg.error.item.update.failed"]));
|
||||
}
|
||||
}
|
||||
// Logically delete the uplaoded image.
|
||||
itemImageAvatarUploaded.Status = SaStatus.Deleted;
|
||||
if (!ItemDataMgr.UpdateItemImage(itemImageAvatarUploaded, DbUpdateInfo))
|
||||
SaLogger.Warn(fn + " Failed to logically delete uploaded avatar image - " + ItemDataMgr.ErrorStateMessage);
|
||||
}
|
||||
|
||||
// Construct response.
|
||||
responseData.Contact = new ContactResponseData();
|
||||
PopulateContactResponseData(model, responseData.Contact, userAccount);
|
||||
}
|
||||
responseData.Success = true;
|
||||
return Json(responseData);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
}
|
||||
//=======================================================================
|
||||
}
|
||||
+523
@@ -0,0 +1,523 @@
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Saxonite.Net.Core.Web.Online.Models;
|
||||
using Saxonite.Net.Core.Web.Base.App;
|
||||
using Saxonite.Net.Core.Web.Base.Controllers;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Saxonite.Net.Standard.Base.Bus;
|
||||
using Sarand.Net.Standard.Base.App;
|
||||
using Sarand.Net.Standard.Base.Bus;
|
||||
using Sarand.Net.Standard.Base.Utils;
|
||||
using Sarand.Net.Standard.Base.Core;
|
||||
using Sarand.Net.Standard.Base.Dbas;
|
||||
using Saxonite.Net.Standard.Base.App;
|
||||
using MailKit;
|
||||
using Org.BouncyCastle.Asn1.Mozilla;
|
||||
|
||||
namespace Saxonite.Net.Core.Web.Online.Controllers
|
||||
{
|
||||
//=======================================================================
|
||||
// Online Account Controller - User Eligibility - Ajax actions.
|
||||
//=======================================================================
|
||||
partial class AccountController
|
||||
{
|
||||
//-------------------------------------------------------------------
|
||||
// Data definitions.
|
||||
private class UserEligibilityResponseListData : AjaxResponse_Data.ItemData_Base
|
||||
{
|
||||
public String UserAccountId { get; set; }
|
||||
public String RegionName { get; set; }
|
||||
public String EligibilityTypeDesc { get; set; }
|
||||
public String Info { get; set; }
|
||||
public String ExpiresOnFmt { get; set; }
|
||||
}
|
||||
private class UserEligibilityResponseItemData : UserEligibilityResponseListData
|
||||
{
|
||||
public String RegionId { get; set; }
|
||||
public String EligibilityType { get; set; }
|
||||
public String ExpiresOnFrm { get; set; }
|
||||
}
|
||||
private void PopulateUserEligibilityResponseListData(SaxModel_Online model, SaxUserEligibility userEligibility, UserEligibilityResponseListData data)
|
||||
{
|
||||
data.Id = model.EncryptId(userEligibility.Id);
|
||||
data.UserAccountId = model.EncryptId(userEligibility.UserAccountId);
|
||||
data.RegionName = model.GetRegionCaption(userEligibility.RegionId);
|
||||
data.EligibilityTypeDesc = Localiser.GetEligibilityTypeCaption(userEligibility.EligibilityType);
|
||||
data.Info = userEligibility.Info;
|
||||
data.ExpiresOnFmt = model.FormatDateForDisplay(userEligibility.ExpiresOn);
|
||||
}
|
||||
private void PopulateUserEligibilityResponseItemData(SaxModel_Online model, SaxUserEligibility userEligibility, UserEligibilityResponseItemData data)
|
||||
{
|
||||
PopulateUserEligibilityResponseListData(model, userEligibility, data);
|
||||
data.RegionId = model.GetEncryptedRegionId(userEligibility.RegionId);
|
||||
data.EligibilityType = EligibilityTypeCodes.GetCodeForType(userEligibility.EligibilityType);
|
||||
data.ExpiresOnFrm = model.FormatDateForForm(userEligibility.ExpiresOn);
|
||||
data.CreatedOnFmt = model.FormatDateForDisplay(userEligibility.CreateStamp.On);
|
||||
data.StatusCode = userEligibility.StatusCode;
|
||||
data.StatusDesc = userEligibility.StatusDesc;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Account - Get User Eligibility list.
|
||||
//-------------------------------------------------------------------
|
||||
private class EligibilityTypeData
|
||||
{
|
||||
public String Code { get; set; }
|
||||
public String Desc { get; set; }
|
||||
/// <summary>Does the eligibility type allow a date range.</summary>
|
||||
public bool? Dates { get; set; } = null;
|
||||
}
|
||||
private class AjaxResponse_UserEligibilityListData : AjaxResponse_Data
|
||||
{
|
||||
// Construction.
|
||||
public AjaxResponse_UserEligibilityListData(SaxModel_Online model) : base(model) { }
|
||||
// Eligibility list.
|
||||
public List<UserEligibilityResponseListData> Eligibilities { get; } = new List<UserEligibilityResponseListData>();
|
||||
// Eligibility types.
|
||||
public List<EligibilityTypeData> Types { get; } = new List<EligibilityTypeData>();
|
||||
// User configuration.
|
||||
public class ConfigData
|
||||
{
|
||||
public bool? hideInfo { get; set; } = null;
|
||||
}
|
||||
public ConfigData Config { get; } = new ConfigData();
|
||||
}
|
||||
// Ajax request.
|
||||
[HttpPost]
|
||||
[Route("Account/Ajax/GetUserEligibilities")]
|
||||
[Route("Account/Ajax/GetUserEligibilityList")]
|
||||
public IActionResult GetUserEligibilities(Model_UserEligibility model)
|
||||
{
|
||||
String fn = GetType().Name + ".GetUserEligibilities";
|
||||
AjaxResponse_UserEligibilityListData responseData = new AjaxResponse_UserEligibilityListData(model);
|
||||
String messageTitle = Localiser["account.caption.profile.eligibility"];
|
||||
|
||||
// Validate session and referrer.
|
||||
if (!ValidReferer) return Forbid();
|
||||
if (!ValidUserSession) return GetAjaxResult_InvalidSession(responseData);
|
||||
RefreshModel(model);
|
||||
|
||||
// Eligibility types.
|
||||
foreach (Sax.EligibilityType eligibilityType in EnumUtil.GetValues<Sax.EligibilityType>())
|
||||
{
|
||||
EligibilityTypeData typeData = new EligibilityTypeData();
|
||||
typeData.Code = model.EligibilityTypeCodes.GetCodeForType(eligibilityType);
|
||||
if (StringUtil.IsBlank(typeData.Code)) continue;
|
||||
typeData.Desc = Localiser.GetEligibilityTypeCaption(eligibilityType);
|
||||
if (SaxUserEligibility.AllowsApplicablePeriod(eligibilityType))
|
||||
typeData.Dates = true;
|
||||
responseData.Types.Add(typeData);
|
||||
}
|
||||
|
||||
// User account.
|
||||
SysId userAccountId = SysId.ToSysId(model.UserAccount.Id);
|
||||
if (!SysId.IsValid(userAccountId))
|
||||
userAccountId = SessionUserAccountId;
|
||||
|
||||
// User configuration.
|
||||
if (SessionData_Online.UserConfig.Profile.Eligibility.HideInfo)
|
||||
responseData.Config.hideInfo = true;
|
||||
|
||||
// Item filter.
|
||||
SaxUserEligibility.Params prmUserEligibility = new SaxUserEligibility.Params();
|
||||
prmUserEligibility.UserAccountIdsIncluded.Add(userAccountId);
|
||||
prmUserEligibility.StatusCat = SaxUserEligibility.StatusCat.NotDeleted;
|
||||
prmUserEligibility.SortColumns.Add(AccountMgr.GetUserEligibilityColumnDfn(SaxUserEligibility.Column.EligibilityType));
|
||||
model.Paging.ItemTotal = (ulong)AccountMgr.GetUserEligibilityCount(prmUserEligibility);
|
||||
model.PopulatePagingTo(prmUserEligibility.ResultsPaging);
|
||||
|
||||
// Item columns.
|
||||
ColumnDfn colId = AccountMgr.GetUserEligibilityColumnDfn(SaxUserEligibility.Column.Id);
|
||||
ColumnDfn colUserAccountId = AccountMgr.GetUserEligibilityColumnDfn(SaxUserEligibility.Column.UserAccountId);
|
||||
ColumnDfn colRegionName = AccountMgr.GetUserEligibilityColumnDfn(SaxUserEligibility.Column.Region_Name);
|
||||
ColumnDfn colEligibilityType = AccountMgr.GetUserEligibilityColumnDfn(SaxUserEligibility.Column.EligibilityType);
|
||||
ColumnDfn colInfo = AccountMgr.GetUserEligibilityColumnDfn(SaxUserEligibility.Column.Info);
|
||||
ColumnDfn colExpires = AccountMgr.GetUserEligibilityColumnDfn(SaxUserEligibility.Column.ExpiresOn);
|
||||
ColumnDfn colStatus = AccountMgr.GetUserEligibilityColumnDfn(SaxUserEligibility.Column.Status);
|
||||
List<ColumnDfn> columns = new List<ColumnDfn>()
|
||||
{
|
||||
colId,colUserAccountId,
|
||||
colRegionName, colEligibilityType,
|
||||
colInfo, colExpires,
|
||||
colStatus,
|
||||
};
|
||||
|
||||
// Sort columns.
|
||||
prmUserEligibility.SortColumns.Add(colRegionName);
|
||||
|
||||
// Query items.
|
||||
using (DbResultSet resultSet = AccountMgr.ExecuteUserEligibilityQuery(columns, prmUserEligibility))
|
||||
{
|
||||
while (resultSet != null && resultSet.HasRows && resultSet.NextRecord())
|
||||
{
|
||||
NamedValue.Map values = resultSet.GetRecordValues();
|
||||
Sax.EligibilityType eligibilityType = (Sax.EligibilityType)values.GetLong(colEligibilityType.DataName);
|
||||
UserEligibilityResponseListData userEligibilityData = new UserEligibilityResponseListData()
|
||||
{
|
||||
Id = model.EncryptId(new SysId(values.GetLong(colId.DataName))),
|
||||
UserAccountId = model.EncryptId(new SysId(values.GetLong(colUserAccountId.DataName))),
|
||||
RegionName = values.GetString(colRegionName.DataName),
|
||||
EligibilityTypeDesc = Localiser.GetEligibilityTypeCaption(eligibilityType),
|
||||
Info = values.GetString(colInfo.DataName),
|
||||
ExpiresOnFmt = model.FormatDateForDisplay(values.GetDate(colExpires.DataName)),
|
||||
StatusCode = values.GetString(colStatus.DataName),
|
||||
StatusDesc = SacsSystem.GetStatusDescForCode(values.GetString(colStatus.DataName))
|
||||
};
|
||||
responseData.Eligibilities.Add(userEligibilityData);
|
||||
}
|
||||
}
|
||||
if (model.Paging.IsPaged)
|
||||
model.Paging.ItemCount = (ushort)responseData.Eligibilities.Count;
|
||||
|
||||
// Complete response.
|
||||
responseData.SetPaging(model);
|
||||
responseData.Success = true;
|
||||
return Json(responseData);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Get User Eligibility ajax request.
|
||||
//-------------------------------------------------------------------
|
||||
private class AjaxResponse_UserEligibility : AjaxResponse_Data
|
||||
{
|
||||
// Construction.
|
||||
public AjaxResponse_UserEligibility(SaxModel_Online model) : base(model) { }
|
||||
// Eligibility details.
|
||||
public UserEligibilityResponseItemData Eligibility { get; } = new UserEligibilityResponseItemData();
|
||||
}
|
||||
//-------------------------------------------------------------------
|
||||
[HttpPost]
|
||||
[Route("Account/Ajax/GetUserEligibility")]
|
||||
public IActionResult Ajax_GetUserEligibility(Model_UserEligibility model)
|
||||
{
|
||||
String fn = GetType().Name + ".Ajax_GetUserEligibility";
|
||||
String messageTitle = Localiser["account.caption.profile.eligibility"];
|
||||
AjaxResponse_UserEligibility responseData = new AjaxResponse_UserEligibility(model);
|
||||
|
||||
// Validate session and referrer.
|
||||
if (!ValidReferer) return Forbid();
|
||||
if (!ValidUserSession) return GetAjaxResult_InvalidSession(responseData);
|
||||
RefreshModel(model);
|
||||
|
||||
// Record disposable items as they are created so all can be disposed when needed.
|
||||
using (DisposableCollection<IDisposable> disposableItems = new DisposableCollection<IDisposable>())
|
||||
{
|
||||
|
||||
// Identify item.
|
||||
SysId userEligibilityId = model.ExtractSysId(model.Eligibility.Id);
|
||||
if (!SysId.IsValid(userEligibilityId))
|
||||
return Json(responseData.SetPopupMessage(messageTitle, Localiser["msg.error.item.id.not.specified"]));
|
||||
|
||||
// Retrieve item.
|
||||
SaxUserEligibility userEligibility = AccountMgr.GetUserEligibilityById(userEligibilityId);
|
||||
disposableItems.Add(userEligibility);
|
||||
if (userEligibility == null)
|
||||
{
|
||||
SaLogger.Warn(fn + " Failed to retrieve User Eligibility for Id: '" + model.Eligibility.Id + "'");
|
||||
return Json(responseData.SetPopupMessage(messageTitle, Localiser["msg.error.item.id.not.found"]));
|
||||
}
|
||||
|
||||
// Construct response.
|
||||
PopulateUserEligibilityResponseItemData(model, userEligibility, responseData.Eligibility);
|
||||
responseData.Success = true;
|
||||
}
|
||||
return Json(responseData);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Store User Eligibility ajax request.
|
||||
//-------------------------------------------------------------------
|
||||
private class AjaxResponse_StoreUserEligibility : AjaxResponse_Data
|
||||
{
|
||||
// Construction.
|
||||
public AjaxResponse_StoreUserEligibility(SaxModel_Online model) : base(model) { }
|
||||
// Eligibility details.
|
||||
public UserEligibilityResponseItemData Eligibility { get; } = new UserEligibilityResponseItemData();
|
||||
}
|
||||
//-------------------------------------------------------------------
|
||||
[HttpPost]
|
||||
[Route("Account/Ajax/StoreUserEligibility")]
|
||||
public IActionResult Ajax_StoreUserEligibility(Model_UserEligibility model)
|
||||
{
|
||||
String fn = GetType().Name + ".Ajax_StoreUserEligibility";
|
||||
String messageTitle = Localiser["account.caption.profile.eligibility"];
|
||||
AjaxResponse_StoreUserEligibility responseData = new AjaxResponse_StoreUserEligibility(model);
|
||||
|
||||
// Validate session and referrer.
|
||||
if (!ValidReferer) return Forbid();
|
||||
if (!ValidUserSession) return GetAjaxResult_InvalidSession(responseData);
|
||||
RefreshModel(model);
|
||||
|
||||
// Record disposable items as they are created so all can be disposed when needed.
|
||||
using (DisposableCollection<IDisposable> disposableItems = new DisposableCollection<IDisposable>())
|
||||
{
|
||||
|
||||
// Validate item properties.
|
||||
model.ValidateEligibilityDetails(responseData);
|
||||
if (responseData.HasControlErrors())
|
||||
return Json(responseData);
|
||||
|
||||
// User account.
|
||||
SysId userAccountId = SysId.ToSysId(model.UserAccount.Id);
|
||||
if (!SysId.IsValid(userAccountId))
|
||||
userAccountId = SessionUserAccountId;
|
||||
|
||||
// Validate User Eligibility Id against 'Exists' flag.
|
||||
SysId userEligibilityId = model.ExtractSysId(model.Eligibility.Id);
|
||||
bool eligibilityExists = StringUtil.ToBool(model.Eligibility.Exists);
|
||||
if (eligibilityExists && !SysId.IsValid(userEligibilityId))
|
||||
{
|
||||
SaLogger.Warn(fn + " Id not specified for existing User Eligibility.");
|
||||
return Json(responseData.SetGoHome(messageTitle, Localiser["msg.error.system"]));
|
||||
}
|
||||
if (!eligibilityExists && SysId.IsValid(userEligibilityId))
|
||||
{
|
||||
SaLogger.Warn(fn + " Id specified for new User Eligibility: '" + model.Eligibility.Id + "'");
|
||||
return Json(responseData.SetGoHome(messageTitle, Localiser["msg.error.system"]));
|
||||
}
|
||||
|
||||
// Retrieve existing item.
|
||||
SaxUserEligibility userEligibility = AccountMgr.GetUserEligibilityById(userEligibilityId);
|
||||
disposableItems.Add(userEligibility);
|
||||
if (userEligibility == null && SysId.IsValid(userEligibilityId))
|
||||
{
|
||||
SaLogger.Warn(fn + " Failed to retrieve User Eligibility for Id: '" + model.Eligibility.Id + "'");
|
||||
return Json(responseData.SetPopupMessage(messageTitle, Localiser["msg.error.item.id.not.found"]));
|
||||
}
|
||||
|
||||
// Validate user eligibility properties.
|
||||
if (userEligibility != null)
|
||||
{
|
||||
if (!userEligibility.UserAccountId.Equals(userAccountId))
|
||||
{
|
||||
SaLogger.Warn(fn + " Inconsistent User Account Id specified for User Eligibility. Expected: " + userEligibility.UserAccountId + ". Found: " + userAccountId);
|
||||
return Json(responseData.SetGoHome(messageTitle, Localiser["msg.error.system"]));
|
||||
}
|
||||
}
|
||||
|
||||
// Region.
|
||||
SysId regionId = model.Eligibility.RegionId != null ? model.DecryptId(model.Eligibility.RegionId) : userEligibility != null ? userEligibility.RegionId : null;
|
||||
if (!SysId.IsValid(regionId))
|
||||
{
|
||||
// Shouldn't get here.
|
||||
SaLogger.Warn(fn + " Region Id not supplied for " + (eligibilityExists ? "existing" : "new") + " eligibility.");
|
||||
return Json(responseData.SetGoHome(messageTitle, Localiser["msg.error.system"]));
|
||||
}
|
||||
SaxRegion.Data region = Internals.GetRegion(regionId);
|
||||
|
||||
// Eligibility type.
|
||||
Sax.EligibilityType eligibilityType = model.Eligibility.Type != null ? model.Eligibility.getEligibilityType() : userEligibility != null ? userEligibility.EligibilityType : 0;
|
||||
if (eligibilityType <= 0)
|
||||
{
|
||||
// Shouldn't get here.
|
||||
SaLogger.Warn(fn + " Eligibility type not specified for " + (eligibilityExists ? "existing" : "new") + " eligibility.");
|
||||
return Json(responseData.SetGoHome(messageTitle, Localiser["msg.error.system"]));
|
||||
}
|
||||
|
||||
// Check for duplicate data.
|
||||
// ToDo Include date range in checking for duplicate eligibility?
|
||||
{
|
||||
// First check without region.
|
||||
SaxUserEligibility.Params prmUserEligibility = new SaxUserEligibility.Params();
|
||||
if (userEligibility != null)
|
||||
prmUserEligibility.IdsExcluded.Add(userEligibility.Id);
|
||||
prmUserEligibility.UserAccountIdsIncluded.Add(userAccountId);
|
||||
prmUserEligibility.EligibilityTypesIncluded.Add(eligibilityType);
|
||||
prmUserEligibility.StatusCat = SaxUserEligibility.StatusCat.NotDeleted;
|
||||
long eligibilityCount = AccountMgr.GetUserEligibilityCount(prmUserEligibility);
|
||||
// Selected Eligibility types have a limit on the number of instances allowed.
|
||||
if (eligibilityCount >= SaxUserEligibility.GetMaxInstances(eligibilityType))
|
||||
{
|
||||
SaLogger.Warn(fn + " Eligibility type instance limit reached. Type: " + eligibilityType.ToString() + ". Instances: " + eligibilityCount + ". " + GetLogSuffix());
|
||||
return Json(responseData.SetPopupMessage(messageTitle, Localiser["msg.error.item.duplicate"]));
|
||||
}
|
||||
// Now include region - only allow one eligibility of each type.
|
||||
prmUserEligibility.RegionIdsIncluded.Add(regionId);
|
||||
eligibilityCount = AccountMgr.GetUserEligibilityCount(prmUserEligibility);
|
||||
if (eligibilityCount >= 1)
|
||||
{
|
||||
SaLogger.Warn(fn + " Duplicate Eligibility exists. RegionId: " + SysId.ToString(regionId) + ". Type: " + eligibilityType.ToString() + ". " + GetLogSuffix());
|
||||
return Json(responseData.SetPopupMessage(messageTitle, Localiser["msg.error.item.duplicate"]));
|
||||
}
|
||||
}
|
||||
|
||||
// If region or eligibility have changed, check whether an equivalent deleted eligibility exists.
|
||||
// NB Can't modify the current eligibility with the modified values as it would conflict with the
|
||||
// deleted item - unique on user, region and eligibility.
|
||||
if (userEligibility != null && (!userEligibility.RegionId.Equals(regionId) || userEligibility.EligibilityType != eligibilityType))
|
||||
{
|
||||
SaxUserEligibility.Params prmUserEligibility = new SaxUserEligibility.Params();
|
||||
prmUserEligibility.IdsExcluded.Add(userEligibility.Id);
|
||||
prmUserEligibility.UserAccountIdsIncluded.Add(userAccountId);
|
||||
prmUserEligibility.RegionIdsIncluded.Add(regionId);
|
||||
prmUserEligibility.EligibilityTypesIncluded.Add(eligibilityType);
|
||||
prmUserEligibility.StatusCat = SaxUserEligibility.StatusCat.DeletedOnly;
|
||||
SaxUserEligibility userEligibilityDeleted = AccountMgr.GetUserEligibility(prmUserEligibility);
|
||||
if (userEligibilityDeleted != null)
|
||||
{
|
||||
disposableItems.Add(userEligibilityDeleted);
|
||||
SaLogger.Info(fn + " Resurrecting User Eligibility with status: " + userEligibilityDeleted.StatusDesc + ". Id: " + SysId.ToString(userEligibilityDeleted.Id) + ". " + GetLogSuffix());
|
||||
userEligibilityDeleted.Status = SaxUserEligibility.DefaultStatus;
|
||||
// Delete current item and replace with previously deleted item.
|
||||
if (!AccountMgr.DeleteUserEligibility(userEligibility, DbUpdateInfo))
|
||||
{
|
||||
SaLogger.Warn(fn + " Failed to delete user eligibility: " + AccountMgr.ErrorStateMessage);
|
||||
return Json(responseData.SetPopupMessage(messageTitle, Localiser["msg.error.item.update.failed"]));
|
||||
}
|
||||
userEligibility = userEligibilityDeleted;
|
||||
}
|
||||
}
|
||||
|
||||
// If eligibility doesn't exist for the user, it may have been previously deleted.
|
||||
if (userEligibility == null)
|
||||
{
|
||||
// See if there is an existing item that matches user, region and eligibility.
|
||||
SaxUserEligibility.Params prmUserEligibility = new SaxUserEligibility.Params();
|
||||
prmUserEligibility.UserAccountIdsIncluded.Add(userAccountId);
|
||||
prmUserEligibility.RegionIdsIncluded.Add(regionId);
|
||||
prmUserEligibility.EligibilityTypesIncluded.Add(eligibilityType);
|
||||
prmUserEligibility.StatusCat = SaxUserEligibility.StatusCat.DeletedOnly;
|
||||
userEligibility = AccountMgr.GetUserEligibility(prmUserEligibility);
|
||||
if (userEligibility == null)
|
||||
{
|
||||
// Try again for the user & region without the eligibility type.
|
||||
prmUserEligibility.EligibilityTypesIncluded.Clear();
|
||||
userEligibility = AccountMgr.GetUserEligibility(prmUserEligibility);
|
||||
}
|
||||
if (userEligibility == null)
|
||||
{
|
||||
// Try again for the user & eligibility type without the region.
|
||||
prmUserEligibility.RegionIdsIncluded.Clear();
|
||||
prmUserEligibility.EligibilityTypesIncluded.Add(eligibilityType);
|
||||
userEligibility = AccountMgr.GetUserEligibility(prmUserEligibility);
|
||||
}
|
||||
if (userEligibility == null)
|
||||
{
|
||||
// Try again just for the user.
|
||||
prmUserEligibility.RegionIdsIncluded.Clear();
|
||||
prmUserEligibility.EligibilityTypesIncluded.Clear();
|
||||
userEligibility = AccountMgr.GetUserEligibility(prmUserEligibility);
|
||||
}
|
||||
if (userEligibility != null)
|
||||
{
|
||||
disposableItems.Add(userEligibility);
|
||||
SaLogger.Info(fn + " Resurrecting User Eligibility with status: " + userEligibility.StatusDesc + ". Id: " + SysId.ToString(userEligibility.Id) + ". " + GetLogSuffix());
|
||||
userEligibility.Status = SaxUserEligibility.DefaultStatus;
|
||||
}
|
||||
else
|
||||
{
|
||||
userEligibility = AccountMgr.CreateUserEligibility(userAccountId, regionId, eligibilityType);
|
||||
disposableItems.Add(userEligibility);
|
||||
}
|
||||
}
|
||||
|
||||
// Populate item properties.
|
||||
userEligibility.RegionId = regionId;
|
||||
userEligibility.EligibilityType = eligibilityType;
|
||||
if (model.Eligibility.Info != null)
|
||||
userEligibility.Info = model.Eligibility.Info;
|
||||
if (model.Eligibility.ExpiresOn != null)
|
||||
userEligibility.ExpiresOn = model.ParseDateFromForm(model.Eligibility.ExpiresOn);
|
||||
|
||||
// Store item.
|
||||
if (!SysId.IsValid(userEligibility.Id))
|
||||
{
|
||||
if (!AccountMgr.InsertUserEligibility(userEligibility, DbUpdateInfo))
|
||||
{
|
||||
SaLogger.Warn(fn + " Failed to insert user eligibility: " + AccountMgr.ErrorStateMessage);
|
||||
return Json(responseData.SetPopupMessage(messageTitle, Localiser["msg.error.item.insert.failed"]));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!AccountMgr.UpdateUserEligibility(userEligibility, DbUpdateInfo))
|
||||
{
|
||||
SaLogger.Warn(fn + " Failed to update user eligibility [Id:" + SysId.ToString(userEligibility.Id) + "]: " + AccountMgr.ErrorStateMessage);
|
||||
return Json(responseData.SetPopupMessage(messageTitle, Localiser["msg.error.item.update.failed"]));
|
||||
}
|
||||
}
|
||||
|
||||
// Construct response.
|
||||
PopulateUserEligibilityResponseItemData(model, userEligibility, responseData.Eligibility);
|
||||
responseData.Success = true;
|
||||
}
|
||||
return Json(responseData);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Remove User Eligibility ajax request.
|
||||
//-------------------------------------------------------------------
|
||||
private class AjaxResponse_RemoveUserEligibility : AjaxResponse_Data
|
||||
{
|
||||
// Construction.
|
||||
public AjaxResponse_RemoveUserEligibility(SaxModel_Online model) : base(model) { }
|
||||
}
|
||||
//-------------------------------------------------------------------
|
||||
[HttpPost]
|
||||
[Route("Account/Ajax/RemoveUserEligibility")]
|
||||
public IActionResult Ajax_RemoveUserEligibility(Model_UserEligibility model)
|
||||
{
|
||||
String fn = GetType().Name + ".Ajax_RemoveUserEligibility";
|
||||
String messageTitle = Localiser["account.caption.profile.eligibility"];
|
||||
AjaxResponse_UserEligibility responseData = new AjaxResponse_UserEligibility(model);
|
||||
|
||||
// Validate session and referrer.
|
||||
if (!ValidReferer) return Forbid();
|
||||
if (!ValidUserSession) return GetAjaxResult_InvalidSession(responseData);
|
||||
RefreshModel(model);
|
||||
|
||||
// User account.
|
||||
SysId userAccountId = SysId.ToSysId(model.UserAccount.Id);
|
||||
if (!SysId.IsValid(userAccountId))
|
||||
userAccountId = SessionUserAccountId;
|
||||
|
||||
// Record disposable items as they are created so all can be disposed when needed.
|
||||
using (DisposableCollection<IDisposable> disposableItems = new DisposableCollection<IDisposable>())
|
||||
{
|
||||
|
||||
// User Eligibility Id.
|
||||
SysId userEligibilityId = model.ExtractSysId(model.Eligibility.Id);
|
||||
if (!SysId.IsValid(userEligibilityId))
|
||||
{
|
||||
SaLogger.Warn(fn + " Id not specified to remove User Eligibility.");
|
||||
return Json(responseData.SetGoHome(messageTitle, Localiser["msg.error.system"]));
|
||||
}
|
||||
|
||||
// Retrieve existing item.
|
||||
SaxUserEligibility userEligibility = AccountMgr.GetUserEligibilityById(userEligibilityId);
|
||||
disposableItems.Add(userEligibility);
|
||||
if (userEligibility == null)
|
||||
{
|
||||
SaLogger.Warn(fn + " Failed to retrieve User Eligibility for Id: '" + model.Eligibility.Id + "'");
|
||||
return Json(responseData.SetPopupMessage(messageTitle, Localiser["msg.error.item.id.not.found"]));
|
||||
}
|
||||
|
||||
// Validate user eligibility properties.
|
||||
if (!userEligibility.UserAccountId.Equals(userAccountId))
|
||||
{
|
||||
SaLogger.Warn(fn + " Inconsistent User Account Id specified for User Eligibility. Expected: " + userEligibility.UserAccountId + ". Found: " + userAccountId);
|
||||
return Json(responseData.SetGoHome(messageTitle, Localiser["msg.error.system"]));
|
||||
}
|
||||
|
||||
// Delete item.
|
||||
if (!AccountMgr.DeleteUserEligibility(userEligibility, DbUpdateInfo))
|
||||
{
|
||||
SaLogger.Warn(fn + " Failed to delete user eligibility [Id:" + SysId.ToString(userEligibility.Id) + "]: " + AccountMgr.ErrorStateMessage);
|
||||
return Json(responseData.SetPopupMessage(messageTitle, Localiser["msg.error.item.update.failed"]));
|
||||
}
|
||||
|
||||
// Construct response.
|
||||
PopulateUserEligibilityResponseItemData(model, userEligibility, responseData.Eligibility);
|
||||
responseData.Success = true;
|
||||
}
|
||||
return Json(responseData);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
}
|
||||
//=======================================================================
|
||||
}
|
||||
+549
@@ -0,0 +1,549 @@
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Saxonite.Net.Core.Web.Online.Models;
|
||||
using Saxonite.Net.Core.Web.Base.App;
|
||||
using Saxonite.Net.Core.Web.Base.Controllers;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Saxonite.Net.Standard.Base.Bus;
|
||||
using Sarand.Net.Standard.Base.App;
|
||||
using Sarand.Net.Standard.Base.Bus;
|
||||
using Sarand.Net.Standard.Base.Utils;
|
||||
using Sarand.Net.Standard.Base.Core;
|
||||
using Sarand.Net.Standard.Base.Dbas;
|
||||
using Saxonite.Net.Standard.Base.App;
|
||||
|
||||
namespace Saxonite.Net.Core.Web.Online.Controllers
|
||||
{
|
||||
//=======================================================================
|
||||
// Online Account Controller - Organisations - Ajax actions.
|
||||
//=======================================================================
|
||||
partial class AccountController
|
||||
{
|
||||
//-------------------------------------------------------------------
|
||||
/// <summary>Organisation properties for list population.</summary>
|
||||
private class ProfileOrganisationListData : AjaxResponse_Data.ItemData_Base
|
||||
{
|
||||
public String Name { get; set; }
|
||||
public String CategoryDesc { get; set; }
|
||||
public String TypeDesc { get; set; }
|
||||
public String LogoUrl { get; set; }
|
||||
public String SportName { get; set; }
|
||||
// Primary Region.
|
||||
public class RegionData
|
||||
{
|
||||
public String Id { get; set; }
|
||||
public String Name { get; set; }
|
||||
public bool? Country { get; set; } = null;
|
||||
}
|
||||
public RegionData RegionPrimary { get; } = new RegionData();
|
||||
// Associated properties.
|
||||
public long MemberCount { get; set; }
|
||||
public long OpportunityCount { get; set; }
|
||||
public bool? Admin { get; set; } = null;
|
||||
public bool? MemberAdmin { get; set; } = null;
|
||||
public bool? OpportunitiyAdmin { get; set; } = null;
|
||||
public bool? ScheduleAdmin { get; set; } = null;
|
||||
public bool? ArticleAdmin { get; set; } = null;
|
||||
}
|
||||
/// <summary>Organisation properties for popup dialog and form.</summary>
|
||||
private class ProfileOrganisationItemData : ProfileOrganisationListData
|
||||
{
|
||||
public String CategoryCode { get; set; }
|
||||
public String TypeCode { get; set; }
|
||||
public String SportId { get; set; }
|
||||
public String About { get; set; }
|
||||
public String Facilities { get; set; }
|
||||
public List<AjaxResponse_Data.ContactMethodData> ContactMethods { get; set; }
|
||||
public AjaxResponse_Data.AddressData Address { get; set; }
|
||||
}
|
||||
/// <summary>Populate organisation properties for list.</summary>
|
||||
private void PopulateOrganisationResponseListData(SaxModel_Online model, SaxOrganisation organisation, SaxUserOrganisation userOrganisation, ProfileOrganisationListData data)
|
||||
{
|
||||
data.Id = model.EncryptId(organisation.Id);
|
||||
data.Name = organisation.Name;
|
||||
data.SportName = model.GetSportCaption(organisation.SportIdPrimary);
|
||||
data.RegionPrimary.Name = model.GetRegionCaption(organisation.RegionIdPrimary);
|
||||
// Associated properties.
|
||||
data.MemberCount = AccountMgr.GetOrganisationMemberCount(organisation.Id);
|
||||
data.OpportunityCount = AccountMgr.GetOrganisationOpportunityCount(organisation.Id);
|
||||
if (userOrganisation != null)
|
||||
{
|
||||
List<String> roleCodes = userOrganisation.GetOrganisationRoleCodes();
|
||||
if (roleCodes.ContainsCI(OrganisationRoleCodes.GetCodeForType(Sax.OrganisationRole.Admin)))
|
||||
data.Admin = true;
|
||||
if (roleCodes.ContainsCI(OrganisationRoleCodes.GetCodeForType(Sax.OrganisationRole.MemberAdmin)))
|
||||
data.MemberAdmin = true;
|
||||
if (roleCodes.ContainsCI(OrganisationRoleCodes.GetCodeForType(Sax.OrganisationRole.OpportunityAdmin)))
|
||||
data.OpportunitiyAdmin = true;
|
||||
if (roleCodes.ContainsCI(OrganisationRoleCodes.GetCodeForType(Sax.OrganisationRole.ScheduleAdmin)))
|
||||
data.ScheduleAdmin = true;
|
||||
if (roleCodes.ContainsCI(OrganisationRoleCodes.GetCodeForType(Sax.OrganisationRole.ArticleAdmin)))
|
||||
data.ArticleAdmin = true;
|
||||
}
|
||||
// Common properties.
|
||||
data.CreatedOnFmt = Localiser.FormatDate(organisation.CreateStamp.On);
|
||||
data.UpdatedOnFmt = Localiser.FormatDate(organisation.UpdateStamp.On);
|
||||
data.StatusCode = organisation.StatusCode;
|
||||
data.StatusDesc = organisation.StatusDesc;
|
||||
}
|
||||
/// <summary>Populate organisation properties for popup dialog and form.</summary>
|
||||
private void PopulateOrganisationResponseItemData(SaxModel_Online model, SaxOrganisation organisation, SaxUserOrganisation userOrganisation, SaxItemAddress address, ProfileOrganisationItemData data)
|
||||
{
|
||||
PopulateOrganisationResponseListData(model, organisation, userOrganisation, (ProfileOrganisationListData)data);
|
||||
data.CategoryCode = OrganisationCategoryCodes.GetCodeForType(organisation.OrganisationCategory);
|
||||
data.CategoryDesc = Localiser.GetOrganisationCategoryCaption(organisation.OrganisationCategory);
|
||||
data.TypeCode = OrganisationTypeCodes.GetCodeForType(organisation.OrganisationType);
|
||||
data.TypeDesc = Localiser.GetOrganisationTypeCaption(organisation.OrganisationType);
|
||||
data.SportId = model.GetEncryptedSportId(organisation.SportIdPrimary);
|
||||
data.RegionPrimary.Id = model.GetEncryptedRegionId(organisation.RegionIdPrimary);
|
||||
data.About = organisation.About;
|
||||
data.Facilities = organisation.Facilities;
|
||||
// Contact methods.
|
||||
SaxContactData contactData = new SaxContactData(organisation.ContactData);
|
||||
foreach (Sax.ContactMethod method in contactData.Methods)
|
||||
{
|
||||
if (data.ContactMethods == null) data.ContactMethods = new List<AjaxResponse_Data.ContactMethodData>();
|
||||
data.ContactMethods.Add(new AjaxResponse_Data.ContactMethodData() { Method = method.ToString(), MethodCaption = Localiser.GetContactMethodCaption(method), Value = contactData.GetContactMethodValue(method) });
|
||||
}
|
||||
// Address.
|
||||
if (address != null && !address.IsStatusDeleted)
|
||||
{
|
||||
data.Address = new AjaxResponse_Data.AddressData();
|
||||
data.Address.Id = model.EncryptId(address.Id);
|
||||
data.Address.Line1 = address.Line1;
|
||||
data.Address.Line2 = address.Line2;
|
||||
data.Address.Line3 = address.Line3;
|
||||
data.Address.Town = address.Town;
|
||||
data.Address.RegionNameProvince = address.Province;
|
||||
data.Address.RegionNameCountry = address.Country;
|
||||
data.Address.PostalCode = address.PostalCode;
|
||||
}
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Account - Get Profile Organisations.
|
||||
//-------------------------------------------------------------------
|
||||
private class AjaxResponse_ProfileOrganisationList : AjaxResponse_Data
|
||||
{
|
||||
// Construction.
|
||||
public AjaxResponse_ProfileOrganisationList(SaxModel_Online model) : base(model) { }
|
||||
// Reference data.
|
||||
public List<ItemCodeDesc> ContactMethods { get; } = new List<ItemCodeDesc>();
|
||||
// Organisation list.
|
||||
public List<ProfileOrganisationListData> Organisations { get; } = new List<ProfileOrganisationListData>();
|
||||
}
|
||||
// Ajax request.
|
||||
[HttpPost]
|
||||
[Route("Account/Ajax/GetProfileOrganisations")]
|
||||
[Route("Account/Ajax/GetProfileOrganisationList")]
|
||||
public IActionResult GetProfileOrganisationList(Model_Account model)
|
||||
{
|
||||
String fn = GetType().Name + ".GetProfileOrganisationList";
|
||||
AjaxResponse_ProfileOrganisationList responseData = new AjaxResponse_ProfileOrganisationList(model);
|
||||
String messageTitle = Localiser["account.caption.profile.organisations"];
|
||||
|
||||
// Validate session and referrer.
|
||||
if (!ValidReferer) return Forbid();
|
||||
if (!ValidUserSession) return GetAjaxResult_InvalidSession(responseData);
|
||||
RefreshModel(model);
|
||||
|
||||
// Reference data - contact methods.
|
||||
List<Sax.ContactMethod> validContactMethods = SaxOrganisation.ValidContactMethods;
|
||||
foreach (TypeCodeDesc contactMethod in ContactMethodCodes)
|
||||
{
|
||||
// Skip methods that aren't associated with Organisations.
|
||||
if (!validContactMethods.Contains((Sax.ContactMethod)contactMethod.Type)) continue;
|
||||
responseData.ContactMethods.Add(new AjaxResponse_Data.ItemCodeDesc() { Code = contactMethod.Code, Desc = Localiser.GetContactMethodCaption((Sax.ContactMethod)contactMethod.Type) });
|
||||
}
|
||||
|
||||
// Record disposable items as they are created so all can be disposed when needed.
|
||||
using (DisposableCollection<IDisposable> disposableItems = new DisposableCollection<IDisposable>())
|
||||
{
|
||||
|
||||
// Query organisations that user is a member of.
|
||||
SaxUserOrganisation.Params prmUserOrganisation = new SaxUserOrganisation.Params();
|
||||
prmUserOrganisation.UserAccountIdsIncluded.Add(SessionUserAccountId);
|
||||
prmUserOrganisation.OrganisationStatusCat = SaxOrganisation.StatusCat.ActiveOnly;
|
||||
prmUserOrganisation.OrganisationMembersOnly = true;
|
||||
prmUserOrganisation.StatusCat = SaxUserOrganisation.StatusCat.ActiveOnly;
|
||||
List<SaxUserOrganisation> userOrganisations = AccountMgr.GetUserOrganisationList(prmUserOrganisation);
|
||||
List<SysId> organisationIds = userOrganisations.GetOrganisationIds();
|
||||
|
||||
// Item columns.
|
||||
// NB Although UserOrgansiation data is queried, the response data is a list of Organisations.
|
||||
ColumnDfn colId = AccountMgr.GetUserOrganisationColumnDfn(SaxUserOrganisation.Column.OrganisationId);
|
||||
ColumnDfn colOrganisationName = AccountMgr.GetUserOrganisationColumnDfn(SaxUserOrganisation.Column.Organisation_Name);
|
||||
ColumnDfn colOrganisationCategory = AccountMgr.GetUserOrganisationColumnDfn(SaxUserOrganisation.Column.Organisation_Category);
|
||||
ColumnDfn colOrganisationType = AccountMgr.GetUserOrganisationColumnDfn(SaxUserOrganisation.Column.Organisation_Type);
|
||||
ColumnDfn colOrganisationSportName = AccountMgr.GetUserOrganisationColumnDfn(SaxUserOrganisation.Column.Organisation_Sport_Name);
|
||||
ColumnDfn colOrganisationRegionName = AccountMgr.GetUserOrganisationColumnDfn(SaxUserOrganisation.Column.Organisation_Region_Name);
|
||||
ColumnDfn colMemberCount = AccountMgr.GetUserOrganisationColumnDfn(SaxUserOrganisation.Column.Organisation_Member_Count);
|
||||
ColumnDfn colOpportunityCount = AccountMgr.GetUserOrganisationColumnDfn(SaxUserOrganisation.Column.Organisation_Opportunity_Count);
|
||||
ColumnDfn colStatus = AccountMgr.GetUserOrganisationColumnDfn(SaxUserOrganisation.Column.Status);
|
||||
ColumnDfn colCreatedOn = AccountMgr.GetUserOrganisationColumnDfn(SaxUserOrganisation.Column.CreateOn_Date);
|
||||
ColumnDfn colLogoCount = AccountMgr.GetUserOrganisationColumnDfn(SaxUserOrganisation.Column.Organisation_LogoImage_Count);
|
||||
ColumnDfn colRoleCodes = AccountMgr.GetUserOrganisationColumnDfn(SaxUserOrganisation.Column.OrganisationRoleCodes);
|
||||
List<ColumnDfn> columns = new List<ColumnDfn>()
|
||||
{
|
||||
colId, colOrganisationName, colOrganisationCategory, colOrganisationType,
|
||||
colOrganisationSportName, colOrganisationRegionName,
|
||||
colMemberCount, colOpportunityCount,
|
||||
colStatus, colStatus, colCreatedOn,
|
||||
colLogoCount, colRoleCodes
|
||||
};
|
||||
|
||||
// Sort columns.
|
||||
colCreatedOn.SortAscending = false;
|
||||
prmUserOrganisation.SortColumns.Add(colOrganisationName);
|
||||
|
||||
// Query items.
|
||||
using (DbResultSet resultSet = AccountMgr.ExecuteUserOrganisationQuery(columns, prmUserOrganisation))
|
||||
{
|
||||
while (resultSet != null && resultSet.HasRows && resultSet.NextRecord())
|
||||
{
|
||||
NamedValue.Map values = resultSet.GetRecordValues();
|
||||
SysId organisationId = new SysId(values.GetLong(colId.DataName));
|
||||
Sax.OrganisationCategory organisationCategory = (Sax.OrganisationCategory)OrganisationCategoryCodes.GetTypeForCode(values.GetString(colOrganisationCategory.DataName));
|
||||
Sax.OrganisationType organisationType = (Sax.OrganisationType)OrganisationTypeCodes.GetTypeForCode(values.GetString(colOrganisationType.DataName));
|
||||
ProfileOrganisationListData organisationData = new ProfileOrganisationListData()
|
||||
{
|
||||
Id = model.EncryptId(organisationId),
|
||||
Name = values.GetString(colOrganisationName.DataName),
|
||||
CategoryDesc = Localiser.GetOrganisationCategoryCaption(organisationCategory),
|
||||
TypeDesc = Localiser.GetOrganisationTypeCaption(organisationType),
|
||||
SportName = values.GetString(colOrganisationSportName.DataName),
|
||||
MemberCount = values.GetLong(colMemberCount.DataName),
|
||||
OpportunityCount = values.GetLong(colOpportunityCount.DataName)
|
||||
};
|
||||
// Primary region.
|
||||
organisationData.RegionPrimary.Name = values.GetString(colOrganisationRegionName.DataName);
|
||||
// Logo.
|
||||
if (values.GetLong(colLogoCount.DataName) > 0)
|
||||
organisationData.LogoUrl = GetOrganisationLogoLink(organisationId, false);
|
||||
// Roles.
|
||||
List<String> roleCodes = StringListUtil.Split(values.GetString(colRoleCodes.DataName), SaxUserOrganisation.UserOrgnisationRoleDelim);
|
||||
if (roleCodes.ContainsCI(OrganisationRoleCodes.GetCodeForType(Sax.OrganisationRole.Admin)))
|
||||
organisationData.Admin = true;
|
||||
if (roleCodes.ContainsCI(OrganisationRoleCodes.GetCodeForType(Sax.OrganisationRole.MemberAdmin)))
|
||||
organisationData.MemberAdmin = true;
|
||||
if (roleCodes.ContainsCI(OrganisationRoleCodes.GetCodeForType(Sax.OrganisationRole.OpportunityAdmin)))
|
||||
organisationData.OpportunitiyAdmin = true;
|
||||
if (roleCodes.ContainsCI(OrganisationRoleCodes.GetCodeForType(Sax.OrganisationRole.ScheduleAdmin)))
|
||||
organisationData.ScheduleAdmin = true;
|
||||
if (roleCodes.ContainsCI(OrganisationRoleCodes.GetCodeForType(Sax.OrganisationRole.ArticleAdmin)))
|
||||
organisationData.ArticleAdmin = true;
|
||||
responseData.Organisations.Add(organisationData);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (model.Paging.IsPaged)
|
||||
model.Paging.ItemCount = (ushort)responseData.Organisations.Count;
|
||||
|
||||
// Complete response.
|
||||
responseData.SetPaging(model);
|
||||
responseData.Success = true;
|
||||
return Json(responseData);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Account - Get Profile Organisation.
|
||||
//-------------------------------------------------------------------
|
||||
private class AjaxResponse_ProfileOrganisation : AjaxResponse_Data
|
||||
{
|
||||
// Construction.
|
||||
public AjaxResponse_ProfileOrganisation(SaxModel_Online model) : base(model) { }
|
||||
// Reference data.
|
||||
public List<AjaxResponse_Data.ItemCodeDesc> Categories { get; } = new List<ItemCodeDesc>();
|
||||
public List<AjaxResponse_Data.ItemCodeDesc> Types { get; } = new List<ItemCodeDesc>();
|
||||
// Organisation list.
|
||||
public ProfileOrganisationItemData Organisation { get; set; }
|
||||
}
|
||||
// Ajax request.
|
||||
[HttpPost]
|
||||
[Route("Account/Ajax/GetProfileOrganisation")]
|
||||
public IActionResult GetProfileOrganisation(Model_Account model)
|
||||
{
|
||||
String fn = GetType().Name + ".GetProfileOrganisation";
|
||||
AjaxResponse_ProfileOrganisation responseData = new AjaxResponse_ProfileOrganisation(model);
|
||||
String messageTitle = Localiser["label.organisation"];
|
||||
|
||||
// Validate session and referrer.
|
||||
if (!ValidReferer) return Forbid();
|
||||
if (!ValidUserSession) return GetAjaxResult_InvalidSession(responseData);
|
||||
RefreshModel(model);
|
||||
|
||||
// Record disposable items as they are created so all can be disposed when needed.
|
||||
using (DisposableCollection<IDisposable> disposableItems = new DisposableCollection<IDisposable>())
|
||||
{
|
||||
|
||||
// Identify item.
|
||||
SysId organisationId = model.ExtractSysId(model.Organisation.Id);
|
||||
if (!SysId.IsValid(organisationId))
|
||||
return Json(responseData.SetPopupMessage(messageTitle, Localiser["msg.error.item.id.not.specified"]));
|
||||
|
||||
// Retrieve item.
|
||||
SaxOrganisation organisation = AccountMgr.GetOrganisationById(organisationId);
|
||||
disposableItems.Add(organisation);
|
||||
if (organisation == null)
|
||||
{
|
||||
SaLogger.Warn(fn + " Failed to retrieve Organisation for Id: " + organisationId.ToString());
|
||||
return Json(responseData.SetPopupMessage(messageTitle, Localiser["msg.error.item.id.not.found"]));
|
||||
}
|
||||
|
||||
// Organisation address.
|
||||
SaxItemAddress address = ItemDataMgr.GetFirstItemAddressByItemAndType(organisation.GetItemId());
|
||||
disposableItems.Add(address);
|
||||
|
||||
// Check whether user is a member of this organisation.
|
||||
SaxUserOrganisation userOrganisation = AccountMgr.GetUserOrganisationByUserOrganisation(SessionUserAccountId, organisationId);
|
||||
disposableItems.Add(userOrganisation);
|
||||
if (userOrganisation != null)
|
||||
{
|
||||
// Make a note of the selected Organisation.
|
||||
SessionData_Online.Filter.SetMemberOrganisation(organisation);
|
||||
}
|
||||
|
||||
// Construct response.
|
||||
responseData.Organisation = new ProfileOrganisationItemData();
|
||||
PopulateOrganisationResponseItemData(model, organisation, userOrganisation, address, responseData.Organisation);
|
||||
|
||||
// Reference data.
|
||||
foreach (TypeCodeDesc organisationCategory in OrganisationCategoryCodes)
|
||||
{
|
||||
// Categories only include Partner/Other if selected organisation has that category.
|
||||
if (organisationCategory.Type != (int)organisation.OrganisationCategory && organisationCategory.Type.In(new[] { (int)Sax.OrganisationCategory.Partner, (int)Sax.OrganisationCategory.Other }))
|
||||
continue;
|
||||
responseData.Categories.Add(new AjaxResponse_Data.ItemCodeDesc() { Code = organisationCategory.Code, Desc = Localiser.GetOrganisationCategoryCaption((Sax.OrganisationCategory)organisationCategory.Type) });
|
||||
}
|
||||
foreach (TypeCodeDesc organisationType in OrganisationTypeCodes)
|
||||
{
|
||||
responseData.Types.Add(new AjaxResponse_Data.ItemCodeDesc() { Code = organisationType.Code, Desc = Localiser.GetOrganisationTypeCaption((Sax.OrganisationType)organisationType.Type) });
|
||||
}
|
||||
}
|
||||
|
||||
// Complete response.
|
||||
responseData.Success = true;
|
||||
return Json(responseData);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Account - Store Profile Organisation.
|
||||
//-------------------------------------------------------------------
|
||||
private class AjaxResponse_StoreProfileOrganisation : AjaxResponse_Data
|
||||
{
|
||||
// Construction.
|
||||
public AjaxResponse_StoreProfileOrganisation(SaxModel_Online model) : base(model) { }
|
||||
// Organisation list.
|
||||
public ProfileOrganisationItemData Organisation { get; set; }
|
||||
}
|
||||
// Ajax request.
|
||||
[HttpPost]
|
||||
[Route("Account/Ajax/StoreProfileOrganisation")]
|
||||
public IActionResult StoreProfileOrganisation(Model_Account model)
|
||||
{
|
||||
String fn = GetType().Name + ".StoreProfileOrganisation";
|
||||
AjaxResponse_StoreProfileOrganisation responseData = new AjaxResponse_StoreProfileOrganisation(model);
|
||||
String messageTitle = Localiser["label.organisation"];
|
||||
|
||||
// Validate session and referrer.
|
||||
if (!ValidReferer) return Forbid();
|
||||
if (!ValidUserSession) return GetAjaxResult_InvalidSession(responseData);
|
||||
RefreshModel(model);
|
||||
|
||||
// Record disposable items as they are created so all can be disposed when needed.
|
||||
using (DisposableCollection<IDisposable> disposableItems = new DisposableCollection<IDisposable>())
|
||||
{
|
||||
|
||||
// Retrieve organisation.
|
||||
SysId organisationId = model.ExtractSysId(model.Organisation.Id);
|
||||
if (!SysId.IsValid(organisationId))
|
||||
return Json(responseData.SetPopupMessage(messageTitle, Localiser["msg.error.item.id.not.specified"]));
|
||||
SaxOrganisation organisation = AccountMgr.GetOrganisationById(organisationId);
|
||||
disposableItems.Add(organisation);
|
||||
if (organisation == null)
|
||||
{
|
||||
SaLogger.Warn(fn + " Failed to retrieve Organisation for Id: " + organisationId.ToString() + ". " + GetLogSuffix());
|
||||
return Json(responseData.SetPopupMessage(messageTitle, Localiser["msg.error.item.id.not.found"]));
|
||||
}
|
||||
|
||||
// Organisation address.
|
||||
SaxItemAddress organisationAddress = ItemDataMgr.GetFirstItemAddressByItemAndType(organisation.GetItemId());
|
||||
disposableItems.Add(organisationAddress);
|
||||
if (!StringUtil.IsEmpty(model.Organisation.Address.Id))
|
||||
{
|
||||
// Validate supplied Address Id.
|
||||
SysId organisationAddressId = model.ExtractSysId(model.Organisation.Address.Id);
|
||||
if (organisationAddress != null)
|
||||
{
|
||||
if (!organisationAddress.Id.Equals(organisationAddressId))
|
||||
{
|
||||
SaLogger.Warn(fn + " Organisation Address Id mismatch. Supplied: " + organisationAddressId + ". Found: " + organisationAddress.Id + ". " + GetLogSuffix());
|
||||
return Json(responseData.SetGoHome(messageTitle, Localiser["msg.error.system"]));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
SaLogger.Warn(fn + " Organisation Address Id supplied (" + organisationAddressId + ") but no address found for Organisation. " + GetLogSuffix());
|
||||
return Json(responseData.SetGoHome(messageTitle, Localiser["msg.error.system"]));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Address Id not supplied.
|
||||
if (organisationAddress == null)
|
||||
{
|
||||
organisationAddress = ItemDataMgr.CreateItemAddress(organisation.GetItemId(), SaxItemAddress.DefaultOrganisationAddressType);
|
||||
disposableItems.Add(organisationAddress);
|
||||
}
|
||||
else if (!organisationAddress.IsStatusDeleted)
|
||||
{
|
||||
SaLogger.Warn(fn + " Organisation Address Id not supplied but no address found for Organisation. Id: " + organisationAddress.Id + ". " + GetLogSuffix());
|
||||
return Json(responseData.SetGoHome(messageTitle, Localiser["msg.error.system"]));
|
||||
}
|
||||
}
|
||||
|
||||
// Check whether user is a member of this organisation.
|
||||
SaxUserOrganisation userOrganisation = AccountMgr.GetUserOrganisationByUserOrganisation(SessionUserAccountId, organisationId);
|
||||
disposableItems.Add(userOrganisation);
|
||||
if (userOrganisation == null)
|
||||
{
|
||||
SaLogger.Warn(fn + " Account: " + SessionData.User.EmailAddress + ". OrganisationId: " + organisationId.ToString() + ". User Organisation not found. " + GetLogSuffix());
|
||||
return Json(responseData.SetGoHome(messageTitle, Localiser["msg.error.system"]));
|
||||
}
|
||||
if (!userOrganisation.GetOrganisationRoles().Contains(Sax.OrganisationRole.Admin))
|
||||
{
|
||||
SaLogger.Warn(fn + " Account: " + SessionData.User.EmailAddress + ". OrganisationId: " + organisationId.ToString() + ". User does not have Admin role to update organisation. " + GetLogSuffix());
|
||||
return Json(responseData.SetGoHome(messageTitle, Localiser["msg.error.system"]));
|
||||
}
|
||||
|
||||
// Validate organisation data.
|
||||
model.ValidateProfileOrganisationData(responseData);
|
||||
if (responseData.HasControlErrors())
|
||||
return Json(responseData);
|
||||
|
||||
// Regions.
|
||||
SysId regionIdCountry = model.ExtractSysId(model.Organisation.RegionIdPrimary);
|
||||
SaxRegion.Data regionCountry = Internals.GetRegion(regionIdCountry);
|
||||
if (SysId.IsValid(regionIdCountry) && regionCountry == null)
|
||||
{
|
||||
SaLogger.Warn(fn + " Country region not found. Id: " + model.Organisation.RegionIdPrimary + ". " + GetLogSuffix());
|
||||
return Json(responseData.SetGoHome(messageTitle, Localiser["msg.error.system"]));
|
||||
}
|
||||
SysId regionIdAddressProvince = model.ExtractSysId(model.Organisation.Address.RegionIdProvince);
|
||||
SaxRegion.Data regionProvince = Internals.GetRegion(regionIdAddressProvince);
|
||||
if (SysId.IsValid(regionIdAddressProvince) && regionProvince == null)
|
||||
{
|
||||
SaLogger.Warn(fn + " Province region not found. Id: " + model.Organisation.Address.RegionIdProvince + ". " + GetLogSuffix());
|
||||
return Json(responseData.SetGoHome(messageTitle, Localiser["msg.error.system"]));
|
||||
}
|
||||
|
||||
// Update organisation.
|
||||
if (model.Organisation.Name != null)
|
||||
organisation.Name = model.Organisation.Name;
|
||||
if (model.Organisation.Type != null)
|
||||
organisation.OrganisationType = model.Organisation.GetOrganisationType();
|
||||
if (model.Organisation.Category != null)
|
||||
organisation.OrganisationCategory = model.Organisation.GetOrganisationCategory();
|
||||
if (model.Organisation.SportId != null)
|
||||
organisation.SportIdPrimary = model.ExtractSysId(model.Organisation.SportId);
|
||||
if (model.Organisation.RegionIdPrimary != null)
|
||||
organisation.RegionIdPrimary = model.ExtractSysId(model.Organisation.RegionIdPrimary);
|
||||
if (model.Organisation.About != null)
|
||||
organisation.About = model.Organisation.About;
|
||||
if (model.Organisation.Facilities != null)
|
||||
organisation.Facilities = model.Organisation.Facilities;
|
||||
if (model.Organisation.ContactData != null)
|
||||
organisation.ContactData = model.Organisation.ContactData.GetContactData();
|
||||
if (!AccountMgr.UpdateOrganisation(organisation, DbUpdateInfo))
|
||||
{
|
||||
SaLogger.Warn(fn + " Failed to update organisation - " + AccountMgr.ErrorStateMessage);
|
||||
return Json(responseData.SetGoHome(messageTitle, Localiser["msg.error.system"]));
|
||||
}
|
||||
|
||||
// Store address.
|
||||
if (model.Organisation.Address.IsSpecified())
|
||||
{
|
||||
// The form includes address fields.
|
||||
if (model.Organisation.Address.IsPopulated())
|
||||
{
|
||||
// At least one address field has been populated.
|
||||
if (model.Organisation.Address.Line1 != null)
|
||||
organisationAddress.Line1 = model.Organisation.Address.Line1;
|
||||
if (model.Organisation.Address.Line2 != null)
|
||||
organisationAddress.Line2 = model.Organisation.Address.Line2;
|
||||
if (model.Organisation.Address.Line3 != null)
|
||||
organisationAddress.Line3 = model.Organisation.Address.Line3;
|
||||
if (model.Organisation.Address.Town != null)
|
||||
organisationAddress.Town = model.Organisation.Address.Town;
|
||||
if (regionProvince != null)
|
||||
{
|
||||
organisationAddress.Province = regionProvince.Name;
|
||||
organisationAddress.RegionIdProvince = regionProvince.Id;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (model.Organisation.Address.Province != null)
|
||||
organisationAddress.Province = model.Organisation.Address.Province;
|
||||
}
|
||||
if (regionCountry != null)
|
||||
{
|
||||
organisationAddress.Country = regionCountry.Name;
|
||||
organisationAddress.RegionIdCountry = regionCountry.Id;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (model.Organisation.Address.Country != null)
|
||||
organisationAddress.Country = model.Organisation.Address.Country;
|
||||
}
|
||||
organisationAddress.PostalCode = model.Organisation.Address.PostalCode;
|
||||
organisationAddress.Status = SaxItemAddress.DefaultStatus;
|
||||
|
||||
// Store address.
|
||||
if (!SysId.IsValid(organisationAddress.Id))
|
||||
{
|
||||
// Create new address.
|
||||
if (!ItemDataMgr.InsertItemAddress(organisationAddress, DbUpdateInfo))
|
||||
{
|
||||
SaLogger.Warn(fn + " Failed to insert organisation address - " + ItemDataMgr.ErrorStateMessage);
|
||||
return Json(responseData.SetGoHome(messageTitle, Localiser["msg.error.system"]));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Update existing address.
|
||||
if (!ItemDataMgr.UpdateItemAddress(organisationAddress, DbUpdateInfo))
|
||||
{
|
||||
SaLogger.Warn(fn + " Failed to update organisation address - " + ItemDataMgr.ErrorStateMessage);
|
||||
return Json(responseData.SetGoHome(messageTitle, Localiser["msg.error.system"]));
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Address not specified - delete it.
|
||||
if (!ItemDataMgr.DeleteItemAddress(organisationAddress, DbUpdateInfo))
|
||||
{
|
||||
SaLogger.Warn(fn + " Failed to delete organisation address - " + ItemDataMgr.ErrorStateMessage);
|
||||
return Json(responseData.SetGoHome(messageTitle, Localiser["msg.error.system"]));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Construct response.
|
||||
responseData.Organisation = new ProfileOrganisationItemData();
|
||||
PopulateOrganisationResponseItemData(model, organisation, userOrganisation, organisationAddress, responseData.Organisation);
|
||||
}
|
||||
|
||||
// Complete response.
|
||||
responseData.Success = true;
|
||||
return Json(responseData);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
}
|
||||
//=======================================================================
|
||||
}
|
||||
@@ -0,0 +1,426 @@
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Saxonite.Net.Core.Web.Online.Models;
|
||||
using Saxonite.Net.Core.Web.Base.App;
|
||||
using Saxonite.Net.Core.Web.Base.Controllers;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Saxonite.Net.Standard.Base.Bus;
|
||||
using Sarand.Net.Standard.Base.App;
|
||||
using Sarand.Net.Standard.Base.Bus;
|
||||
using Sarand.Net.Standard.Base.Utils;
|
||||
using Sarand.Net.Standard.Base.Core;
|
||||
using Sarand.Net.Standard.Base.Dbas;
|
||||
using Saxonite.Net.Standard.Base.App;
|
||||
using static Saxonite.Net.Standard.Base.App.Sax.Config;
|
||||
using static Saxonite.Net.Standard.Base.Bus.SaxArticle;
|
||||
|
||||
namespace Saxonite.Net.Core.Web.Online.Controllers
|
||||
{
|
||||
//=======================================================================
|
||||
// Online Account Controller - Sports - Ajax actions.
|
||||
//=======================================================================
|
||||
partial class AccountController
|
||||
{
|
||||
//-------------------------------------------------------------------
|
||||
// Data definitions.
|
||||
private class ProfileSportResponseListData : AjaxResponse_Data.ItemData_Base
|
||||
{
|
||||
public String SportId { get; set; }
|
||||
public String SportName { get; set; }
|
||||
public String SportSpecialityLabel { get; set; }
|
||||
public String SportParticipating { get; set; }
|
||||
public String SportPreparing { get; set; }
|
||||
public String SportOfficiating { get; set; }
|
||||
}
|
||||
private class ProfileSportResponseItemData : ProfileSportResponseListData
|
||||
{
|
||||
public String SportAbout { get; set; }
|
||||
public List<SportContactData> Contacts { get; set; }
|
||||
public String SportParticipatingCode { get; set; }
|
||||
public String SportPreparingCode { get; set; }
|
||||
public String SportOfficiatingCode { get; set; }
|
||||
}
|
||||
public class SportContactData
|
||||
{
|
||||
public String ContactType { get; set; }
|
||||
public String ContactTypeDesc { get; set; }
|
||||
public String Title { get; set; }
|
||||
public String FirstName { get; set; }
|
||||
public String LastName { get; set; }
|
||||
public String EmailAddress { get; set; }
|
||||
public String Phone { get; set; }
|
||||
}
|
||||
private void PopulateProfileSportResponseListData(Model_Account model, SaxUserSport userSport, SaxSport sport, ProfileSportResponseListData data)
|
||||
{
|
||||
data.Id = model.EncryptId(userSport.Id);
|
||||
data.SportId = model.GetEncryptedSportId(userSport.SportId);
|
||||
data.SportName = sport.Name;
|
||||
data.SportSpecialityLabel = model.GetSportSpecialityLabel(userSport.SportId);
|
||||
data.SportParticipating = Localiser.GetSportParticipatingCaption(userSport.Participating);
|
||||
data.SportPreparing = Localiser.GetSportPreparingCaption(userSport.Preparing);
|
||||
data.SportOfficiating = Localiser.GetSportOfficiatingCaption(userSport.Officiating);
|
||||
}
|
||||
private void PopulateProfileSportResponseItemData(Model_Account model, SaxUserSport userSport, SaxSport sport, ProfileSportResponseItemData data)
|
||||
{
|
||||
PopulateProfileSportResponseListData(model, userSport, sport, data);
|
||||
data.SportAbout = userSport.About;
|
||||
// Sport Contacts.
|
||||
SaxSportContactsData sportContacts = new SaxSportContactsData(userSport.ContactsData);
|
||||
foreach (Sax.SportContactType contactType in sportContacts.ContactTypes)
|
||||
{
|
||||
if (data.Contacts == null) data.Contacts = new List<SportContactData>();
|
||||
SportContactData sportContact =
|
||||
new SportContactData()
|
||||
{
|
||||
ContactType = SportContactTypeCodes.GetCodeForType(contactType),
|
||||
ContactTypeDesc = Localiser.GetSportContactTypeCaption(contactType),
|
||||
Title = sportContacts.GetContactTitle(contactType),
|
||||
FirstName = sportContacts.GetContactFirstName(contactType),
|
||||
LastName = sportContacts.GetContactLastName(contactType),
|
||||
EmailAddress = sportContacts.GetContactEmailAddress(contactType),
|
||||
Phone = sportContacts.GetContactPhone(contactType),
|
||||
};
|
||||
data.Contacts.Add(sportContact);
|
||||
}
|
||||
data.SportParticipatingCode = SportParticipatingCodes.GetCodeForType(userSport.Participating);
|
||||
data.SportPreparingCode = SportPreparingCodes.GetCodeForType(userSport.Preparing);
|
||||
data.SportOfficiatingCode = SportOfficiatingCodes.GetCodeForType(userSport.Officiating);
|
||||
data.CreatedOnFmt = model.FormatDateForDisplay(userSport.CreateStamp.On);
|
||||
data.StatusCode = userSport.StatusCode;
|
||||
data.StatusDesc = userSport.StatusDesc;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Account - Get Profile Sports.
|
||||
//-------------------------------------------------------------------
|
||||
private class AjaxResponse_ProfileSportsData : AjaxResponse_Data
|
||||
{
|
||||
// Construction.
|
||||
public AjaxResponse_ProfileSportsData(SaxModel_Online model) : base(model) { }
|
||||
// Reference data.
|
||||
public List<ItemCodeDesc> ContactTypes { get; } = new List<ItemCodeDesc>();
|
||||
public List<ItemCodeDesc> Titles { get; } = new List<ItemCodeDesc>();
|
||||
// Sport list.
|
||||
public List<ProfileSportResponseListData> Sports { get; } = new List<ProfileSportResponseListData>();
|
||||
}
|
||||
// Ajax request.
|
||||
[HttpPost]
|
||||
[Route("Account/Ajax/GetProfileSports")]
|
||||
public IActionResult GetProfileSports(Model_Account model)
|
||||
{
|
||||
String fn = GetType().Name + ".GetProfileSports";
|
||||
AjaxResponse_ProfileSportsData responseData = new AjaxResponse_ProfileSportsData(model);
|
||||
String messageTitle = Localiser["account.caption.profile.sports"];
|
||||
|
||||
// Validate session and referrer.
|
||||
if (!ValidReferer) return Forbid();
|
||||
if (!ValidUserSession) return GetAjaxResult_InvalidSession(responseData);
|
||||
RefreshModel(model);
|
||||
|
||||
// Reference data - Contact types.
|
||||
List<Sax.SportContactType> validContactTypes = new List<Sax.SportContactType>(EnumUtil.GetValues<Sax.SportContactType>());
|
||||
foreach (TypeCodeDesc contactType in SportContactTypeCodes)
|
||||
{
|
||||
if (!validContactTypes.Contains((Sax.SportContactType)contactType.Type)) continue;
|
||||
responseData.ContactTypes.Add(new AjaxResponse_Data.ItemCodeDesc() { Code = contactType.Code, Desc = Localiser.GetSportContactTypeCaption((Sax.SportContactType)contactType.Type) });
|
||||
}
|
||||
|
||||
// Reference data - Titles.
|
||||
foreach (var title in model.TitlesForSelect)
|
||||
responseData.Titles.Add(new AjaxResponse_Data.ItemCodeDesc() { Code = title.Value, Desc = title.Text });
|
||||
|
||||
// Item filter.
|
||||
SaxUserSport.Params prmUserSport = new SaxUserSport.Params();
|
||||
prmUserSport.UserAccountIdsIncluded.Add(SessionUserAccountId);
|
||||
prmUserSport.StatusCat = SaxUserSport.StatusCat.NotDeleted;
|
||||
model.Paging.ItemTotal = (ulong)AccountMgr.GetUserSportCount(prmUserSport);
|
||||
model.PopulatePagingTo(prmUserSport.ResultsPaging);
|
||||
|
||||
// Item columns.
|
||||
ColumnDfn colId = AccountMgr.GetUserSportColumnDfn(SaxUserSport.Column.Id);
|
||||
ColumnDfn colSportId = AccountMgr.GetUserSportColumnDfn(SaxUserSport.Column.SportId);
|
||||
ColumnDfn colSportName = AccountMgr.GetUserSportColumnDfn(SaxUserSport.Column.Sport_Name);
|
||||
ColumnDfn colParticipating = AccountMgr.GetUserSportColumnDfn(SaxUserSport.Column.SportParticipating);
|
||||
ColumnDfn colPreparing = AccountMgr.GetUserSportColumnDfn(SaxUserSport.Column.SportPreparing);
|
||||
ColumnDfn colOfficiating = AccountMgr.GetUserSportColumnDfn(SaxUserSport.Column.SportOfficiating);
|
||||
ColumnDfn colStatus = AccountMgr.GetUserSportColumnDfn(SaxUserSport.Column.Status);
|
||||
List<ColumnDfn> columns = new List<ColumnDfn>()
|
||||
{
|
||||
colId,
|
||||
colSportId, colSportName,
|
||||
colParticipating, colPreparing, colOfficiating,
|
||||
colStatus,
|
||||
};
|
||||
|
||||
// Sort columns.
|
||||
prmUserSport.SortColumns.Add(colSportName);
|
||||
|
||||
// Query items.
|
||||
using (DbResultSet resultSet = AccountMgr.ExecuteUserSportQuery(columns, prmUserSport))
|
||||
{
|
||||
while (resultSet != null && resultSet.HasRows && resultSet.NextRecord())
|
||||
{
|
||||
NamedValue.Map values = resultSet.GetRecordValues();
|
||||
SysId sportId = new SysId(values.GetLong(colSportId.DataName));
|
||||
ProfileSportResponseListData userSportData = new ProfileSportResponseListData()
|
||||
{
|
||||
Id = model.EncryptId(new SysId(values.GetLong(colId.DataName))),
|
||||
SportId = model.GetEncryptedSportId(sportId),
|
||||
SportName = values.GetString(colSportName.DataName),
|
||||
SportSpecialityLabel = model.GetSportSpecialityLabel(sportId),
|
||||
SportParticipating = Localiser.GetSportParticipatingCaption((Sax.SportParticipating)values.GetLong(colParticipating.DataName)),
|
||||
SportPreparing = Localiser.GetSportPreparingCaption((Sax.SportPreparing)values.GetLong(colPreparing.DataName)),
|
||||
SportOfficiating = Localiser.GetSportOfficiatingCaption((Sax.SportOfficiating)values.GetLong(colOfficiating.DataName)),
|
||||
StatusCode = values.GetString(colStatus.DataName),
|
||||
StatusDesc = SacsSystem.GetStatusDescForCode(values.GetString(colStatus.DataName))
|
||||
};
|
||||
responseData.Sports.Add(userSportData);
|
||||
}
|
||||
}
|
||||
if (model.Paging.IsPaged)
|
||||
model.Paging.ItemCount = (ushort)responseData.Sports.Count;
|
||||
|
||||
// Complete response.
|
||||
responseData.SetPaging(model);
|
||||
responseData.Success = true;
|
||||
return Json(responseData);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Get Profile Sport ajax request.
|
||||
//-------------------------------------------------------------------
|
||||
private class AjaxResponse_ProfileSport : AjaxResponse_Data
|
||||
{
|
||||
// Construction.
|
||||
public AjaxResponse_ProfileSport(SaxModel_Online model) : base(model) { }
|
||||
// Sport details.
|
||||
public ProfileSportResponseItemData Sport { get; } = new ProfileSportResponseItemData();
|
||||
}
|
||||
//-------------------------------------------------------------------
|
||||
[HttpPost]
|
||||
[Route("Account/Ajax/GetProfileSport")]
|
||||
public IActionResult Ajax_GetProfileSport(Model_Account model)
|
||||
{
|
||||
String fn = GetType().Name + ".Ajax_GetProfileSport";
|
||||
String messageTitle = Localiser["account.caption.profile.sport"];
|
||||
AjaxResponse_ProfileSport responseData = new AjaxResponse_ProfileSport(model);
|
||||
|
||||
// Validate session and referrer.
|
||||
if (!ValidReferer) return Forbid();
|
||||
if (!ValidUserSession) return GetAjaxResult_InvalidSession(responseData);
|
||||
RefreshModel(model);
|
||||
|
||||
// Record disposable items as they are created so all can be disposed when needed.
|
||||
using (DisposableCollection<IDisposable> disposableItems = new DisposableCollection<IDisposable>())
|
||||
{
|
||||
|
||||
// Identify item.
|
||||
SysId userSportId = model.ExtractSysId(model.UserSportId);
|
||||
if (!SysId.IsValid(userSportId))
|
||||
return Json(responseData.SetPopupMessage(messageTitle, Localiser["msg.error.item.id.not.specified"]));
|
||||
|
||||
// Retrieve item.
|
||||
SaxUserSport userSport = AccountMgr.GetUserSportById(userSportId);
|
||||
disposableItems.Add(userSport);
|
||||
if (userSport == null)
|
||||
{
|
||||
SaLogger.Warn(fn + " Failed to retrieve User Sport for Id: '" + model.UserSportId + "'");
|
||||
return Json(responseData.SetPopupMessage(messageTitle, Localiser["msg.error.item.id.not.found"]));
|
||||
}
|
||||
|
||||
// Retrieve sport.
|
||||
SaxSport sport = ReferenceMgr.GetSportById(userSport.SportId);
|
||||
disposableItems.Add(sport);
|
||||
if (sport == null)
|
||||
{
|
||||
SaLogger.Warn(fn + " Failed to retrieve Sport for Id: '" + userSport.SportId + "'");
|
||||
return Json(responseData.SetPopupMessage(messageTitle, Localiser["msg.error.item.id.not.found"]));
|
||||
}
|
||||
|
||||
// Construct response.
|
||||
PopulateProfileSportResponseItemData(model, userSport, sport, responseData.Sport);
|
||||
responseData.Success = true;
|
||||
}
|
||||
return Json(responseData);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Validate Profile Sport Contact ajax request.
|
||||
//-------------------------------------------------------------------
|
||||
private class AjaxResponse_ProfileSportContact : AjaxResponse_Data
|
||||
{
|
||||
// Construction.
|
||||
public AjaxResponse_ProfileSportContact(SaxModel_Online model) : base(model) { }
|
||||
}
|
||||
[HttpPost]
|
||||
[Route("Account/Ajax/ValidateProfileSportContact")]
|
||||
public IActionResult Ajax_ValidateProfileSportContact(Model_UserSportContact model)
|
||||
{
|
||||
String fn = GetType().Name + ".Ajax_ValidateProfileSportContact";
|
||||
String messageTitle = Localiser["account.caption.profile.sport.contact"];
|
||||
AjaxResponse_ProfileSportContact responseData = new AjaxResponse_ProfileSportContact(model);
|
||||
|
||||
// Validate session and referrer.
|
||||
if (!ValidReferer) return Forbid();
|
||||
if (!ValidUserSession) return GetAjaxResult_InvalidSession(responseData);
|
||||
RefreshModel(model);
|
||||
|
||||
// Record disposable items as they are created so all can be disposed when needed.
|
||||
using (DisposableCollection<IDisposable> disposableItems = new DisposableCollection<IDisposable>())
|
||||
{
|
||||
|
||||
// Validate item properties.
|
||||
model.ValidateUserSportContactData(responseData);
|
||||
if (responseData.HasControlErrors())
|
||||
return Json(responseData);
|
||||
|
||||
// Construct response.
|
||||
responseData.Success = true;
|
||||
}
|
||||
return Json(responseData);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Store Profile Sport ajax request.
|
||||
//-------------------------------------------------------------------
|
||||
[HttpPost]
|
||||
[Route("Account/Ajax/StoreProfileSport")]
|
||||
public IActionResult Ajax_StoreProfileSport(Model_Account model)
|
||||
{
|
||||
String fn = GetType().Name + ".Ajax_StoreProfileSport";
|
||||
String messageTitle = Localiser["account.caption.profile.sport"];
|
||||
AjaxResponse_ProfileSport responseData = new AjaxResponse_ProfileSport(model);
|
||||
|
||||
// Validate session and referrer.
|
||||
if (!ValidReferer) return Forbid();
|
||||
if (!ValidUserSession) return GetAjaxResult_InvalidSession(responseData);
|
||||
RefreshModel(model);
|
||||
|
||||
// Record disposable items as they are created so all can be disposed when needed.
|
||||
using (DisposableCollection<IDisposable> disposableItems = new DisposableCollection<IDisposable>())
|
||||
{
|
||||
|
||||
// Validate item properties.
|
||||
model.ValidateProfileSportData(responseData);
|
||||
if (responseData.HasControlErrors())
|
||||
return Json(responseData);
|
||||
|
||||
// Validate Profile Sport Id against 'Exists' flag.
|
||||
SysId userSportId = model.ExtractSysId(model.UserSportId);
|
||||
bool profileSportExists = StringUtil.ToBool(model.ProfileSportExists);
|
||||
if (profileSportExists && !SysId.IsValid(userSportId))
|
||||
{
|
||||
SaLogger.Warn(fn + " Id not specified for existing Profile Sport.");
|
||||
return Json(responseData.SetGoHome(messageTitle, Localiser["msg.error.system"]));
|
||||
}
|
||||
if (!profileSportExists && SysId.IsValid(userSportId))
|
||||
{
|
||||
SaLogger.Warn(fn + " Id specified for new Profile Sport: '" + model.UserSportId + "'");
|
||||
return Json(responseData.SetGoHome(messageTitle, Localiser["msg.error.system"]));
|
||||
}
|
||||
|
||||
// Retrieve the sport.
|
||||
SysId sportId = model.ExtractSysId(model.ProfileSportId);
|
||||
SaxSport sport = ReferenceMgr.GetSportById(sportId);
|
||||
disposableItems.Add(sport);
|
||||
if (sport == null)
|
||||
{
|
||||
SaLogger.Warn(fn + " Failed to retrieve Sport for Id: " + sportId);
|
||||
return Json(responseData.SetGoHome(messageTitle, Localiser["msg.error.system"]));
|
||||
}
|
||||
|
||||
// Retrieve existing item.
|
||||
SaxUserSport userSport = AccountMgr.GetUserSportById(userSportId);
|
||||
disposableItems.Add(userSport);
|
||||
if (userSport == null && SysId.IsValid(userSportId))
|
||||
{
|
||||
SaLogger.Warn(fn + " Failed to retrieve User Sport for Id: '" + model.UserSportId + "'");
|
||||
return Json(responseData.SetPopupMessage(messageTitle, Localiser["msg.error.item.id.not.found"]));
|
||||
}
|
||||
// Validate user sport properties.
|
||||
if (userSport != null)
|
||||
{
|
||||
if (!userSport.SportId.Equals(sportId))
|
||||
{
|
||||
SaLogger.Warn(fn + " Inconsistent Sport Id specified for User Sport. Expected: " + userSport.SportId + ". Found: " + sportId);
|
||||
return Json(responseData.SetGoHome(messageTitle, Localiser["msg.error.system"]));
|
||||
}
|
||||
}
|
||||
|
||||
// If sport doesn't exist for the user, it may have been previously deleted.
|
||||
if (userSport == null)
|
||||
{
|
||||
SaxUserSport.Params prmUserSport = new SaxUserSport.Params();
|
||||
prmUserSport.UserAccountIdsIncluded.Add(SessionUserAccountId);
|
||||
prmUserSport.SportIdsIncluded.Add(sportId);
|
||||
prmUserSport.StatusCat = SaxUserSport.StatusCat.Any;
|
||||
userSport = AccountMgr.GetUserSport(prmUserSport);
|
||||
if (userSport != null)
|
||||
{
|
||||
disposableItems.Add(userSport);
|
||||
if (userSport.Status == SaStatus.Deleted)
|
||||
{
|
||||
SaLogger.Info(fn + " Resurrecting User Sport with status: " + userSport.StatusDesc + ". Id: " + SysId.ToString(userSport.Id));
|
||||
userSport.Status = SaxUserSport.DefaultStatus;
|
||||
}
|
||||
else
|
||||
{
|
||||
responseData.SetControlError(nameof(model.ProfileSportId), Localiser["msg.validation.duplicate.value"]);
|
||||
return Json(responseData);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
userSport = AccountMgr.CreateUserSport(SessionUserAccountId, sportId);
|
||||
disposableItems.Add(userSport);
|
||||
}
|
||||
}
|
||||
|
||||
// Populate item properties.
|
||||
if (model.ProfileSportAbout != null)
|
||||
userSport.About = model.ProfileSportAbout;
|
||||
if (model.Contacts.ContactsData != null)
|
||||
userSport.ContactsData = model.Contacts.ContactsData.ToXml();
|
||||
if (model.ProfileSportParticipatingCode != null)
|
||||
userSport.Participating = model.ProfileSportParticipating;
|
||||
if (model.ProfileSportPreparingCode != null)
|
||||
userSport.Preparing = model.ProfileSportPreparing;
|
||||
if (model.ProfileSportOfficiatingCode != null)
|
||||
userSport.Officiating = model.ProfileSportOfficiating;
|
||||
|
||||
// Store item.
|
||||
if (!SysId.IsValid(userSport.Id))
|
||||
{
|
||||
if (!AccountMgr.InsertUserSport(userSport, DbUpdateInfo))
|
||||
{
|
||||
SaLogger.Warn(fn + " Failed to insert user sport: " + AccountMgr.ErrorStateMessage);
|
||||
return Json(responseData.SetPopupMessage(messageTitle, Localiser["msg.error.item.insert.failed"]));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!AccountMgr.UpdateUserSport(userSport, DbUpdateInfo))
|
||||
{
|
||||
SaLogger.Warn(fn + " Failed to update user sport [Id:" + SysId.ToString(userSport.Id) + "]: " + AccountMgr.ErrorStateMessage);
|
||||
return Json(responseData.SetPopupMessage(messageTitle, Localiser["msg.error.item.update.failed"]));
|
||||
}
|
||||
}
|
||||
|
||||
// Refresh list of profile sports for Activity Index.
|
||||
RefreshSessionProfileSports();
|
||||
|
||||
// Construct response.
|
||||
PopulateProfileSportResponseItemData(model, userSport, sport, responseData.Sport);
|
||||
responseData.Success = true;
|
||||
}
|
||||
return Json(responseData);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
}
|
||||
//=======================================================================
|
||||
}
|
||||
+370
@@ -0,0 +1,370 @@
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Saxonite.Net.Core.Web.Online.Models;
|
||||
using Saxonite.Net.Core.Web.Base.App;
|
||||
using Saxonite.Net.Core.Web.Base.Controllers;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Saxonite.Net.Standard.Base.Bus;
|
||||
using Sarand.Net.Standard.Base.App;
|
||||
using Sarand.Net.Standard.Base.Bus;
|
||||
using Sarand.Net.Standard.Base.Utils;
|
||||
using Saxonite.Net.Standard.Base.App;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Sarand.Net.Standard.Base.Helpers;
|
||||
using System.IO;
|
||||
using System.Drawing;
|
||||
using Sarand.Net.Standard.Base.Core;
|
||||
using Sarand.Net.Standard.Base.Dbas;
|
||||
|
||||
namespace Saxonite.Net.Core.Web.Online.Controllers
|
||||
{
|
||||
//=======================================================================
|
||||
// Online Account Controller - User Sport Experience - Ajax actions.
|
||||
//=======================================================================
|
||||
partial class AccountController
|
||||
{
|
||||
//-------------------------------------------------------------------
|
||||
// Common response data.
|
||||
private class SportExperienceResponseListData : AjaxResponse_Data.ItemData_Base
|
||||
{
|
||||
public String UserSportId { get; set; }
|
||||
public String Period { get; set; }
|
||||
public String PeriodFrom { get; set; }
|
||||
public String PeriodTo { get; set; }
|
||||
public String OrganisationName { get; set; }
|
||||
public String Summary { get; set; }
|
||||
public String Team { get; set; }
|
||||
public String League { get; set; }
|
||||
public String Speciality { get; set; }
|
||||
// Regions.
|
||||
public String RegionCaptionNation { get; set; }
|
||||
public String RegionCaptionProvince { get; set; }
|
||||
public string RegionRepresentation { get; set; }
|
||||
}
|
||||
private class SportExperienceResponseItemData : SportExperienceResponseListData
|
||||
{
|
||||
public String PeriodFrom_YMD { get; set; }
|
||||
public String PeriodTo_YMD { get; set; }
|
||||
public String OrganisationId { get; set; }
|
||||
public String Awards { get; set; }
|
||||
public String RegionIdNation { get; set; }
|
||||
public String RegionIdProvince { get; set; }
|
||||
}
|
||||
private void PopulateSportExperienceResponseListData(Model_UserSportExperience model, SportExperienceResponseListData data, SaxUserSport userSport, SaxUserSportExperience userSportExperience)
|
||||
{
|
||||
data.Id = model.EncryptId(userSportExperience.Id);
|
||||
data.UserSportId = model.EncryptId(userSportExperience.UserSportId);
|
||||
data.PeriodFrom = model.FormatDateForForm(userSportExperience.PeriodFrom);
|
||||
data.PeriodTo = model.FormatDateForForm(userSportExperience.PeriodTo);
|
||||
data.OrganisationName = userSportExperience.OrganisationName;
|
||||
data.Summary = userSportExperience.Summary;
|
||||
data.Team = userSportExperience.Team;
|
||||
data.League = userSportExperience.League;
|
||||
data.Speciality = userSportExperience.Speciality;
|
||||
// Regions.
|
||||
data.RegionCaptionNation = Localiser.GetRegionName(Internals.GetRegion(userSportExperience.RegionIdNation));
|
||||
data.RegionCaptionProvince = Localiser.GetRegionName(Internals.GetRegion(userSportExperience.RegionIdProvince));
|
||||
List<String> locations = new List<string>() { data.RegionCaptionProvince, data.RegionCaptionNation };
|
||||
data.RegionRepresentation = locations.Concat(", ", "", "", true, true);
|
||||
}
|
||||
private void PopulateSportExperienceResponseItemData(Model_UserSportExperience model, SportExperienceResponseItemData data, SaxUserSport userSport, SaxUserSportExperience userSportExperience)
|
||||
{
|
||||
PopulateSportExperienceResponseListData(model, data, userSport, userSportExperience);
|
||||
data.PeriodFrom_YMD = DateUtil.FormatDateForJavascript(userSportExperience.PeriodFrom);
|
||||
data.PeriodTo_YMD = DateUtil.FormatDateForJavascript(userSportExperience.PeriodTo);
|
||||
data.Period = data.PeriodFrom + " - " + data.PeriodTo;
|
||||
data.OrganisationId = model.EncryptId(userSportExperience.OrganisationId);
|
||||
data.Awards = userSportExperience.Awards;
|
||||
// Regions.
|
||||
data.RegionIdNation = model.GetEncryptedRegionId(userSportExperience.RegionIdNation);
|
||||
data.RegionIdProvince = model.GetEncryptedRegionId(userSportExperience.RegionIdProvince);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Utilites.
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// User Sport - Get Experience list.
|
||||
//-------------------------------------------------------------------
|
||||
private class AjaxResponse_UserSportExperienceList : AjaxResponse_Data
|
||||
{
|
||||
// Construction.
|
||||
public AjaxResponse_UserSportExperienceList(SaxModel_Online model) : base(model) { }
|
||||
// Contact details.
|
||||
public List<SportExperienceResponseListData> Experiences { get; } = new List<SportExperienceResponseListData>();
|
||||
// Sport details.
|
||||
public class SportData
|
||||
{
|
||||
public class SpecialityData
|
||||
{
|
||||
public bool? NotRelevant { get; set; } = null;
|
||||
public String Label { get; set; }
|
||||
}
|
||||
public SpecialityData Speciality { get; } = new SpecialityData();
|
||||
}
|
||||
public SportData Sport { get; } = new SportData();
|
||||
}
|
||||
// Ajax request.
|
||||
[HttpPost]
|
||||
[Route("UserSport/Ajax/GetExperienceList")]
|
||||
public IActionResult GetUserSportExperienceList(Model_UserSportExperience model)
|
||||
{
|
||||
String fn = GetType().Name + ".GetUserSportExperienceList";
|
||||
AjaxResponse_UserSportExperienceList responseData = new AjaxResponse_UserSportExperienceList(model);
|
||||
String messageTitle = Localiser["account.caption.profile.sports"];
|
||||
|
||||
// Validate session and referrer.
|
||||
if (!ValidReferer) return Forbid();
|
||||
if (!ValidUserSession) return GetAjaxResult_InvalidSession(responseData);
|
||||
RefreshModel(model);
|
||||
|
||||
// Record disposable items as they are created so all can be disposed when needed.
|
||||
using (DisposableCollection<IDisposable> disposableItems = new DisposableCollection<IDisposable>())
|
||||
{
|
||||
// Validate User Sport Id against user account.
|
||||
SysId userSportId = model.ExtractSysId(model.UserSportId);
|
||||
SaxUserSport userSport = AccountMgr.GetUserSportById(userSportId);
|
||||
disposableItems.Add(userSport);
|
||||
if (userSport == null || !userSport.UserAccountId.Equals(SessionUserAccountId))
|
||||
return Json(responseData.SetGoHome(messageTitle, Localiser["msg.something.gone.wrong"]));
|
||||
|
||||
// Sport details.
|
||||
if (model.SportSpecialityNotRelevant(userSport.SportId)) responseData.Sport.Speciality.NotRelevant = true;
|
||||
responseData.Sport.Speciality.Label = model.GetSportSpecialityLabel(userSport.SportId);
|
||||
|
||||
// Columns.
|
||||
ColumnDfn colId = AccountMgr.GetUserSportExperienceColumnDfn(SaxUserSportExperience.Column.Id);
|
||||
ColumnDfn colUserSportId = AccountMgr.GetUserSportExperienceColumnDfn(SaxUserSportExperience.Column.UserSportId);
|
||||
ColumnDfn colPeriodFrom = AccountMgr.GetUserSportExperienceColumnDfn(SaxUserSportExperience.Column.PeriodFrom);
|
||||
ColumnDfn colPeriodTo = AccountMgr.GetUserSportExperienceColumnDfn(SaxUserSportExperience.Column.PeriodTo);
|
||||
ColumnDfn colOrganisationId = AccountMgr.GetUserSportExperienceColumnDfn(SaxUserSportExperience.Column.OrganisationId);
|
||||
ColumnDfn colOrganisationName = AccountMgr.GetUserSportExperienceColumnDfn(SaxUserSportExperience.Column.Organisation_Name);
|
||||
ColumnDfn colSummary = AccountMgr.GetUserSportExperienceColumnDfn(SaxUserSportExperience.Column.Summary);
|
||||
ColumnDfn colTeam = AccountMgr.GetUserSportExperienceColumnDfn(SaxUserSportExperience.Column.Team);
|
||||
ColumnDfn colLeague = AccountMgr.GetUserSportExperienceColumnDfn(SaxUserSportExperience.Column.League);
|
||||
ColumnDfn colSpeciality = AccountMgr.GetUserSportExperienceColumnDfn(SaxUserSportExperience.Column.Speciality);
|
||||
ColumnDfn colNotes = AccountMgr.GetUserSportExperienceColumnDfn(SaxUserSportExperience.Column.Notes);
|
||||
List<ColumnDfn> columnsToQuery = new List<ColumnDfn>()
|
||||
{
|
||||
colId, colUserSportId, colPeriodFrom, colPeriodTo,
|
||||
colOrganisationId, colOrganisationName,
|
||||
colSummary, colTeam, colLeague, colSpeciality, colNotes
|
||||
};
|
||||
|
||||
// Filter.
|
||||
SaxUserSportExperience.Params prmUserSportExperience = new SaxUserSportExperience.Params();
|
||||
prmUserSportExperience.UserSportIdsIncluded.Add(model.ExtractSysId(model.UserSportId));
|
||||
prmUserSportExperience.StatusCat = SaxUserSportExperience.StatusCat.NotDeleted;
|
||||
|
||||
// Sort columns.
|
||||
colPeriodFrom.SortAscending = false;
|
||||
prmUserSportExperience.SortColumns.Add(colPeriodFrom);
|
||||
|
||||
// Query items.
|
||||
using (DbResultSet resultSet = AccountMgr.ExecuteUserSportExperienceQuery(columnsToQuery, prmUserSportExperience))
|
||||
{
|
||||
while (resultSet != null && resultSet.HasRows && resultSet.NextRecord())
|
||||
{
|
||||
NamedValue.Map values = resultSet.GetRecordValues();
|
||||
SportExperienceResponseListData itemData = new SportExperienceResponseListData()
|
||||
{
|
||||
Id = model.EncryptId(new SysId(values.GetLong(colId.DataName))),
|
||||
UserSportId = model.EncryptId(new SysId(values.GetLong(colUserSportId.DataName))),
|
||||
PeriodFrom = model.FormatDateForForm(values.GetDate(colPeriodFrom.DataName)),
|
||||
PeriodTo = model.FormatDateForForm(values.GetDate(colPeriodTo.DataName)),
|
||||
OrganisationName = AccountMgr.GetUserSportExperienceDataValue(colOrganisationName, values).AsString(),
|
||||
Summary = values.GetString(colSummary.DataName),
|
||||
Team = values.GetString(colTeam.DataName),
|
||||
League = values.GetString(colLeague.DataName),
|
||||
Speciality = values.GetString(colSpeciality.DataName),
|
||||
};
|
||||
itemData.Period = itemData.PeriodFrom + " - " + itemData.PeriodTo;
|
||||
responseData.Experiences.Add(itemData);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Complete response.
|
||||
responseData.Success = true;
|
||||
return Json(responseData);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// User Sport - Get Experience.
|
||||
//-------------------------------------------------------------------
|
||||
private class AjaxResponse_UserSportExperienceData : AjaxResponse_Data
|
||||
{
|
||||
// Construction.
|
||||
public AjaxResponse_UserSportExperienceData(SaxModel_Online model) : base(model) { }
|
||||
// Contact details.
|
||||
public SportExperienceResponseItemData Experience { get; set; }
|
||||
}
|
||||
// Ajax request.
|
||||
[HttpPost]
|
||||
[Route("UserSport/Ajax/GetExperience")]
|
||||
public IActionResult GetUserSportExperience(Model_UserSportExperience model)
|
||||
{
|
||||
String fn = GetType().Name + ".GetUserSportExperience";
|
||||
AjaxResponse_UserSportExperienceData responseData = new AjaxResponse_UserSportExperienceData(model);
|
||||
String messageTitle = Localiser["account.caption.profile.sports"];
|
||||
|
||||
// Validate session and referrer.
|
||||
if (!ValidReferer) return Forbid();
|
||||
if (!ValidUserSession) return GetAjaxResult_InvalidSession(responseData);
|
||||
RefreshModel(model);
|
||||
|
||||
// Record disposable items as they are created so all can be disposed when needed.
|
||||
using (DisposableCollection<IDisposable> disposableItems = new DisposableCollection<IDisposable>())
|
||||
{
|
||||
// Validate User Sport Experience Id against user account.
|
||||
SysId userSportExperienceId = model.ExtractSysId(model.UserSportExperienceId);
|
||||
SaxUserSportExperience userSportExperience = AccountMgr.GetUserSportExperienceById(userSportExperienceId);
|
||||
disposableItems.Add(userSportExperience);
|
||||
SaxUserSport userSport = AccountMgr.GetUserSportById(userSportExperience?.UserSportId ?? null);
|
||||
disposableItems.Add(userSport);
|
||||
if (userSportExperience == null || userSport == null || !userSport.UserAccountId.Equals(SessionUserAccountId))
|
||||
return Json(responseData.SetGoHome(messageTitle, Localiser["msg.something.gone.wrong"]));
|
||||
|
||||
// Populate data to response.
|
||||
responseData.Experience = new SportExperienceResponseItemData();
|
||||
PopulateSportExperienceResponseItemData(model, responseData.Experience, userSport, userSportExperience);
|
||||
}
|
||||
|
||||
// Complete response.
|
||||
responseData.Success = true;
|
||||
return Json(responseData);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Account - Store User Sport Experience.
|
||||
//-------------------------------------------------------------------
|
||||
private class AjaxResponse_StoreUserSportExperience : AjaxResponse_Data
|
||||
{
|
||||
// Construction.
|
||||
public AjaxResponse_StoreUserSportExperience(SaxModel_Online model) : base(model) { }
|
||||
// Contact details.
|
||||
public SportExperienceResponseItemData Experience { get; set; }
|
||||
}
|
||||
// Ajax request.
|
||||
[HttpPost]
|
||||
[Route("UserSport/Ajax/StoreExperience")]
|
||||
public IActionResult StoreUserSportExperience(Model_UserSportExperience model)
|
||||
{
|
||||
String fn = GetType().Name + ".StoreUserSportExperience";
|
||||
AjaxResponse_StoreUserSportExperience responseData = new AjaxResponse_StoreUserSportExperience(model);
|
||||
String messageTitle = Localiser["account.caption.profile.sports"];
|
||||
|
||||
// Validate session and referrer.
|
||||
if (!ValidReferer) return Forbid();
|
||||
if (!ValidUserSession) return GetAjaxResult_InvalidSession(responseData);
|
||||
RefreshModel(model);
|
||||
|
||||
// Record disposable items as they are created so all can be disposed when needed.
|
||||
using (DisposableCollection<IDisposable> disposableItems = new DisposableCollection<IDisposable>())
|
||||
{
|
||||
// Validate data.
|
||||
model.ValidateProfileSportData(responseData);
|
||||
if (responseData.HasControlErrors())
|
||||
return Json(responseData);
|
||||
|
||||
// Validate User Sport Experience Id.
|
||||
SysId userSportExperienceId = model.ExtractSysId(model.UserSportExperienceId);
|
||||
if (SysId.IsValid(userSportExperienceId) != StringUtil.ToBool(model.UserSportExperienceExists))
|
||||
return Json(responseData.SetGoHome(messageTitle, Localiser["msg.something.gone.wrong"]));
|
||||
|
||||
// Retrieve User Sport Experience.
|
||||
SaxUserSportExperience userSportExperience = null;
|
||||
SaxUserSport userSport = null;
|
||||
if (SysId.IsValid(userSportExperienceId))
|
||||
{
|
||||
userSportExperience = AccountMgr.GetUserSportExperienceById(userSportExperienceId);
|
||||
disposableItems.Add(userSportExperience);
|
||||
userSport = AccountMgr.GetUserSportById(userSportExperience?.UserSportId ?? null);
|
||||
disposableItems.Add(userSport);
|
||||
if (userSportExperience == null || userSport == null || !userSport.UserAccountId.Equals(SessionUserAccountId))
|
||||
return Json(responseData.SetGoHome(messageTitle, Localiser["msg.something.gone.wrong"]));
|
||||
}
|
||||
else
|
||||
{
|
||||
// Creating new User Sport Experience.
|
||||
// Retrieve User Sport and validate.
|
||||
SysId userSportId = model.ExtractSysId(model.UserSportId);
|
||||
userSport = AccountMgr.GetUserSportById(userSportId);
|
||||
disposableItems.Add(userSport);
|
||||
if (userSport == null || !userSport.UserAccountId.Equals(SessionUserAccountId))
|
||||
return Json(responseData.SetGoHome(messageTitle, Localiser["msg.something.gone.wrong"]));
|
||||
// Create User Sport Experience.
|
||||
userSportExperience = AccountMgr.CreateUserSportExperience(userSport.Id);
|
||||
disposableItems.Add(userSportExperience);
|
||||
}
|
||||
|
||||
// Populate properties.
|
||||
userSportExperience.Changed = false;
|
||||
if (model.ExperiencePeriodFrom != null)
|
||||
userSportExperience.PeriodFrom = model.ParseDateFromForm(model.ExperiencePeriodFrom);
|
||||
if (model.ExperiencePeriodTo != null)
|
||||
userSportExperience.PeriodTo = model.ParseDateFromForm(model.ExperiencePeriodTo);
|
||||
if (model.ExperienceOrganisationId != null)
|
||||
userSportExperience.OrganisationId = model.ExtractSysId(model.ExperienceOrganisationId);
|
||||
if (model.ExperienceOrganisationName != null)
|
||||
userSportExperience.OrganisationName = model.ExperienceOrganisationName;
|
||||
if (model.ExperienceSummary != null)
|
||||
userSportExperience.Summary = model.ExperienceSummary;
|
||||
if (model.ExperienceTeam != null)
|
||||
userSportExperience.Team = model.ExperienceTeam;
|
||||
if (model.ExperienceLeague != null)
|
||||
userSportExperience.League = model.ExperienceLeague;
|
||||
if (model.ExperienceSpeciality != null)
|
||||
userSportExperience.Speciality = model.ExperienceSpeciality;
|
||||
if (model.ExperienceAwards != null)
|
||||
userSportExperience.Awards = model.ExperienceAwards;
|
||||
// Regions.
|
||||
if (model.ExperienceRegionIdNation != null)
|
||||
userSportExperience.RegionIdNation = model.ExtractSysId(model.ExperienceRegionIdNation);
|
||||
if (model.ExperienceRegionIdProvince != null)
|
||||
userSportExperience.RegionIdProvince = model.ExtractSysId(model.ExperienceRegionIdProvince);
|
||||
|
||||
// Store Experience.
|
||||
if (!SysId.IsValid(userSportExperience.Id))
|
||||
{
|
||||
if (AccountMgr.InsertUserSportExperience(userSportExperience, DbUpdateInfo))
|
||||
{
|
||||
responseData.SetNotifyMessage(messageTitle, Localiser["msg.item.created"]);
|
||||
}
|
||||
else
|
||||
{
|
||||
SaLogger.Warn(fn + " Failed to insert user sport experience: " + AccountMgr.ErrorStateMessage);
|
||||
return Json(responseData.SetPopupMessage(messageTitle, Localiser["msg.error.item.insert.failed"]));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (AccountMgr.UpdateUserSportExperience(userSportExperience, DbUpdateInfo))
|
||||
{
|
||||
responseData.SetNotifyMessage(messageTitle, Localiser["msg.item.updated"]);
|
||||
}
|
||||
else
|
||||
{
|
||||
SaLogger.Warn(fn + " Failed to update user sport experience: " + AccountMgr.ErrorStateMessage);
|
||||
return Json(responseData.SetPopupMessage(messageTitle, Localiser["msg.error.item.update.failed"]));
|
||||
}
|
||||
}
|
||||
|
||||
// Populate data to response.
|
||||
responseData.Experience = new SportExperienceResponseItemData();
|
||||
PopulateSportExperienceResponseItemData(model, responseData.Experience, userSport, userSportExperience);
|
||||
}
|
||||
|
||||
// Complete response.
|
||||
responseData.Success = true;
|
||||
return Json(responseData);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
}
|
||||
//=======================================================================
|
||||
}
|
||||
@@ -0,0 +1,77 @@
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Saxonite.Net.Core.Web.Online.Models;
|
||||
using Saxonite.Net.Core.Web.Base.App;
|
||||
using Saxonite.Net.Core.Web.Base.Controllers;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Saxonite.Net.Core.Web.Online.Controllers
|
||||
{
|
||||
//=======================================================================
|
||||
// Online Account Controller.
|
||||
//=======================================================================
|
||||
public partial class AccountController : SaxController_Online
|
||||
{
|
||||
//-------------------------------------------------------------------
|
||||
// Construction.
|
||||
public AccountController(SaxLocaliser localiser, ILogger<HomeController> logger) :
|
||||
base(localiser, logger)
|
||||
{
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
[HttpGet]
|
||||
public IActionResult Index()
|
||||
{
|
||||
// Validate session.
|
||||
if (!ValidUserSession)
|
||||
return RedirectToAction("", "");
|
||||
|
||||
Model_Account model = new Model_Account(Localiser);
|
||||
return View(model);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
[HttpGet]
|
||||
public IActionResult Profile()
|
||||
{
|
||||
// Validate session.
|
||||
if (!ValidUserSession)
|
||||
return RedirectToAction("", "");
|
||||
|
||||
Model_Account model = new Model_Account(Localiser);
|
||||
return View(model);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
[HttpGet]
|
||||
public IActionResult Sports()
|
||||
{
|
||||
// Validate session.
|
||||
if (!ValidUserSession)
|
||||
return RedirectToAction("", "");
|
||||
|
||||
Model_Account model = new Model_Account(Localiser);
|
||||
return View(model);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
[HttpGet]
|
||||
public IActionResult Organisations()
|
||||
{
|
||||
// Validate session.
|
||||
if (!ValidUserSession)
|
||||
return RedirectToAction("", "");
|
||||
|
||||
Model_Account model = new Model_Account(Localiser);
|
||||
return View(model);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
}
|
||||
//=======================================================================
|
||||
}
|
||||
@@ -0,0 +1,453 @@
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Sarand.Net.Standard.Base.App;
|
||||
using Sarand.Net.Standard.Base.Bus;
|
||||
using Sarand.Net.Standard.Base.Core;
|
||||
using Sarand.Net.Standard.Base.Dbas;
|
||||
using Sarand.Net.Standard.Base.Utils;
|
||||
using Saxonite.Net.Core.Web.Base.App;
|
||||
using Saxonite.Net.Core.Web.Online.App;
|
||||
using Saxonite.Net.Core.Web.Online.Models;
|
||||
using Saxonite.Net.Standard.Base.App;
|
||||
using Saxonite.Net.Standard.Base.Bus;
|
||||
using Saxonite.Net.Standard.Base.Consoles;
|
||||
using Saxonite.Net.Standard.Base.Mgr;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Saxonite.Net.Core.Web.Online.Controllers
|
||||
{
|
||||
//=======================================================================
|
||||
// Online Activity Controller - Ajax actions only.
|
||||
//=======================================================================
|
||||
public partial class ActivityController : SaxController_Online
|
||||
{
|
||||
//-------------------------------------------------------------------
|
||||
// Construction.
|
||||
public ActivityController(SaxLocaliser localiser, ILogger<HomeController> logger) :
|
||||
base(localiser, logger)
|
||||
{ }
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Data definitions.
|
||||
/// <summary>Activity details for home page list.</summary>
|
||||
private class ActivityResponseData
|
||||
{
|
||||
public short ItemType { get; set; }
|
||||
public String ItemTypeClass { get; set; }
|
||||
public String ItemId { get; set; }
|
||||
public String Organisation { get; set; }
|
||||
public String OrganisationLogoUrl { get; set; }
|
||||
public String Author { get; set; }
|
||||
public String Caption { get; set; }
|
||||
public String Blurb { get; set; }
|
||||
public String ThumbnailUrl { get; set; }
|
||||
public String Sport { get; set; }
|
||||
public String Region { get; set; }
|
||||
public int? Reaction { get; set; } = null;
|
||||
public String PublishedOnFmt { get; set; }
|
||||
}
|
||||
/// <summary>Article activity info. </summary>
|
||||
private class ActivityResponseData_Article
|
||||
{
|
||||
public ActivityResponseData_Article(SaxController_Online controller, SaxModel_Online model, SaxArticle article, SaxOrganisation organisation)
|
||||
{
|
||||
Organisation = organisation?.Name ?? null;
|
||||
if (controller.ItemDataMgr.ItemHasActiveImage(organisation?.GetItemId() ?? null, Sax.ImageType.OrganisationLogo))
|
||||
OrganisationLogoUrl = controller.GetOrganisationLogoLink(organisation.Id, false);
|
||||
Author = model.GetUserAccountDisplayName(article.UserAccountIdAuthor);
|
||||
Headline = article.Headline;
|
||||
Summary = article.Summary;
|
||||
Sport = model.GetSportCaption(article.SportIdPrimary);
|
||||
Region = model.GetRegionCaption(article.RegionIdPrimary);
|
||||
PublishedOnFmt = model.Localiser.FormatDate(article.PublishedAt);
|
||||
SaxArticle.ContentData content = SaxArticle.ExtractContent(article.BodyData);
|
||||
foreach (SaxArticle.ContentData.SegmentData segment in content.Segments)
|
||||
Content.Segments.Add(new ContentData.SegmentData(controller, segment));
|
||||
}
|
||||
public String Organisation { get; set; }
|
||||
public String OrganisationLogoUrl { get; set; }
|
||||
public String Author { get; set; }
|
||||
public String Headline { get; set; }
|
||||
public String Summary { get; set; }
|
||||
public String Sport { get; set; }
|
||||
public String Region { get; set; }
|
||||
public String PublishedOnFmt { get; set; }
|
||||
public class ContentData
|
||||
{
|
||||
public class SegmentData
|
||||
{
|
||||
public SegmentData(SaxController_Online controller, SaxArticle.ContentData.SegmentData segment)
|
||||
{
|
||||
if (segment.Body.IsValid())
|
||||
{
|
||||
Body = new BodyData();
|
||||
Body.Html = segment.Body.Html;
|
||||
}
|
||||
else if (segment.Image.IsValid())
|
||||
{
|
||||
Image = new ImageData();
|
||||
Image.Link = controller.GetItemImageLink(segment.Image.ItemImageId);
|
||||
}
|
||||
}
|
||||
public class BodyData
|
||||
{
|
||||
public String Html { get; set; }
|
||||
}
|
||||
public BodyData Body { get; }
|
||||
public class ImageData
|
||||
{
|
||||
public String Link { get; set; }
|
||||
}
|
||||
public ImageData Image { get; }
|
||||
}
|
||||
public List<SegmentData> Segments { get; } = new List<SegmentData>();
|
||||
}
|
||||
public ContentData Content { get; } = new ContentData();
|
||||
}
|
||||
/// <summary>Event activity info. </summary>
|
||||
private class ActivityResponseData_Event
|
||||
{
|
||||
public ActivityResponseData_Event(SaxController_Online controller, SaxModel_Online model, SaxOrganisationEvent organisationEvent, SaxOrganisation organisation)
|
||||
{
|
||||
Organisation = model.GetOrganisationName(organisationEvent.OrganisationId);
|
||||
if (controller.ItemDataMgr.ItemHasActiveImage(organisation?.GetItemId() ?? null, Sax.ImageType.OrganisationLogo))
|
||||
OrganisationLogoUrl = controller.GetOrganisationLogoLink(organisation.Id, false);
|
||||
EventAt = model.FormatDateForDisplay(organisationEvent.EventAt);
|
||||
if (organisationEvent.EventAt.Hour > 0 || organisationEvent.EventAt.Minute > 0)
|
||||
EventAt += DateUtil.Format(organisationEvent.EventAt, " HH:ss");
|
||||
Summary = organisationEvent.Summary;
|
||||
Details = organisationEvent.Details;
|
||||
Sport = model.GetSportCaption(organisationEvent.SportIdPrimary);
|
||||
Region = model.GetRegionCaption(organisationEvent.RegionIdCountry);
|
||||
PublishedOnFmt = model.Localiser.FormatDate(organisationEvent.PublishedAt);
|
||||
}
|
||||
public String Organisation { get; set; }
|
||||
public String OrganisationLogoUrl { get; set; }
|
||||
public String EventAt { get; set; }
|
||||
public String Summary { get; set; }
|
||||
public String Details { get; set; }
|
||||
public String Sport { get; set; }
|
||||
public String Region { get; set; }
|
||||
public String PublishedOnFmt { get; set; }
|
||||
}
|
||||
/// <summary>Opportunity activity info. </summary>
|
||||
private class ActivityResponseData_Opportunity
|
||||
{
|
||||
public ActivityResponseData_Opportunity(SaxController_Online controller, SaxModel_Online model, SaxOrganisationOpportunity opportunity, SaxOrganisation organisation)
|
||||
{
|
||||
Organisation = model.GetOrganisationName(opportunity.OrganisationId);
|
||||
if (controller.ItemDataMgr.ItemHasActiveImage(organisation?.GetItemId() ?? null, Sax.ImageType.OrganisationLogo))
|
||||
OrganisationLogoUrl = controller.GetOrganisationLogoLink(organisation.Id, false);
|
||||
Position = opportunity.Position;
|
||||
Outline = opportunity.Outline;
|
||||
Sport = model.GetSportCaption(opportunity.SportIdPrimary);
|
||||
Region = model.GetRegionCaption(opportunity.RegionIdPrimary);
|
||||
PublishedOnFmt = model.Localiser.FormatDate(opportunity.PublishedAt);
|
||||
}
|
||||
public String Organisation { get; set; }
|
||||
public String OrganisationLogoUrl { get; set; }
|
||||
public String Position { get; set; }
|
||||
public String Outline { get; set; }
|
||||
public String Sport { get; set; }
|
||||
public String Region { get; set; }
|
||||
public String PublishedOnFmt { get; set; }
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Activities
|
||||
//-------------------------------------------------------------------
|
||||
private class AjaxResponse_ActivityList : AjaxResponse_Base
|
||||
{
|
||||
public List<ActivityResponseData> Activities { get; } = new List<ActivityResponseData>();
|
||||
}
|
||||
//-------------------------------------------------------------------
|
||||
[HttpPost]
|
||||
[Route("Activity/Ajax/GetList")]
|
||||
[Route("Activity/Ajax/GetActivityList")]
|
||||
[Route("Activity/Ajax/GetActivities")]
|
||||
public IActionResult Ajax_GetActivityList(Model_Activity model)
|
||||
{
|
||||
String fn = GetType().Name + ".Ajax_GetActivityList";
|
||||
String messageTitle = Localiser["activity.caption.activities"];
|
||||
AjaxResponse_ActivityList responseData = new AjaxResponse_ActivityList();
|
||||
|
||||
// Validate session and referrer.
|
||||
if (!ValidReferer) return Forbid();
|
||||
if (!ValidUserSession) return GetAjaxResult_InvalidSession(responseData);
|
||||
RefreshModel(model);
|
||||
SaxSessionData_Online sessionData = SessionData_Online;
|
||||
|
||||
// User context.
|
||||
SysId userAccountId = SessionUserAccountId;
|
||||
SaxActivityConsole.IndexContext indexContext = new SaxActivityConsole.IndexContext(userAccountId);
|
||||
if (SysId.IsValid(userAccountId))
|
||||
indexContext.UserAccountIdsOwner.Add(userAccountId);
|
||||
SysId organisationId = model.DecryptId(model.Filter.OrganisationId);
|
||||
if (SysId.IsValid(organisationId))
|
||||
indexContext.OrganisationIdsOwner.Add(organisationId);
|
||||
|
||||
// Period.
|
||||
indexContext.EffectiveTo = DateTime.Today;
|
||||
|
||||
// Search filter is dissected to extract regions and sports.
|
||||
String searchFilter = model.Filter.Search.TrimAll();
|
||||
List<SysId> sportIds = ExtractSearchFilterSports(ref searchFilter);
|
||||
List<SysId> regionIds = ExtractSearchFilterRegions(ref searchFilter);
|
||||
|
||||
// Sport and region combinations.
|
||||
if (sportIds.IsEmpty())
|
||||
{
|
||||
// No sports extractd from search filter - default to user's sports.
|
||||
foreach (SysId sportId in sessionData.Profile.Sports.Select(item => item.SportId))
|
||||
{
|
||||
if (sportIds.Contains(sportId)) continue;
|
||||
sportIds.AddId(sportId);
|
||||
// Include child sports.
|
||||
sportIds.AddIds(model.GetChildSports_Active(sportId).Select(item => item.Id));
|
||||
model.GetSportCaption(sportId);
|
||||
}
|
||||
}
|
||||
if (regionIds.IsEmpty())
|
||||
{
|
||||
// No regions extracted from search filter - default to user's region(s).
|
||||
regionIds.AddId(sessionData.User.RegionIdProvince);
|
||||
if (regionIds.IsEmpty())
|
||||
regionIds.AddId(sessionData.User.RegionIdCountry);
|
||||
}
|
||||
foreach (SysId sportId in sportIds)
|
||||
{
|
||||
foreach (SysId regionId in regionIds)
|
||||
indexContext.SportRegionIdsIncluded.Add(new SaxActivityIndex.SportRegionIds(sportId, regionId));
|
||||
}
|
||||
|
||||
// Populate activities.
|
||||
List<ItemId> activityItemIds = new List<ItemId>();
|
||||
SaxActivityConsole.IndexResults indexResults = ActivityConsole.QueryIndex(indexContext);
|
||||
foreach (SaxActivityConsole.IndexResults.ActivityData itemData in indexResults.Items)
|
||||
{
|
||||
activityItemIds.Add(itemData.ItemId);
|
||||
ActivityResponseData activityData = new ActivityResponseData();
|
||||
activityData.ItemType = itemData.ItemId.Type;
|
||||
if (itemData.ItemId.Type == (int)Sax.DataItemType.Article)
|
||||
activityData.ItemTypeClass = "Article";
|
||||
else if (itemData.ItemId.Type == (int)Sax.DataItemType.OrganisationEvent)
|
||||
activityData.ItemTypeClass = "Event";
|
||||
else if (itemData.ItemId.Type == (int)Sax.DataItemType.OrganisationOpportunity)
|
||||
activityData.ItemTypeClass = "Opportunity";
|
||||
// ToDo Mask activity index Id with cross-reference stored in session data.
|
||||
activityData.ItemId = model.EncryptId(itemData.ItemId.Id);
|
||||
// Organisation.
|
||||
activityData.Organisation = itemData.Organisation;
|
||||
// Organisation Logo URL.
|
||||
if (SysId.IsValid(itemData.OrganisationId) && itemData.OrganisationHasLogo)
|
||||
activityData.OrganisationLogoUrl = GetOrganisationLogoLink(itemData.OrganisationId, false);
|
||||
// Author.
|
||||
activityData.Author = itemData.Author;
|
||||
// Thumbnail image URL.
|
||||
if (SysId.IsValid(itemData.ItemImageIdThumbnail))
|
||||
activityData.ThumbnailUrl = GetItemImageLink(itemData.ItemImageIdThumbnail);
|
||||
// Activity details.
|
||||
activityData.Caption = itemData.Caption;
|
||||
activityData.Blurb = itemData.Blurb;
|
||||
activityData.Sport = Localiser.GetSportName(itemData.SportId, itemData.SportName);
|
||||
activityData.Region = Localiser.GetRegionName(itemData.RegionId, itemData.RegionName);
|
||||
if ((int)itemData.Reaction > 0)
|
||||
activityData.Reaction = (int)itemData.Reaction;
|
||||
activityData.PublishedOnFmt = Localiser.FormatDate(itemData.EffectiveOn);
|
||||
responseData.Activities.Add(activityData);
|
||||
}
|
||||
|
||||
if (!activityItemIds.IsEmpty())
|
||||
ActivityConsole.RecordUserActivitiesListed(userAccountId, activityItemIds, DbUpdateInfo);
|
||||
|
||||
// Complete response.
|
||||
responseData.Success = true;
|
||||
return Json(responseData);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
/// <summary>Extract Sports from activity search filter.</summary>
|
||||
private List<SysId> ExtractSearchFilterSports(ref string searchFilter)
|
||||
{
|
||||
List<SysId> sportIds = new List<SysId>();
|
||||
if (StringUtil.IsEmpty(searchFilter)) return sportIds;
|
||||
foreach (SaxSport.Data sport in DataCacheConsole.GetActiveSports())
|
||||
{
|
||||
Regex reSport = new Regex("\\b" + Regex.Escape(sport.Name) + "\\b", RegexOptions.IgnoreCase);
|
||||
Match match = reSport.Match(searchFilter);
|
||||
if (match.Success)
|
||||
{
|
||||
sportIds.Add(sport.Id);
|
||||
searchFilter = reSport.Replace(searchFilter, " ").TrimAll();
|
||||
}
|
||||
}
|
||||
return sportIds;
|
||||
}
|
||||
/// <summary>Extract Regions from activity search filter.</summary>
|
||||
private List<SysId> ExtractSearchFilterRegions(ref string searchFilter)
|
||||
{
|
||||
List<SysId> regionIds = new List<SysId>();
|
||||
if (StringUtil.IsEmpty(searchFilter)) return regionIds;
|
||||
foreach (SaxRegion.Data region in DataCacheConsole.GetActiveRegions())
|
||||
{
|
||||
Regex reRegion = new Regex("\\b" + Regex.Escape(region.Name) + "\\b", RegexOptions.IgnoreCase);
|
||||
Match match = reRegion.Match(searchFilter);
|
||||
if (match.Success)
|
||||
{
|
||||
regionIds.Add(region.Id);
|
||||
searchFilter = reRegion.Replace(searchFilter, " ").TrimAll();
|
||||
}
|
||||
}
|
||||
return regionIds;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Activity Info
|
||||
//-------------------------------------------------------------------
|
||||
private class AjaxResponse_ActivityInfo : AjaxResponse_Base
|
||||
{
|
||||
public ActivityResponseData_Article Article { get; set; }
|
||||
public ActivityResponseData_Event Event { get; set; }
|
||||
public ActivityResponseData_Opportunity Opportunity { get; set; }
|
||||
}
|
||||
//-------------------------------------------------------------------
|
||||
[HttpPost]
|
||||
[Route("Activity/Ajax/GetInfo")]
|
||||
[Route("Activity/Ajax/GetItemInfo")]
|
||||
[Route("Activity/Ajax/GetActivityInfo")]
|
||||
[Route("Activity/Ajax/GetActivity")]
|
||||
public IActionResult Ajax_GetActivityInfo(Model_Activity model)
|
||||
{
|
||||
String fn = GetType().Name + ".Ajax_GetActivityInfo";
|
||||
String messageTitle = Localiser["activity.caption.activity"];
|
||||
AjaxResponse_ActivityInfo responseData = new AjaxResponse_ActivityInfo();
|
||||
|
||||
// Validate session and referrer.
|
||||
if (!ValidReferer) return Forbid();
|
||||
if (!ValidUserSession) return GetAjaxResult_InvalidSession(responseData);
|
||||
RefreshModel(model);
|
||||
SaxSessionData_Online sessionData = SessionData_Online;
|
||||
|
||||
// Record disposable items as they are created so all can be disposed when needed.
|
||||
using (DisposableCollection<IDisposable> disposableItems = new DisposableCollection<IDisposable>())
|
||||
{
|
||||
|
||||
// Identify activity.
|
||||
Sax.DataItemType itemType = (Sax.DataItemType)StringUtil.ToShort(model.ActivityItemType);
|
||||
SysId itemId = model.ExtractSysId(model.ActivityItemId);
|
||||
if (itemType <= 0 || !SysId.IsValid(itemId))
|
||||
{
|
||||
SaLogger.Warn(fn + " Activity type/Id inncorrectly specified." + GetLogSuffix());
|
||||
return Json(responseData);
|
||||
}
|
||||
|
||||
// Retrieve activity details.
|
||||
if (itemType == Sax.DataItemType.Article)
|
||||
{
|
||||
// Article.
|
||||
SaxArticle article = ActivityMgr.GetArticleById(itemId);
|
||||
disposableItems.Add(article);
|
||||
if (article == null)
|
||||
{
|
||||
SaLogger.Warn(fn + " Article not found for Activity Id: " + itemId.ToString() + "." + GetLogSuffix());
|
||||
return Json(responseData);
|
||||
}
|
||||
SaxOrganisation organisation = AccountMgr.GetOrganisationById(article.OrganisationId);
|
||||
disposableItems.Add(organisation);
|
||||
responseData.Article = new ActivityResponseData_Article(this, model, article, organisation);
|
||||
}
|
||||
else if (itemType == Sax.DataItemType.OrganisationEvent)
|
||||
{
|
||||
// Organisation Event.
|
||||
SaxOrganisationEvent organisationEvent = ActivityMgr.GetOrganisationEventById(itemId);
|
||||
disposableItems.Add(organisationEvent);
|
||||
if (organisationEvent == null)
|
||||
{
|
||||
SaLogger.Warn(fn + " Event not found for Activity Id: " + itemId.ToString() + "." + GetLogSuffix());
|
||||
return Json(responseData);
|
||||
}
|
||||
SaxOrganisation organisation = AccountMgr.GetOrganisationById(organisationEvent.OrganisationId);
|
||||
disposableItems.Add(organisation);
|
||||
responseData.Event = new ActivityResponseData_Event(this, model, organisationEvent, organisation);
|
||||
}
|
||||
else if (itemType == Sax.DataItemType.OrganisationOpportunity)
|
||||
{
|
||||
// Organisation Opportunity.
|
||||
SaxOrganisationOpportunity opportunity = ActivityMgr.GetOrganisationOpportunityById(itemId);
|
||||
disposableItems.Add(opportunity);
|
||||
if (opportunity == null)
|
||||
{
|
||||
SaLogger.Warn(fn + " Opportunity not found for Activity Id: " + itemId.ToString() + "." + GetLogSuffix());
|
||||
return Json(responseData);
|
||||
}
|
||||
SaxOrganisation organisation = AccountMgr.GetOrganisationById(opportunity.OrganisationId);
|
||||
disposableItems.Add(organisation);
|
||||
responseData.Opportunity = new ActivityResponseData_Opportunity(this, model, opportunity, organisation);
|
||||
}
|
||||
|
||||
// Record activity viewing.
|
||||
if (!ActivityConsole.RecordUserActivityViewed(SessionUserAccountId, new ItemId((short)itemType, itemId), DbUpdateInfo))
|
||||
{
|
||||
SaLogger.Warn(fn + " Failed to record Activity Viewing: " + ActivityConsole.ErrorStateMessage + "." + GetLogSuffix());
|
||||
return Json(responseData);
|
||||
}
|
||||
}
|
||||
|
||||
// Complete response.
|
||||
responseData.Success = true;
|
||||
return Json(responseData);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Activity Reaction.
|
||||
//-------------------------------------------------------------------
|
||||
private class AjaxResponse_ActivityReaction : AjaxResponse_Base
|
||||
{
|
||||
public int Reaction { get; set; }
|
||||
}
|
||||
//-------------------------------------------------------------------
|
||||
[HttpPost]
|
||||
[Route("Activity/Ajax/React")]
|
||||
[Route("Activity/Ajax/Reaction")]
|
||||
public IActionResult Ajax_SetActivityReaction(Model_Activity model)
|
||||
{
|
||||
String fn = GetType().Name + ".Ajax_SetActivityReaction";
|
||||
String messageTitle = Localiser["activity.caption.activity"];
|
||||
AjaxResponse_ActivityReaction responseData = new AjaxResponse_ActivityReaction();
|
||||
|
||||
// Validate session and referrer.
|
||||
if (!ValidReferer) return Forbid();
|
||||
if (!ValidUserSession) return GetAjaxResult_InvalidSession(responseData);
|
||||
RefreshModel(model);
|
||||
SaxSessionData_Online sessionData = SessionData_Online;
|
||||
|
||||
// Identify activity.
|
||||
Sax.DataItemType itemType = (Sax.DataItemType)StringUtil.ToShort(model.ActivityItemType);
|
||||
SysId itemId = model.ExtractSysId(model.ActivityItemId);
|
||||
if (itemType <= 0 || !SysId.IsValid(itemId))
|
||||
{
|
||||
SaLogger.Warn(fn + " Activity type/Id inncorrectly specified." + GetLogSuffix());
|
||||
return Json(responseData);
|
||||
}
|
||||
|
||||
// Record activity reaction.
|
||||
if (!ActivityConsole.RecordUserActivityReaction(SessionUserAccountId, new ItemId((short)itemType, itemId), model.GetActivityReaction(), DbUpdateInfo))
|
||||
{
|
||||
SaLogger.Warn(fn + " Failed to record Activity Reaction: " + ActivityConsole.ErrorStateMessage + "." + GetLogSuffix());
|
||||
return Json(responseData);
|
||||
}
|
||||
|
||||
// Complete response.
|
||||
responseData.Reaction = (int)model.GetActivityReaction();
|
||||
responseData.Success = true;
|
||||
return Json(responseData);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
}
|
||||
//=======================================================================
|
||||
}
|
||||
@@ -0,0 +1,135 @@
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Saxonite.Net.Core.Web.Online.Models;
|
||||
using Saxonite.Net.Core.Web.Base.App;
|
||||
using Saxonite.Net.Core.Web.Base.Controllers;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Saxonite.Net.Standard.Base.Bus;
|
||||
using Sarand.Net.Standard.Base.App;
|
||||
using Sarand.Net.Standard.Base.Bus;
|
||||
using Sarand.Net.Standard.Base.Utils;
|
||||
using Sarand.Net.Standard.Base.Core;
|
||||
using Sarand.Net.Standard.Base.Dbas;
|
||||
using Saxonite.Net.Standard.Base.App;
|
||||
using MailKit;
|
||||
using Org.BouncyCastle.Asn1.Mozilla;
|
||||
using Microsoft.Extensions.Primitives;
|
||||
using Saxonite.Net.Standard.Base.Data;
|
||||
|
||||
namespace Saxonite.Net.Core.Web.Online.Controllers
|
||||
{
|
||||
//=======================================================================
|
||||
// Online Ajax Controller - User Config.
|
||||
//=======================================================================
|
||||
partial class AccountController
|
||||
{
|
||||
//-------------------------------------------------------------------
|
||||
// Data definitions.
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Update User Config.
|
||||
//-------------------------------------------------------------------
|
||||
private class AjaxResponse_UserConfigData : AjaxResponse_Data
|
||||
{
|
||||
// Construction.
|
||||
public AjaxResponse_UserConfigData(SaxModel_Online model) : base(model) { }
|
||||
}
|
||||
// Ajax request.
|
||||
[HttpPost]
|
||||
[Route("UserConfig/Ajax/Update")]
|
||||
public IActionResult UpdateUserConfig(SaxModel_Online model)
|
||||
{
|
||||
String fn = GetType().Name + ".UpdateUserConfig";
|
||||
AjaxResponse_UserConfigData responseData = new AjaxResponse_UserConfigData(model);
|
||||
String messageTitle = Localiser["caption.user.config"];
|
||||
|
||||
// Validate session and referrer.
|
||||
if (!ValidReferer) return Forbid();
|
||||
if (!ValidUserSession) return GetAjaxResult_InvalidSession(responseData);
|
||||
RefreshModel(model);
|
||||
|
||||
// Record disposable items as they are created so all can be disposed when needed.
|
||||
using (DisposableCollection<IDisposable> disposableItems = new DisposableCollection<IDisposable>())
|
||||
{
|
||||
// Retrieve User Config.
|
||||
Dictionary<Sax.UserConfigType, SaxUserConfig> userConfigs = new Dictionary<Sax.UserConfigType, SaxUserConfig>();
|
||||
|
||||
// Update user's configuration.
|
||||
foreach (String key in Request.Form.Keys)
|
||||
{
|
||||
StringValues formValue = "";
|
||||
Request.Form.TryGetValue(key, out formValue);
|
||||
SaLogger.Debug(fn + " Form data. Key: " + key + ". Value: " + formValue);
|
||||
if (key.EqualsCI("HideProfileEligibilityInfo"))
|
||||
{
|
||||
SaxUserConfig userConfig = RefreshUserConfig(Sax.UserConfigType.Online_Profile, userConfigs);
|
||||
if (userConfig != null)
|
||||
{
|
||||
disposableItems.Add(userConfig);
|
||||
SessionData_Online.UserConfig.Profile.Eligibility.HideInfo = StringUtil.ToBool(formValue);
|
||||
userConfig.ConfigData = SaxConfigData.ProfileData.ToXml(SessionData_Online.UserConfig.Profile);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Store configuration.
|
||||
foreach (SaxUserConfig userConfig in userConfigs.Values)
|
||||
{
|
||||
if (!SysId.IsValid(userConfig.Id))
|
||||
{
|
||||
// Add new configuration.
|
||||
if (!AccountMgr.InsertUserConfig(userConfig, DbUpdateInfo))
|
||||
SaLogger.Warn(fn + " Failed to insert User Config: " + AccountMgr.ErrorStateMessage);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Update existing configuration.
|
||||
if (!AccountMgr.UpdateUserConfig(userConfig, DbUpdateInfo))
|
||||
SaLogger.Warn(fn + " Failed to update User Config: " + AccountMgr.ErrorStateMessage);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Complete response.
|
||||
responseData.Success = true;
|
||||
return Json(responseData);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
/// <summary>
|
||||
/// Retrieve the corresponding User Config if previously stored, otherwise create.
|
||||
/// </summary>
|
||||
private SaxUserConfig RefreshUserConfig(Sax.UserConfigType configType, Dictionary<Sax.UserConfigType, SaxUserConfig> userConfigs)
|
||||
{
|
||||
// Check if Config is already in cache.
|
||||
if (userConfigs.ContainsKey(configType)) return userConfigs.GetValueOrDefault(configType, null);
|
||||
// Retrieve user config.
|
||||
SaxUserConfig userConfig = AccountMgr.GetUserConfig(SessionUserAccountId, configType);
|
||||
if (userConfig == null)
|
||||
{
|
||||
// Configuration doesn't currently exist.
|
||||
userConfig = AccountMgr.CreateUserConfig(SessionUserAccountId, configType);
|
||||
}
|
||||
else
|
||||
{
|
||||
// User Configuration already exists.
|
||||
// Refresh configuration in case updated elsewhere.
|
||||
switch (configType)
|
||||
{
|
||||
case Sax.UserConfigType.Online_Profile:
|
||||
SessionData_Online.UserConfig.Profile = SaxConfigData.ProfileData.FromXml(userConfig.ConfigData);
|
||||
break;
|
||||
}
|
||||
}
|
||||
userConfigs.Add(userConfig.ConfigType, userConfig);
|
||||
return userConfig;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
}
|
||||
//=======================================================================
|
||||
}
|
||||
@@ -0,0 +1,782 @@
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Sarand.Net.Standard.Base.App;
|
||||
using Sarand.Net.Standard.Base.Bus;
|
||||
using Sarand.Net.Standard.Base.Core;
|
||||
using Sarand.Net.Standard.Base.Dbas;
|
||||
using Sarand.Net.Standard.Base.Helpers;
|
||||
using Sarand.Net.Standard.Base.Utils;
|
||||
using Saxonite.Net.Core.Web.Online.App;
|
||||
using Saxonite.Net.Core.Web.Online.Models;
|
||||
using Saxonite.Net.Standard.Base.App;
|
||||
using Saxonite.Net.Standard.Base.Bus;
|
||||
using Saxonite.Net.Standard.Base.Consoles;
|
||||
using Saxonite.Net.Standard.Base.Mgr;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Specialized;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Saxonite.Net.Core.Web.Online.Controllers
|
||||
{
|
||||
//=======================================================================
|
||||
// Online Article Controller - Ajax actions.
|
||||
//=======================================================================
|
||||
partial class ArticleController
|
||||
{
|
||||
//-------------------------------------------------------------------
|
||||
// Article Content data.
|
||||
private class ArticleContentData
|
||||
{
|
||||
public List<ArticleContentSegmentData> Segments { get; } = new List<ArticleContentSegmentData>();
|
||||
}
|
||||
private class ArticleContentSegmentData
|
||||
{
|
||||
public ArticleContentSegmentBodyData Body { get; set; }
|
||||
public ArticleContentSegmentImageData Image { get; set; }
|
||||
}
|
||||
private class ArticleContentSegmentBodyData
|
||||
{
|
||||
public String Html { get; set; }
|
||||
}
|
||||
private class ArticleContentSegmentImageData
|
||||
{
|
||||
public int ItemImageId { get; set; }
|
||||
public int ImageIdx { get; set; }
|
||||
public String ImageLink { get; set; }
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Article data.
|
||||
private class ArticleListData : AjaxResponse_Data.ItemData_Base
|
||||
{
|
||||
public String OrganisationId { get; set; }
|
||||
public String OrganisationName { get; set; }
|
||||
public String Headline { get; set; }
|
||||
public String Summary { get; set; }
|
||||
public class FeedbackData
|
||||
{
|
||||
public String Summary { get; set; }
|
||||
public long? ViewCount { get; set; } = null;
|
||||
public long? FeedbackCount { get; set; } = null;
|
||||
public String FeedbackAverage { get; set; }
|
||||
}
|
||||
public FeedbackData Feedback { get; set; }
|
||||
public String RegionCaptionPrimary { get; set; }
|
||||
public String SportCaptionPrimary { get; set; }
|
||||
public String PublishedOnFmt { get; set; }
|
||||
}
|
||||
private class ArticleItemData : ArticleListData
|
||||
{
|
||||
public String RegionIdPrimary { get; set; }
|
||||
public String SportIdPrimary { get; set; }
|
||||
public bool? Published { get; set; } = null;
|
||||
public bool? PublishedInFuture { get; set; } = null;
|
||||
public String PublishedOn_YYYYMMDD { get; set; }
|
||||
public String PublishedOn_Calendar { get; set; }
|
||||
public ArticleContentData Content { get; } = new ArticleContentData();
|
||||
}
|
||||
private void PopulateArticleResponseListData(Model_Article model, SaxArticle article, SaxOrganisation organisation, SaxActivityFeedback activityFeedback, ArticleListData data)
|
||||
{
|
||||
data.Id = model.EncryptId(article.Id);
|
||||
data.OrganisationId = SysId.ToString(article.OrganisationId);
|
||||
data.Headline = article.Headline;
|
||||
data.Summary = article.Summary;
|
||||
PopulateFeedbackResponseListData(activityFeedback, data);
|
||||
data.RegionCaptionPrimary = model.GetRegionCaption(article.RegionIdPrimary);
|
||||
data.SportCaptionPrimary = model.GetSportCaption(article.SportIdPrimary);
|
||||
data.CreatedOnFmt = model.FormatDateForDisplay(article.CreateStamp.On);
|
||||
data.PublishedOnFmt = model.FormatDateForDisplay(article.PublishedAt);
|
||||
data.StatusCode = article.StatusCode;
|
||||
data.StatusDesc = article.StatusDesc;
|
||||
}
|
||||
private void PopulateArticleResponseItemData(Model_Article model, SaxArticle article, SaxOrganisation organisation, SaxActivityFeedback activityFeedback, ArticleItemData data)
|
||||
{
|
||||
PopulateArticleResponseListData(model, article, organisation, activityFeedback, data as ArticleListData);
|
||||
data.RegionIdPrimary = model.GetEncryptedRegionId(article.RegionIdPrimary);
|
||||
data.SportIdPrimary = model.GetEncryptedSportId(article.SportIdPrimary);
|
||||
data.Published = DateUtil.IsValid(article.PublishedAt) ? true : (bool?)null;
|
||||
data.PublishedInFuture = (data.Published == true && article.PublishedAt != null && ((DateTime)article.PublishedAt).CompareTo(DateTime.Today) >= 0) ? true : (bool?)null;
|
||||
data.PublishedOn_YYYYMMDD = DateUtil.Format(article.PublishedAt, "yyyyMMdd");
|
||||
data.PublishedOn_Calendar = model.FormatDateForForm(article.PublishedAt);
|
||||
|
||||
// Article content.
|
||||
SaxArticle.ContentData articleContent = SaxArticle.ExtractContent(article.BodyData);
|
||||
foreach (var contentSegment in articleContent.Segments)
|
||||
{
|
||||
var segmentData = new ArticleContentSegmentData();
|
||||
if (contentSegment.Body.IsValid())
|
||||
{
|
||||
segmentData.Body = new ArticleContentSegmentBodyData();
|
||||
segmentData.Body.Html = contentSegment.Body.Html;
|
||||
}
|
||||
else if (contentSegment.Image.IsValid())
|
||||
{
|
||||
segmentData.Image = new ArticleContentSegmentImageData();
|
||||
segmentData.Image.ItemImageId = SysId.ToInt(contentSegment.Image.ItemImageId);
|
||||
segmentData.Image.ImageLink = GetItemImageLink(contentSegment.Image.ItemImageId);
|
||||
}
|
||||
data.Content.Segments.Add(segmentData);
|
||||
}
|
||||
}
|
||||
// Feedback.
|
||||
private void PopulateFeedbackResponseData(SaxActivityFeedback activityFeedback, ArticleItemData data)
|
||||
{
|
||||
PopulateFeedbackResponseListData(activityFeedback, data);
|
||||
}
|
||||
private void PopulateFeedbackResponseListData(SaxActivityFeedback activityFeedback, ArticleListData data)
|
||||
{
|
||||
if (activityFeedback == null) return;
|
||||
PopulateFeedbackResponseListData(activityFeedback.ViewCount, activityFeedback.FeedbackCount, activityFeedback.FeedbackTotal, activityFeedback.FeedbackAverage, data);
|
||||
}
|
||||
private void PopulateFeedbackResponseListData(long viewCount, long feedbackCount, long feedbackTotal, decimal feedbackAverage, ArticleListData data)
|
||||
{
|
||||
if (viewCount <= 0) return;
|
||||
data.Feedback = new ArticleListData.FeedbackData();
|
||||
data.Feedback.Summary = feedbackCount.ToString() + "/" + viewCount.ToString();
|
||||
if (feedbackCount > 0)
|
||||
data.Feedback.Summary = feedbackAverage.ToString("N1") + " " + data.Feedback.Summary;
|
||||
data.Feedback.ViewCount = viewCount;
|
||||
data.Feedback.FeedbackCount = feedbackCount;
|
||||
data.Feedback.FeedbackAverage = feedbackAverage.ToString("N1");
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Get Article List ajax request.
|
||||
//-------------------------------------------------------------------
|
||||
private class OrganisationData : AjaxResponse_Data.ItemIdName { }
|
||||
private class AjaxResponse_ArticleList : AjaxResponse_Data
|
||||
{
|
||||
// Construction.
|
||||
public AjaxResponse_ArticleList(SaxModel_Online model) : base(model) { }
|
||||
// Article list.
|
||||
public List<ArticleListData> Articles { get; } = new List<ArticleListData>();
|
||||
/// <summary>Organisations that the user has rights to author articles for.</summary>
|
||||
public List<OrganisationData> Organisations { get; set; }
|
||||
public ItemIdName DefaultSport { get; set; }
|
||||
public ItemIdName DefaultRegion { get; set; }
|
||||
public List<String> ImageContentTypes { get; set; }
|
||||
}
|
||||
//-------------------------------------------------------------------
|
||||
[HttpPost]
|
||||
[Route("Article/Ajax/GetList")]
|
||||
[Route("Article/Ajax/GetArticles")]
|
||||
public IActionResult Ajax_GetArticleList(Model_Article model)
|
||||
{
|
||||
String fn = GetType().Name + ".Ajax_GetArticleList";
|
||||
String messageTitle = Localiser["article.caption.articles"];
|
||||
AjaxResponse_ArticleList responseData = new AjaxResponse_ArticleList(model);
|
||||
|
||||
// Validate session and referrer.
|
||||
if (!ValidReferer) return Forbid();
|
||||
if (!ValidUserSession) return GetAjaxResult_InvalidSession(responseData);
|
||||
SaxSessionData_Online sessionData = SessionData_Online;
|
||||
SysId userAccountId = SessionUserAccountId;
|
||||
RefreshModel(model);
|
||||
|
||||
// Record disposable items as they are created so all can be disposed when needed.
|
||||
using (DisposableCollection<IDisposable> disposableItems = new DisposableCollection<IDisposable>())
|
||||
{
|
||||
// User account.
|
||||
SaxUserAccount userAccount = AccountMgr.GetUserAccountById(userAccountId);
|
||||
disposableItems.Add(userAccount);
|
||||
|
||||
// Organisations that the user has rights to author articles for.
|
||||
foreach (SaxAccountMgr.OrganisationIdName articleOrganisation in AccountMgr.GetOrganisationsForAnyUserRole(userAccountId, new[] { Sax.OrganisationRole.Admin, Sax.OrganisationRole.ArticleAdmin }))
|
||||
{
|
||||
if (responseData.Organisations == null) responseData.Organisations = new List<OrganisationData>();
|
||||
OrganisationData organisationData = new OrganisationData()
|
||||
{
|
||||
Id = model.EncryptId(articleOrganisation.Id),
|
||||
Name = articleOrganisation.Name
|
||||
};
|
||||
responseData.Organisations.Add(organisationData);
|
||||
}
|
||||
|
||||
// User must either be a journalist or allowed to author organisation articles.
|
||||
if (!UserIsJournalist && responseData.Organisations == null) return GetAjaxResult_GoHome(responseData);
|
||||
if (UserIsJournalist && responseData.Organisations != null)
|
||||
{
|
||||
OrganisationData organisationData = new OrganisationData()
|
||||
{
|
||||
Id = "",
|
||||
Name = "No Organisation - Journalist Articles"
|
||||
};
|
||||
responseData.Organisations.Insert(0, organisationData);
|
||||
}
|
||||
|
||||
// Filter organisation.
|
||||
SysId organisationIdFilter = model.ExtractSysId(model.Filter.OrganisationId);
|
||||
SaxOrganisation organisation = AccountMgr.GetOrganisationById(organisationIdFilter);
|
||||
disposableItems.Add(organisation);
|
||||
|
||||
// Default Sport - defined by organisation if selected.
|
||||
SysId defaultSportId = organisation?.SportIdPrimary ?? null;
|
||||
if (SysId.IsValid(defaultSportId))
|
||||
{
|
||||
responseData.DefaultSport = new AjaxResponse_Data.ItemIdName()
|
||||
{
|
||||
Id = model.GetEncryptedSportId(defaultSportId),
|
||||
Name = model.GetSportCaption(defaultSportId)
|
||||
};
|
||||
}
|
||||
|
||||
// Default region - defined by organisation (if selected) otherwise user themselves.
|
||||
SysId defaultRegionId = organisation?.RegionIdPrimary ?? userAccount?.RegionIdCountry ?? null;
|
||||
if (SysId.IsValid(defaultRegionId))
|
||||
{
|
||||
responseData.DefaultRegion = new AjaxResponse_Data.ItemIdName()
|
||||
{
|
||||
Id = model.GetEncryptedRegionId(defaultRegionId),
|
||||
Name = model.GetRegionCaption(defaultRegionId)
|
||||
};
|
||||
}
|
||||
|
||||
// Article image content types.
|
||||
responseData.ImageContentTypes = SaxItemImage.GetValidContentTypes(Sax.DataItemType.Article);
|
||||
|
||||
// Item filter.
|
||||
SaxArticle.Params prmArticle = new SaxArticle.Params();
|
||||
prmArticle.UserAccountIdsAuthorIncluded.Add(sessionData.User.UserAccountId);
|
||||
if (SysId.IsValid(organisationIdFilter))
|
||||
prmArticle.OrganisationIdsIncluded.Add(organisationIdFilter);
|
||||
else
|
||||
prmArticle.ExcludeOrganisationArticles = true;
|
||||
prmArticle.ArticleFilter = model.Filter.Article;
|
||||
prmArticle.StatusCat = SaxArticle.StatusCat.NotDeleted;
|
||||
model.Paging.ItemTotal = (ulong)ActivityMgr.GetArticleCount(prmArticle);
|
||||
model.PopulatePagingTo(prmArticle.ResultsPaging);
|
||||
|
||||
// Item columns.
|
||||
ColumnDfn colId = ActivityMgr.GetArticleColumnDfn(SaxArticle.Column.Id);
|
||||
ColumnDfn colOrganisationId = ActivityMgr.GetArticleColumnDfn(SaxArticle.Column.OrganisationId);
|
||||
ColumnDfn colOrganisationName = ActivityMgr.GetArticleColumnDfn(SaxArticle.Column.Organisation_Name);
|
||||
ColumnDfn colHeadline = ActivityMgr.GetArticleColumnDfn(SaxArticle.Column.Headline);
|
||||
ColumnDfn colSummary = ActivityMgr.GetArticleColumnDfn(SaxArticle.Column.Summary);
|
||||
ColumnDfn colRegionIdPrimary = ActivityMgr.GetArticleColumnDfn(SaxArticle.Column.RegionIdPrimary);
|
||||
ColumnDfn colSportIdPrimary = ActivityMgr.GetArticleColumnDfn(SaxArticle.Column.SportIdPrimary);
|
||||
ColumnDfn colPublishedOn = ActivityMgr.GetArticleColumnDfn(SaxArticle.Column.PublishedAt_Date);
|
||||
ColumnDfn colStatus = ActivityMgr.GetArticleColumnDfn(SaxArticle.Column.Status);
|
||||
ColumnDfn colCreatedOn = ActivityMgr.GetArticleColumnDfn(SaxArticle.Column.CreateOn_Date);
|
||||
// Feedback.
|
||||
ColumnDfn colFeedback_ViewCount = ActivityMgr.GetArticleColumnDfn(SaxArticle.Column.Feedback_ViewCount);
|
||||
ColumnDfn colFeedback_FeedbackCount = ActivityMgr.GetArticleColumnDfn(SaxArticle.Column.Feedback_FeedbackCount);
|
||||
ColumnDfn colFeedback_FeedbackTotal = ActivityMgr.GetArticleColumnDfn(SaxArticle.Column.Feedback_FeedbackTotal);
|
||||
ColumnDfn colFeedback_FeedbackAverage = ActivityMgr.GetArticleColumnDfn(SaxArticle.Column.Feedback_FeedbackAverage);
|
||||
List<ColumnDfn> columns = new List<ColumnDfn>()
|
||||
{
|
||||
colId, colOrganisationId, colOrganisationName, colHeadline, colSummary,
|
||||
colRegionIdPrimary, colSportIdPrimary, colPublishedOn,
|
||||
colStatus, colCreatedOn,
|
||||
colFeedback_ViewCount, colFeedback_FeedbackCount, colFeedback_FeedbackTotal, colFeedback_FeedbackAverage
|
||||
};
|
||||
|
||||
// Sort columns.
|
||||
colCreatedOn.SortAscending = false;
|
||||
prmArticle.SortColumns.Add(colCreatedOn);
|
||||
|
||||
// Query items.
|
||||
using (DbResultSet resultSet = ActivityMgr.ExecuteArticleQuery(columns, prmArticle))
|
||||
{
|
||||
while (resultSet != null && resultSet.HasRows && resultSet.NextRecord())
|
||||
{
|
||||
NamedValue.Map values = resultSet.GetRecordValues();
|
||||
ArticleListData articleData = new ArticleListData()
|
||||
{
|
||||
Id = model.EncryptId(new SysId(values.GetLong(colId.DataName))),
|
||||
OrganisationId = model.EncryptId(new SysId(values.GetLong(colOrganisationId.DataName))),
|
||||
OrganisationName = values.GetString(colOrganisationName.DataName),
|
||||
Headline = values.GetString(colHeadline.DataName),
|
||||
Summary = values.GetString(colSummary.DataName),
|
||||
RegionCaptionPrimary = model.GetRegionCaption(SysId.ToSysId(values.GetString(colRegionIdPrimary.DataName))),
|
||||
SportCaptionPrimary = model.GetSportCaption(SysId.ToSysId(values.GetString(colSportIdPrimary.DataName))),
|
||||
CreatedOnFmt = model.FormatDateForDisplay(values.GetDateTime(colCreatedOn.DataName)),
|
||||
PublishedOnFmt = model.FormatDateForDisplay(values.GetDateTime(colPublishedOn.DataName)),
|
||||
StatusCode = values.GetString(colStatus.DataName),
|
||||
StatusDesc = SacsSystem.GetStatusDescForCode(values.GetString(colStatus.DataName))
|
||||
};
|
||||
// Feedback.
|
||||
long viewCount = values.GetLong(colFeedback_ViewCount.DataName);
|
||||
if (viewCount > 0)
|
||||
PopulateFeedbackResponseListData(viewCount, values.GetLong(colFeedback_FeedbackCount.DataName), values.GetLong(colFeedback_FeedbackTotal.DataName), values.GetDecimal(colFeedback_FeedbackAverage.DataName), articleData);
|
||||
responseData.Articles.Add(articleData);
|
||||
}
|
||||
}
|
||||
if (model.Paging.IsPaged)
|
||||
model.Paging.ItemCount = (ushort)responseData.Articles.Count;
|
||||
}
|
||||
|
||||
// Complete response.
|
||||
responseData.SetPaging(model);
|
||||
responseData.Success = true;
|
||||
return Json(responseData);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Get Article ajax request.
|
||||
//-------------------------------------------------------------------
|
||||
private class AjaxResponse_Article : AjaxResponse_Data
|
||||
{
|
||||
// Construction.
|
||||
public AjaxResponse_Article(SaxModel_Online model) : base(model) { }
|
||||
// Article details.
|
||||
public ArticleItemData Article { get; } = new ArticleItemData();
|
||||
}
|
||||
//-------------------------------------------------------------------
|
||||
[HttpPost]
|
||||
[Route("Article/Ajax/Get")]
|
||||
[Route("Article/Ajax/GetItem")]
|
||||
[Route("Article/Ajax/GetArticle")]
|
||||
public IActionResult Ajax_GetArticle(Model_Article model)
|
||||
{
|
||||
String fn = GetType().Name + ".Ajax_GetArticle";
|
||||
String messageTitle = Localiser["article.caption.article"];
|
||||
AjaxResponse_Article responseData = new AjaxResponse_Article(model);
|
||||
|
||||
// Validate session and referrer.
|
||||
if (!ValidReferer) return Forbid();
|
||||
if (!ValidUserSession) return GetAjaxResult_InvalidSession(responseData);
|
||||
SysId userAccountId = SessionUserAccountId;
|
||||
RefreshModel(model);
|
||||
|
||||
// Record disposable items as they are created so all can be disposed when needed.
|
||||
using (DisposableCollection<IDisposable> disposableItems = new DisposableCollection<IDisposable>())
|
||||
{
|
||||
|
||||
// Identify item.
|
||||
SysId articleId = model.ExtractSysId(model.ArticleId);
|
||||
if (!SysId.IsValid(articleId))
|
||||
return Json(responseData.SetPopupMessage(messageTitle, Localiser["msg.error.item.id.not.specified"]));
|
||||
|
||||
// Retrieve item.
|
||||
SaxArticle article = ActivityMgr.GetArticleById(articleId);
|
||||
disposableItems.Add(article);
|
||||
if (article == null)
|
||||
{
|
||||
SaLogger.Warn(fn + " Failed to retrieve Article for Id: '" + model.ArticleId + "'");
|
||||
return Json(responseData.SetPopupMessage(messageTitle, Localiser["msg.error.item.id.not.found"]));
|
||||
}
|
||||
if (!article.UserAccountIdAuthor.Equals(userAccountId))
|
||||
{
|
||||
SaLogger.Warn(fn + " Inconsistent Article Author. Expected: " + userAccountId + ". Found: " + article.UserAccountIdAuthor);
|
||||
return Json(responseData.SetPopupMessage(messageTitle, Localiser["msg.error.system"]));
|
||||
}
|
||||
|
||||
// Organisation.
|
||||
SaxOrganisation organisation = AccountMgr.GetOrganisationById(article.OrganisationId);
|
||||
disposableItems.Add(organisation);
|
||||
|
||||
// Delete upload images.
|
||||
SaxItemImage.Params prmItemImage = new SaxItemImage.Params();
|
||||
prmItemImage.ItemIdsIncluded.Add(new ItemId((short)Sax.DataItemType.Article, articleId));
|
||||
prmItemImage.ImageTypesIncluded.Add(Sax.ImageType.Article_Upload);
|
||||
prmItemImage.StatusCat = SaxItemImage.StatusCat.NotDeleted;
|
||||
foreach (SaxItemImage itemImage in ItemDataMgr.GetItemImageList(prmItemImage))
|
||||
{
|
||||
disposableItems.Add(itemImage);
|
||||
itemImage.SessionUid = 0;
|
||||
itemImage.ImageUid = 0;
|
||||
itemImage.Status = SaStatus.Deleted;
|
||||
ItemDataMgr.UpdateItemImage(itemImage, DbUpdateInfo);
|
||||
}
|
||||
|
||||
// Article Feedback.
|
||||
SaxActivityFeedback activityFeedback = ActivityMgr.GetActivityFeedbackForItem(article.GetItemId());
|
||||
disposableItems.Add(activityFeedback);
|
||||
|
||||
// Construct response.
|
||||
PopulateArticleResponseItemData(model, article, organisation, activityFeedback, responseData.Article);
|
||||
}
|
||||
responseData.Success = true;
|
||||
return Json(responseData);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Article - Upload Image.
|
||||
//-------------------------------------------------------------------
|
||||
private class AjaxResponse_UploadArticleImage : AjaxResponse_Data
|
||||
{
|
||||
// Construction.
|
||||
public AjaxResponse_UploadArticleImage(SaxModel_Online model) : base(model) { }
|
||||
// Article segment details.
|
||||
public ArticleContentSegmentData Segment { get; set; }
|
||||
public String UploadMsg { get; set; }
|
||||
}
|
||||
// Ajax request.
|
||||
[HttpPost]
|
||||
[Route("Article/Ajax/UploadImage")]
|
||||
public IActionResult Ajax_UploadArticleImage(Model_Article model)
|
||||
{
|
||||
String fn = GetType().Name + ".Ajax_UploadArticleImage";
|
||||
AjaxResponse_UploadArticleImage responseData = new AjaxResponse_UploadArticleImage(model);
|
||||
String messageTitle = Localiser["article.caption.article"];
|
||||
|
||||
// Validate session and referrer.
|
||||
if (!ValidReferer) return Forbid();
|
||||
if (!ValidUserSession) return GetAjaxResult_InvalidSession(responseData);
|
||||
SaxSessionData_Online sessionData = SessionData_Online;
|
||||
RefreshModel(model);
|
||||
|
||||
// Record disposable items as they are created so all can be disposed when needed.
|
||||
using (DisposableCollection<IDisposable> disposableItems = new DisposableCollection<IDisposable>())
|
||||
{
|
||||
|
||||
// Validate number of images.
|
||||
if (model.ArticleImage.IsEmpty())
|
||||
{
|
||||
SaLogger.Warn(fn + " No image file supplied for upload");
|
||||
return Json(responseData);
|
||||
}
|
||||
if (model.ArticleImage.Count != 1)
|
||||
{
|
||||
SaLogger.Warn(fn + " Invalid number of image files uploaded: " + model.ArticleImage.Count);
|
||||
return Json(responseData.SetControlError("ArticleImage", Localiser["msg.upload.image.single"]));
|
||||
}
|
||||
IFormFile file = model.ArticleImage[0];
|
||||
|
||||
// Image properties.
|
||||
byte[] imageData = null;
|
||||
using (MemoryStream fileStream = new MemoryStream())
|
||||
{
|
||||
file.CopyTo(fileStream);
|
||||
imageData = fileStream.ToArray();
|
||||
}
|
||||
|
||||
// Validate content type.
|
||||
if (StringUtil.IsEmpty(file.ContentType) || !SaxItemImage.GetValidContentTypes(Sax.DataItemType.Article).ContainsCI(file.ContentType))
|
||||
return Json(responseData.SetControlError("ArticleImage", Localiser["msg.upload.image.invalid.content.type"]));
|
||||
Sarand.Net.Standard.Base.Core.Sacs.MimeType mimeTypeExpected = SacsContentTypeHelper.GetMimeTypeFromContentType(file.ContentType);
|
||||
|
||||
// Validate the image.
|
||||
ImageUtils.ImageConfig imageConfig = null;
|
||||
if (mimeTypeExpected == Sarand.Net.Standard.Base.Core.Sacs.MimeType.Svg)
|
||||
imageConfig = ImageUtils.VerifySvgImageData(imageData);
|
||||
else
|
||||
imageConfig = ImageUtils.VerifyImageData(imageData);
|
||||
if (!imageConfig.ValidImage)
|
||||
return Json(responseData.SetControlError("ArticleImage", Localiser["msg.upload.image.invalid"]));
|
||||
|
||||
// Validate mime type.
|
||||
if (!SaxItemImage.GetValidMimeTypes(Sax.DataItemType.Article).Contains(imageConfig.MimeType))
|
||||
return Json(responseData.SetControlError("ArticleImage", Localiser["msg.upload.image.invalid.mime"]));
|
||||
if (imageConfig.MimeType != mimeTypeExpected)
|
||||
{
|
||||
SaLogger.Warn($"{SysUtil.Fn} Image upload - inconsistent Mime. Filename: {file.FileName}. Mime: {imageConfig.MimeType}. Expected Mime: {mimeTypeExpected}.");
|
||||
return Json(responseData.SetControlError("OrganisationLogoImage", Localiser["msg.upload.image.invalid"]));
|
||||
}
|
||||
|
||||
// Resize the image if required.
|
||||
if (!ImageUtils.ConstrainImage(imageConfig, Sax.Config.Articles.Images.WidthMax, Sax.Config.Articles.Images.HeightMax))
|
||||
return Json(responseData.SetControlError("ArticleImage", Localiser["msg.upload.image.resize.failed"]));
|
||||
|
||||
// Image belongs to the article.
|
||||
// If the article doesn't yet exist, it will need to be uploaded to the user first and later transferred.
|
||||
SysId articleId = model.ExtractSysId(model.ArticleId);
|
||||
ItemId articleItemId = new ItemId((short)Sax.DataItemType.Article, articleId);
|
||||
ItemId userItemId = new ItemId((short)Sax.DataItemType.UserAccount, sessionData.User.UserAccountId);
|
||||
ItemId imageItemId = SysId.IsValid(articleId) ? articleItemId : userItemId;
|
||||
|
||||
// Store uploaded image as 'Upload' - awaiting confirmation that the article details are to be saved.
|
||||
// NB Reuse any existing deleted article upload image to avoid creating new images unless necessary.
|
||||
SaxItemImage.Params prmItemImage = new SaxItemImage.Params();
|
||||
prmItemImage.ItemIdsIncluded.Add(imageItemId);
|
||||
prmItemImage.ImageTypesIncluded.Add(Sax.ImageType.Article);
|
||||
prmItemImage.ImageTypesIncluded.Add(Sax.ImageType.Article_Upload);
|
||||
prmItemImage.StatusCat = SaxItemImage.StatusCat.DeletedOnly;
|
||||
prmItemImage.ResultsPaging.PageLength = 1;
|
||||
prmItemImage.ResultsPaging.PageNo = 1;
|
||||
List<SaxItemImage> itemImages = ItemDataMgr.GetItemImageList(prmItemImage);
|
||||
SaxItemImage itemImage = !itemImages.IsEmpty() ? itemImages[0] : null;
|
||||
if (itemImage == null)
|
||||
itemImage = ItemDataMgr.CreateItemImage(imageItemId, Sax.ImageType.Article_Upload);
|
||||
disposableItems.Add(itemImage);
|
||||
itemImage.ImageType = Sax.ImageType.Article_Upload;
|
||||
itemImage.Filename = file.FileName;
|
||||
itemImage.Mime = SacsContentTypeHelper.GetMimeTypeFromContentType(file.ContentType).ToString().ToLower();
|
||||
itemImage.ContentType = file.ContentType;
|
||||
itemImage.ImageData = imageConfig.ImageData;
|
||||
itemImage.Width = imageConfig.Width;
|
||||
itemImage.Height = imageConfig.Height;
|
||||
itemImage.SessionUid = sessionData.SessionIdx;
|
||||
itemImage.ImageUid = sessionData.NextItemIdx;
|
||||
itemImage.Status = SaxItemImage.DefaultStatus;
|
||||
|
||||
if (!SysId.IsValid(itemImage.Id))
|
||||
{
|
||||
if (!ItemDataMgr.InsertItemImage(itemImage, DbUpdateInfo))
|
||||
{
|
||||
SaLogger.Warn(fn + " Failed to insert uploaded image - " + ItemDataMgr.ErrorStateMessage);
|
||||
return Json(responseData.SetControlError("ArticleImage", Localiser["msg.error.item.insert.failed"]));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!ItemDataMgr.UpdateItemImage(itemImage, DbUpdateInfo))
|
||||
{
|
||||
SaLogger.Warn(fn + " Failed to update uploaded image - " + ItemDataMgr.ErrorStateMessage);
|
||||
return Json(responseData.SetControlError("ArticleImage", Localiser["msg.error.item.insert.failed"]));
|
||||
}
|
||||
}
|
||||
|
||||
// Segment image info.
|
||||
responseData.Segment = new ArticleContentSegmentData();
|
||||
responseData.Segment.Image = new ArticleContentSegmentImageData();
|
||||
responseData.Segment.Image.ImageLink = GetItemImageLink(itemImage.Id);
|
||||
responseData.Segment.Image.ImageIdx = itemImage.ImageUid;
|
||||
}
|
||||
|
||||
// Complete response.
|
||||
//responseData.SetNotifyMessage(messageTitle, "Image uploaded.");
|
||||
responseData.Success = true;
|
||||
return Json(responseData);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Store Article ajax request.
|
||||
//-------------------------------------------------------------------
|
||||
[HttpPost]
|
||||
[Route("Article/Ajax/Store")]
|
||||
[Route("Article/Ajax/StoreItem")]
|
||||
[Route("Article/Ajax/StoreArticle")]
|
||||
public IActionResult Ajax_StoreArticle(Model_Article model)
|
||||
{
|
||||
String fn = GetType().Name + ".Ajax_StoreArticle";
|
||||
String messageTitle = Localiser["article.caption.article"];
|
||||
AjaxResponse_Article responseData = new AjaxResponse_Article(model);
|
||||
|
||||
// Validate session and referrer.
|
||||
if (!ValidReferer) return Forbid();
|
||||
if (!ValidUserSession) return GetAjaxResult_InvalidSession(responseData);
|
||||
SaxSessionData_Online sessionData = SessionData_Online;
|
||||
RefreshModel(model);
|
||||
|
||||
// Record disposable items as they are created so all can be disposed when needed.
|
||||
using (DisposableCollection<IDisposable> disposableItems = new DisposableCollection<IDisposable>())
|
||||
{
|
||||
|
||||
// Validate item properties.
|
||||
model.ValidateArticleData(responseData);
|
||||
if (responseData.HasControlErrors())
|
||||
return Json(responseData);
|
||||
|
||||
// Validate User & Organisation.
|
||||
SysId userAccountId = SessionUserAccountId;
|
||||
SysId organisationId = model.ExtractSysId(model.ArticleOrganisationId);
|
||||
if (SysId.IsValid(organisationId))
|
||||
{
|
||||
// Organisation specified - User must have Article Admin role.
|
||||
if (!AccountMgr.UserHasAnyOrganisationRole(userAccountId, organisationId, new[] { Sax.OrganisationRole.Admin, Sax.OrganisationRole.ArticleAdmin }))
|
||||
{
|
||||
SaLogger.Warn(fn + " User does not have Article Admin role for organisation." + GetLogSuffix());
|
||||
return Json(responseData.SetGoHome(messageTitle, Localiser["msg.error.system"]));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Organisation not specified - User must be a Journalist.
|
||||
if (!UserIsJournalist)
|
||||
{
|
||||
SaLogger.Warn(fn + " User is not a Journalist for non-organisation article." + GetLogSuffix());
|
||||
return Json(responseData.SetGoHome(messageTitle, Localiser["msg.error.system"]));
|
||||
}
|
||||
}
|
||||
|
||||
// Validate item Id against 'Exists' flag.
|
||||
SysId articleId = model.ExtractSysId(model.ArticleId);
|
||||
bool articleExists = StringUtil.ToBool(model.ArticleExists);
|
||||
if (articleExists && !SysId.IsValid(articleId))
|
||||
{
|
||||
SaLogger.Warn(fn + " Id not specified for existing Article.");
|
||||
return Json(responseData.SetGoHome(messageTitle, Localiser["msg.error.system"]));
|
||||
}
|
||||
if (!articleExists && SysId.IsValid(articleId))
|
||||
{
|
||||
SaLogger.Warn(fn + " Id specified for new Article: '" + model.ArticleId + "'");
|
||||
return Json(responseData.SetGoHome(messageTitle, Localiser["msg.error.system"]));
|
||||
}
|
||||
|
||||
// Retrieve existing item.
|
||||
SaxArticle article = ActivityMgr.GetArticleById(articleId);
|
||||
disposableItems.Add(article);
|
||||
if (article == null && SysId.IsValid(articleId))
|
||||
{
|
||||
SaLogger.Warn(fn + " Failed to retrieve article for Id: '" + model.ArticleId + "'");
|
||||
return Json(responseData.SetPopupMessage(messageTitle, Localiser["msg.error.item.id.not.found"]));
|
||||
}
|
||||
if (article != null)
|
||||
{
|
||||
// Validate existing article.
|
||||
if (SysId.ToLong(article.UserAccountIdAuthor) != SysId.ToLong(userAccountId))
|
||||
{
|
||||
SaLogger.Warn(fn + " Inconsistent Article Author." + GetLogSuffix());
|
||||
return Json(responseData.SetGoHome(messageTitle, Localiser["msg.error.system"]));
|
||||
}
|
||||
if (SysId.ToLong(article.OrganisationId) != SysId.ToLong(organisationId))
|
||||
{
|
||||
SaLogger.Warn(fn + " Inconsistent Article Organisation." + GetLogSuffix());
|
||||
return Json(responseData.SetGoHome(messageTitle, Localiser["msg.error.system"]));
|
||||
}
|
||||
}
|
||||
|
||||
// Organisation.
|
||||
SaxOrganisation organisation = AccountMgr.GetOrganisationById(organisationId);
|
||||
disposableItems.Add(organisation);
|
||||
|
||||
// Create new item if required.
|
||||
if (article == null)
|
||||
{
|
||||
article = ActivityMgr.CreateArticle(sessionData.User.UserAccountId, organisationId);
|
||||
disposableItems.Add(article);
|
||||
}
|
||||
|
||||
// Populate item properties.
|
||||
if (model.ArticleRegionId != null)
|
||||
article.RegionIdPrimary = model.ExtractSysId(model.ArticleRegionId);
|
||||
if (model.ArticleSportId != null)
|
||||
article.SportIdPrimary = model.ExtractSysId(model.ArticleSportId);
|
||||
if (model.ArticleHeadline != null)
|
||||
article.Headline = model.ArticleHeadline;
|
||||
if (model.ArticleSummary != null)
|
||||
article.Summary = model.ArticleSummary;
|
||||
if (!model.ArticlePublished.ToBool())
|
||||
{
|
||||
if (model.ArticlePublish)
|
||||
article.PublishedAt = model.GetArticlePublishOn();
|
||||
else
|
||||
article.PublishedAt = null;
|
||||
}
|
||||
if (model.ArticleStatusCode != null)
|
||||
article.Status = model.ArticleStatus;
|
||||
|
||||
// Retrieve all article images - before new article is created as uploaded images are assigned to user first.
|
||||
SaxItemImage.Params prmItemImage = new SaxItemImage.Params();
|
||||
if (SysId.IsValid(article.Id))
|
||||
prmItemImage.ItemIdsIncluded.Add(article.GetItemId());
|
||||
else
|
||||
prmItemImage.ItemIdsIncluded.Add(new ItemId((short)Sax.DataItemType.UserAccount, sessionData.User.UserAccountId));
|
||||
prmItemImage.ImageTypesIncluded.Add(Sax.ImageType.Article);
|
||||
prmItemImage.ImageTypesIncluded.Add(Sax.ImageType.Article_Upload);
|
||||
prmItemImage.StatusCat = SaxItemImage.StatusCat.NotDeleted;
|
||||
List<SaxItemImage> itemImages = ItemDataMgr.GetItemImageList(prmItemImage);
|
||||
disposableItems.AddRange(itemImages);
|
||||
|
||||
// If Article doesn't yet exist, create it now so that images can be assigned.
|
||||
bool articleCreated = false;
|
||||
if (!SysId.IsValid(article.Id))
|
||||
{
|
||||
if (!ActivityMgr.InsertArticle(article, DbUpdateInfo))
|
||||
{
|
||||
SaLogger.Warn(fn + " Failed to insert article: " + ActivityMgr.ErrorStateMessage);
|
||||
return Json(responseData.SetPopupMessage(messageTitle, Localiser["msg.error.item.insert.failed"]));
|
||||
}
|
||||
articleCreated = true;
|
||||
}
|
||||
|
||||
// Content.
|
||||
if (model.ArticleContentSegmentBodies != null)
|
||||
{
|
||||
SaxArticle.ContentData articleContent = new SaxArticle.ContentData();
|
||||
for (int segmentIdx = 0; segmentIdx < model.ArticleContentSegmentBodies.Count; segmentIdx++)
|
||||
{
|
||||
String segmentBody = model.ArticleContentSegmentBodies[segmentIdx];
|
||||
String segmentItemImageId = model.ArticleContentSegmentItemImageIds.Count > segmentIdx ? model.ArticleContentSegmentItemImageIds[segmentIdx] : "";
|
||||
String segmentImageIdx = model.ArticleContentSegmentImageIdxs.Count > segmentIdx ? model.ArticleContentSegmentImageIdxs[segmentIdx] : "";
|
||||
if (!StringUtil.IsEmpty(segmentBody))
|
||||
{
|
||||
// HTML Body segment.
|
||||
var segment = articleContent.AddSegment();
|
||||
segment.Body.Html = segmentBody;
|
||||
}
|
||||
else if (!StringUtil.IsEmpty(segmentItemImageId) || !StringUtil.IsEmpty(segmentImageIdx))
|
||||
{
|
||||
SysId itemImageId = model.ExtractSysId(segmentItemImageId);
|
||||
int imageIdx = StringUtil.ToInt(segmentImageIdx);
|
||||
|
||||
// Check for new image first.
|
||||
SaxItemImage itemImage = itemImages.GetItemImageBySessionImage(sessionData.SessionIdx, imageIdx);
|
||||
if (itemImage == null)
|
||||
itemImage = itemImages.GetItemImageById(itemImageId);
|
||||
if (itemImage != null)
|
||||
{
|
||||
// Ensure that the image is correctly identified for the Article.
|
||||
itemImage.ItemId = article.GetItemId();
|
||||
itemImage.ImageType = Sax.ImageType.Article;
|
||||
itemImage.SessionUid = 0;
|
||||
itemImage.ImageUid = 0;
|
||||
itemImage.Status = SaxItemImage.DefaultStatus;
|
||||
if (ItemDataMgr.UpdateItemImage(itemImage, DbUpdateInfo))
|
||||
{
|
||||
// Assign the image segment to the article.
|
||||
var segment = articleContent.AddSegment();
|
||||
segment.Image.ItemImageId = itemImage.Id;
|
||||
// Remove the image from the list as it's now been handled.
|
||||
itemImages.Remove(itemImage);
|
||||
}
|
||||
else
|
||||
SaLogger.Warn(fn + " Failed to update article image: " + ItemDataMgr.ErrorStateMessage);
|
||||
}
|
||||
else
|
||||
SaLogger.Warn(fn + " Failed to identify article image. ItemImageId: " + itemImageId.ToInt() + ". SessionIdx: " + sessionData.SessionIdx + ". ImageIdx: " + imageIdx + ".");
|
||||
}
|
||||
}
|
||||
article.BodyData = SaxArticle.GetContentData(articleContent);
|
||||
}
|
||||
|
||||
// Assign/Validate thumbnail image.
|
||||
// Compile list of images in the article body and make a note of the first image.
|
||||
SysId itemIdImage_First = null;
|
||||
List<SysId> itemImageIds = new List<SysId>();
|
||||
foreach (var contentSegment in SaxArticle.ExtractContent(article.BodyData).Segments)
|
||||
{
|
||||
var segmentData = new ArticleContentSegmentData();
|
||||
if (contentSegment.Image.IsValid())
|
||||
{
|
||||
if (!SysId.IsValid(itemIdImage_First))
|
||||
itemIdImage_First = contentSegment.Image.ItemImageId;
|
||||
itemImageIds.AddId(contentSegment.Image.ItemImageId);
|
||||
}
|
||||
}
|
||||
// If the thumbnail isn't found in the body clear it.
|
||||
if (!itemImageIds.Contains(article.ItemImageIdThumbnail))
|
||||
article.ItemImageIdThumbnail = null;
|
||||
// If the thumbnail isn't assigned, assign the first image.
|
||||
if (!SysId.IsValid(article.ItemImageIdThumbnail))
|
||||
article.ItemImageIdThumbnail = itemIdImage_First;
|
||||
|
||||
// Update the Article.
|
||||
if (!ActivityMgr.UpdateArticle(article, DbUpdateInfo))
|
||||
{
|
||||
SaLogger.Warn(fn + " Failed to update article [Id:" + SysId.ToString(article.Id) + "]: " + ActivityMgr.ErrorStateMessage);
|
||||
return Json(responseData.SetPopupMessage(messageTitle, Localiser["msg.error.item.update.failed"]));
|
||||
}
|
||||
SaLogger.Info(fn + " Article " + (articleCreated ? "created" : "updated") + ". Id: " + article.Id.ToString() + ". User: " + SessionData.User.EmailAddress, true);
|
||||
|
||||
// Store Article Activity Index data.
|
||||
ActivityConsole.StoreActivityIndex(article, DbUpdateInfo);
|
||||
|
||||
// Delete remaining images as they are no longer required.
|
||||
foreach (SaxItemImage itemImage in itemImages)
|
||||
{
|
||||
itemImage.SessionUid = 0;
|
||||
itemImage.ImageUid = 0;
|
||||
itemImage.Status = SaStatus.Deleted;
|
||||
ItemDataMgr.UpdateItemImage(itemImage, DbUpdateInfo);
|
||||
}
|
||||
|
||||
// Article Feedback.
|
||||
SaxActivityFeedback activityFeedback = ActivityMgr.GetActivityFeedbackForItem(article.GetItemId());
|
||||
disposableItems.Add(activityFeedback);
|
||||
|
||||
// Construct response.
|
||||
PopulateArticleResponseItemData(model, article, organisation, activityFeedback, responseData.Article);
|
||||
responseData.Success = true;
|
||||
}
|
||||
return Json(responseData);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
}
|
||||
//=======================================================================
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Sarand.Net.Standard.Base.Bus;
|
||||
using Saxonite.Net.Core.Web.Base.App;
|
||||
using Saxonite.Net.Core.Web.Online.Models;
|
||||
using Saxonite.Net.Standard.Base.App;
|
||||
using Saxonite.Net.Standard.Base.Bus;
|
||||
using Saxonite.Net.Standard.Base.Mgr;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Saxonite.Net.Core.Web.Online.Controllers
|
||||
{
|
||||
//=======================================================================
|
||||
// Online Journalist Controller.
|
||||
//=======================================================================
|
||||
public partial class ArticleController : SaxController_Online
|
||||
{
|
||||
//-------------------------------------------------------------------
|
||||
// Construction.
|
||||
public ArticleController(SaxLocaliser localiser, ILogger<HomeController> logger) :
|
||||
base(localiser, logger)
|
||||
{
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
[HttpGet]
|
||||
public IActionResult Index()
|
||||
{
|
||||
// Validate session.
|
||||
if (!ValidUserSession)
|
||||
return RedirectToAction("", "");
|
||||
|
||||
// User must either be a Journalist or have Article Admin rights with at least one organisation.
|
||||
List<SaxAccountMgr.OrganisationIdName> organisations = AccountMgr.GetOrganisationsForAnyUserRole(SessionUserAccountId, new [] { Sax.OrganisationRole.Admin, Sax.OrganisationRole.ArticleAdmin });
|
||||
if (organisations.Count < 1 && !UserIsJournalist)
|
||||
return RedirectToAction("", "");
|
||||
|
||||
// Model.
|
||||
Model_Article model = new Model_Article(Localiser);
|
||||
model.UserCanAuthorOrganisationArticles = organisations.Count > 0;
|
||||
model.UserCanAuthorJournalistArticles = UserIsJournalist;
|
||||
if (organisations.Count > 0)
|
||||
{
|
||||
// Default filter to first organisation.
|
||||
model.Filter.OrganisationId = model.EncryptId(organisations[0].Id);
|
||||
model.Filter.OrganisationCaption = organisations[0].Name;
|
||||
}
|
||||
model.Paging.PageNo = 1;
|
||||
model.Paging.PageLength = 6;
|
||||
|
||||
return View(model);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
}
|
||||
//=======================================================================
|
||||
}
|
||||
@@ -0,0 +1,103 @@
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Saxonite.Net.Core.Web.Online.Models;
|
||||
using Saxonite.Net.Core.Web.Base.App;
|
||||
using Saxonite.Net.Core.Web.Base.Controllers;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Sarand.Net.Standard.Base.Bus;
|
||||
using Saxonite.Net.Standard.Base.Bus;
|
||||
using Sarand.Net.Standard.Base.App;
|
||||
using Sarand.Net.Standard.Base.Utils;
|
||||
using Sarand.Net.Standard.Base.Core;
|
||||
|
||||
namespace Saxonite.Net.Core.Web.Online.Controllers
|
||||
{
|
||||
//=======================================================================
|
||||
public class HomeController : SaxController_Online
|
||||
{
|
||||
//-------------------------------------------------------------------
|
||||
// Data members.
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Construction.
|
||||
public HomeController(SaxLocaliser localiser, ILogger<HomeController> logger) :
|
||||
base(localiser, logger)
|
||||
{
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
[HttpGet]
|
||||
public IActionResult Index()
|
||||
{
|
||||
String fn = GetType().Name + ".Index";
|
||||
|
||||
// Check for 'Keep Logged In' cookie.
|
||||
// NB Only allowed if there isn't a current user session.
|
||||
if (!ValidUserSession && AppConfig.Security.SignIn.KeepLoggedIn.Allowed)
|
||||
{
|
||||
String encryptedParams = GetRequestCookie(KeepLoggedIn.CookieName);
|
||||
KeepLoggedInParams keepLoggedInParams = ExtractKeepLoggedInParams(encryptedParams);
|
||||
String logSuffix = keepLoggedInParams.GetValidParams().Concat("", " ", ".");
|
||||
if (SysId.IsValid(keepLoggedInParams.UserAccountId))
|
||||
{
|
||||
// Record disposable items as they are created so all can be disposed when needed.
|
||||
using (DisposableCollection<IDisposable> disposableItems = new DisposableCollection<IDisposable>())
|
||||
{
|
||||
SaxUserAccount userAccount = AccountMgr.GetUserAccountById(keepLoggedInParams.UserAccountId);
|
||||
if (userAccount != null)
|
||||
{
|
||||
disposableItems.Add(userAccount);
|
||||
if (userAccount.IsStatusActive)
|
||||
{
|
||||
List<SaxUserRole> userRoles = AccountMgr.GetRolesForUser(userAccount.Id);
|
||||
disposableItems.AddRange(userRoles);
|
||||
List<SaxUserConfig> userConfigs = AccountMgr.GetConfigsForUser(userAccount.Id);
|
||||
disposableItems.AddRange(userConfigs);
|
||||
String errorMessage = "";
|
||||
if (SignUserIn(userAccount, userRoles, userConfigs, true, ref errorMessage))
|
||||
SaLogger.Info(fn + " Keep Logged In cookie found." + logSuffix);
|
||||
else SaLogger.Warn(fn + " Keep Logged In cookie found but failed to sign user in: " + errorMessage + "." + logSuffix);
|
||||
}
|
||||
else SaLogger.Warn(fn + " Keep Logged In cookie found but UserAccount is not active." + logSuffix);
|
||||
}
|
||||
else SaLogger.Warn(fn + " Keep Logged In cookie found but UserAccount not found." + logSuffix);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Redirect to sign-in if not signed-in.
|
||||
if (!ValidUserSession)
|
||||
{
|
||||
ClearKeepLoggedInCookie();
|
||||
//return RedirectToAction("", "Security");
|
||||
}
|
||||
|
||||
// Home page.
|
||||
Model_Home model = new Model_Home(Localiser);
|
||||
model.ProhibitCache = false;
|
||||
return View(model);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
[HttpGet]
|
||||
public IActionResult Privacy()
|
||||
{
|
||||
Model_Home model = new Model_Home(Localiser);
|
||||
return View(model);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)]
|
||||
public IActionResult Error()
|
||||
{
|
||||
return View(new ErrorViewModel(Localiser) { RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier });
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
}
|
||||
//=======================================================================
|
||||
}
|
||||
@@ -0,0 +1,229 @@
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Saxonite.Net.Core.Web.Online.Models;
|
||||
using Saxonite.Net.Core.Web.Base.App;
|
||||
using Saxonite.Net.Core.Web.Base.Controllers;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Saxonite.Net.Standard.Base.Bus;
|
||||
using Sarand.Net.Standard.Base.App;
|
||||
using Sarand.Net.Standard.Base.Bus;
|
||||
using Sarand.Net.Standard.Base.Utils;
|
||||
using Saxonite.Net.Standard.Base.App;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Sarand.Net.Standard.Base.Helpers;
|
||||
using System.IO;
|
||||
using System.Drawing;
|
||||
using Sarand.Net.Standard.Base.Core;
|
||||
using Microsoft.Net.Http.Headers;
|
||||
using System.Collections.Specialized;
|
||||
|
||||
namespace Saxonite.Net.Core.Web.Online.Controllers
|
||||
{
|
||||
//=======================================================================
|
||||
// Online Image Controller - delivers dynamic images.
|
||||
//=======================================================================
|
||||
public partial class ImageController : SaxController_Online
|
||||
{
|
||||
//-------------------------------------------------------------------
|
||||
// Data members.
|
||||
public static String ParamName_OrganisationLogoEncrypted { get; } = "ole";
|
||||
public static String ParamName_ItemImageEncrypted { get; } = "iie";
|
||||
public static String ParamName_OrganisationId { get; } = "ori";
|
||||
public static String ParamName_ItemImageId { get; } = "iii";
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Construction.
|
||||
public ImageController(SaxLocaliser localiser, ILogger<HomeController> logger) :
|
||||
base(localiser, logger)
|
||||
{
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Account Contact image - General
|
||||
//-------------------------------------------------------------------
|
||||
// Account Contact Image request.
|
||||
/// <summary>
|
||||
/// Get the Account Contact Image for the specified account.
|
||||
/// <para>Current User Account is used if no other specified in the encrypted parameter.</para>
|
||||
/// <para>Encrypted parameter:</para>
|
||||
/// <para>- uaie: User Account Id encrypted.</para>
|
||||
/// </summary>
|
||||
[HttpGet]
|
||||
[Route("Image/Account/Contact")]
|
||||
public IActionResult GetAccountContactImage(String uaie)
|
||||
{
|
||||
String userAccountIdParam = "";// ToDo Decrypt from uaie value.
|
||||
SysId userAccountId = SysId.ToSysId(userAccountIdParam);
|
||||
if (!SysId.IsValid(userAccountId))
|
||||
userAccountId = SessionUserAccountId;
|
||||
return GetAccountContactImage(userAccountId, Sax.ImageType.Avatar);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Account Contact image - Profile
|
||||
//-------------------------------------------------------------------
|
||||
// Account Profile Contact Image request.
|
||||
/// <summary>
|
||||
/// Get the current Account Profile Contact Image for the specified account.
|
||||
/// <para>Account is always current User Account - this request is only fir use from the user's own profile page.</para>
|
||||
/// <para>'Uploaded' avatar image will take precedence as this will be the latest if present.</para>
|
||||
/// <para>NB Avoid caching this image as it will change whenever a new one is uploaded.</para>
|
||||
/// </summary>
|
||||
[HttpGet]
|
||||
[Route("Image/Account/Contact/Profile")]
|
||||
[ResponseCache(NoStore = true, Location = ResponseCacheLocation.None)]
|
||||
public IActionResult GetAccountContactImage()
|
||||
{
|
||||
// Response should not be cached.
|
||||
Response.Headers[HeaderNames.CacheControl] = "no-cache, no-store, must-revalidate, max-age=0";
|
||||
Response.Headers[HeaderNames.Expires] = "-1";
|
||||
SysId userAccountId = SessionUserAccountId;
|
||||
return GetAccountContactImage(userAccountId, Sax.ImageType.Avatar_Upload);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
/// <summary>
|
||||
/// Get the
|
||||
/// </summary>
|
||||
/// <param name="imageTypePriority"></param>
|
||||
/// <returns></returns>
|
||||
private IActionResult GetAccountContactImage(SysId userAccountId, Sax.ImageType imageTypePriority)
|
||||
{
|
||||
String fn = GetType().Name + ".GetAccountContactImage";
|
||||
|
||||
// Validate session and referrer.
|
||||
if (!ValidReferer) return Forbid();
|
||||
if (!ValidUserSession) return Forbid();
|
||||
ItemId userItemId = new ItemId((short)Sax.DataItemType.UserAccount, userAccountId);
|
||||
|
||||
// Retrieve account contact images.
|
||||
SaxItemImage.Params prmItemImage = new SaxItemImage.Params();
|
||||
prmItemImage.ItemIdsIncluded.Add(userItemId);
|
||||
prmItemImage.ImageTypesIncluded.Add(Sax.ImageType.Avatar);
|
||||
prmItemImage.ImageTypesIncluded.Add(Sax.ImageType.Avatar_Upload);
|
||||
prmItemImage.StatusCat = SaxItemImage.StatusCat.ActiveOnly;
|
||||
SaxItemImage itemImage = null;
|
||||
foreach (SaxItemImage itemImageCandidate in ItemDataMgr.GetItemImageList(prmItemImage))
|
||||
{
|
||||
// One of the 'Avatar' image types will take precedence.
|
||||
if (itemImage == null || itemImageCandidate.ImageType == imageTypePriority)
|
||||
itemImage = itemImageCandidate;
|
||||
}
|
||||
|
||||
if (itemImage == null)
|
||||
return NotFound();
|
||||
|
||||
// Construct response.
|
||||
return File(itemImage.ImageData, itemImage.ContentType);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Organisation logo.
|
||||
//-------------------------------------------------------------------
|
||||
/// <summary>
|
||||
/// Get the logo for the specified Organisation.
|
||||
/// <para>Method parameter name (ole) must match name of encrypted parameter.</para>
|
||||
/// <para>Encrypted parameters:</para>
|
||||
/// <para>- ori: Organisation Id.</para>
|
||||
/// </summary>
|
||||
[HttpGet]
|
||||
[Route("Image/Organisation/Logo")]
|
||||
public IActionResult GetOrganisationLogo(String ole)
|
||||
{
|
||||
return GetOrganisationLogo(ole, false);
|
||||
}
|
||||
/// <summary>
|
||||
/// Get the logo for the specified Organisation.
|
||||
/// <para>Method parameter name (ole) must match name of encrypted parameter.</para>
|
||||
/// <para>Encrypted parameters:</para>
|
||||
/// <para>- ori: Organisation Id.</para>
|
||||
/// </summary>
|
||||
[HttpGet]
|
||||
[Route("Image/Organisation/Logo/Upload")]
|
||||
public IActionResult GetOrganisationLogoUpload(String ole)
|
||||
{
|
||||
return GetOrganisationLogo(ole, true);
|
||||
}
|
||||
private IActionResult GetOrganisationLogo(String encryptedParams, bool allowUploadImage)
|
||||
{
|
||||
String fn = GetType().Name + ".GetOrganisationLogo";
|
||||
|
||||
// Validate session and referrer.
|
||||
if (!ValidReferer || !ValidUserSession) return Forbid();
|
||||
|
||||
// Extract encrypted parameters.
|
||||
NameValueCollection parameters = ExtractOnlineParams(encryptedParams);
|
||||
if (parameters.Count < 1) return Forbid();
|
||||
|
||||
// Organisation Id.
|
||||
SysId organisationId = SysId.ToSysId(parameters.Get(ParamName_OrganisationId));
|
||||
if (!SysId.IsValid(organisationId)) return Forbid();
|
||||
ItemId organisationItemId = new ItemId((short)Sax.DataItemType.Organisation, organisationId);
|
||||
|
||||
// Query Organisation Logo images.
|
||||
SaxItemImage.Params prmItemImage = new SaxItemImage.Params();
|
||||
prmItemImage.ItemIdsIncluded.Add(organisationItemId);
|
||||
prmItemImage.ImageTypesIncluded.Add(Sax.ImageType.OrganisationLogo);
|
||||
if (allowUploadImage)
|
||||
prmItemImage.ImageTypesIncluded.Add(Sax.ImageType.OrganisationLogo_Upload);
|
||||
prmItemImage.StatusCat = SaxItemImage.StatusCat.ActiveOnly;
|
||||
SaxItemImage itemImage = null;
|
||||
foreach (SaxItemImage itemImageCandidate in ItemDataMgr.GetItemImageList(prmItemImage))
|
||||
{
|
||||
// The 'Upload' image will take precedence if allowed.
|
||||
if (itemImage == null || itemImageCandidate.ImageType == Sax.ImageType.OrganisationLogo_Upload)
|
||||
itemImage = itemImageCandidate;
|
||||
}
|
||||
|
||||
if (itemImage == null)
|
||||
return NotFound();
|
||||
|
||||
// Construct response.
|
||||
Response.Headers[HeaderNames.CacheControl] = "no-cache, no-store, must-revalidate, max-age=0";
|
||||
Response.Headers[HeaderNames.Expires] = "-1";
|
||||
return File(itemImage.ImageData, itemImage.ContentType);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Item image
|
||||
//-------------------------------------------------------------------
|
||||
/// <summary>
|
||||
/// Get the specified Item Image.
|
||||
/// <para>Method parameter name (iie) must match name of encrypted parameter.</para>
|
||||
/// <para>Encrypted parameters:</para>
|
||||
/// <para>- iii: item Image Id.</para>
|
||||
/// </summary>
|
||||
[HttpGet]
|
||||
[Route("Image/Item")]
|
||||
public IActionResult GetItemImage(String iie)
|
||||
{
|
||||
String fn = GetType().Name + ".GetItemImage";
|
||||
|
||||
// Validate session and referrer.
|
||||
if (!ValidReferer) return Forbid();
|
||||
if (!ValidUserSession) return Forbid();
|
||||
ItemId userItemId = new ItemId((short)Sax.DataItemType.UserAccount, SessionUserAccountId);
|
||||
|
||||
// Extract encrypted parameters.
|
||||
NameValueCollection parameters = ExtractOnlineParams(iie);
|
||||
if (parameters.Count<1) return Forbid();
|
||||
|
||||
// Item Image.
|
||||
SysId itemImageId = SysId.ToSysId(parameters.Get(ParamName_ItemImageId));
|
||||
if (!SysId.IsValid(itemImageId)) return Forbid();
|
||||
SaxItemImage itemImage = ItemDataMgr.GetItemImageById(itemImageId);
|
||||
if (itemImage == null)
|
||||
return NotFound();
|
||||
|
||||
// Construct response.
|
||||
return File(itemImage.ImageData, itemImage.ContentType);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
}
|
||||
//=======================================================================
|
||||
}
|
||||
+520
@@ -0,0 +1,520 @@
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.AspNetCore.Mvc.Diagnostics;
|
||||
using Sarand.Net.Standard.Base.App;
|
||||
using Sarand.Net.Standard.Base.Bus;
|
||||
using Sarand.Net.Standard.Base.Core;
|
||||
using Sarand.Net.Standard.Base.Dbas;
|
||||
using Sarand.Net.Standard.Base.Utils;
|
||||
using Saxonite.Net.Core.Web.Online.Models;
|
||||
using Saxonite.Net.Standard.Base.App;
|
||||
using Saxonite.Net.Standard.Base.Bus;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Saxonite.Net.Core.Web.Online.Controllers
|
||||
{
|
||||
//=======================================================================
|
||||
// Online Organisation Controller - Events - Ajax actions.
|
||||
//=======================================================================
|
||||
partial class OrganisationController
|
||||
{
|
||||
//-------------------------------------------------------------------
|
||||
// Organisation Event data.
|
||||
private class EventListData : AjaxResponse_Data.ItemData_Base
|
||||
{
|
||||
public String EventAtDateFmt { get; set; }
|
||||
public String EventAtTimeFmt { get; set; }
|
||||
public String EventToDateFmt { get; set; }
|
||||
public String EventToTimeFmt { get; set; }
|
||||
public String Duration { get; set; }
|
||||
public String TypeCode { get; set; }
|
||||
public String TypeDesc { get; set; }
|
||||
public String Summary { get; set; }
|
||||
public String SportCaptionPrimary { get; set; }
|
||||
public String RegionCaptionCountry { get; set; }
|
||||
public String PublishedOnFmt { get; set; }
|
||||
public String ExpiresOnFmt { get; set; }
|
||||
}
|
||||
private class EventItemData : EventListData
|
||||
{
|
||||
public String EventAt_Calendar { get; set; }
|
||||
public String EventAt_YYYYMMDD { get; set; }
|
||||
public String EventAt_HHMM { get; set; }
|
||||
public String EventTo_Calendar { get; set; }
|
||||
public String EventTo_YYYYMMDD { get; set; }
|
||||
public String EventTo_HHMM { get; set; }
|
||||
public String Details { get; set; }
|
||||
public String SportIdPrimary { get; set; }
|
||||
public String RegionIdCountry { get; set; }
|
||||
public String PublishedOn_YYYYMMDD { get; set; }
|
||||
public String ExpiresOn_YYYYMMDD { get; set; }
|
||||
}
|
||||
private void PopulateEventResponseListData(Model_Organisation_Events model, SaxOrganisationEvent organisationEvent, EventListData data)
|
||||
{
|
||||
data.Id = model.EncryptId(organisationEvent.Id);
|
||||
// 'At' date/time.
|
||||
data.EventAtDateFmt = Localiser.FormatDate(organisationEvent.EventAt);
|
||||
if (organisationEvent.HasValidEventAtTime())
|
||||
data.EventAtTimeFmt = DateUtil.Format(organisationEvent.EventAt, "HH:mm");
|
||||
// 'To' date/time.
|
||||
data.EventToDateFmt = Localiser.FormatDate(organisationEvent.EventTo);
|
||||
if (organisationEvent.HasValidEventToTime())
|
||||
data.EventToTimeFmt = DateUtil.Format(organisationEvent.EventTo, "HH:mm");
|
||||
// Event properties.
|
||||
if (DateUtil.IsValid(organisationEvent.EventTo) && organisationEvent.EventTo > organisationEvent.EventAt)
|
||||
data.Duration = DateUtil.FormatNumberOfSeconds(((DateTime)organisationEvent.EventTo - organisationEvent.EventAt).TotalSeconds);
|
||||
data.TypeCode = EventTypeCodes.GetCodeForType(organisationEvent.EventType);
|
||||
data.TypeDesc = Localiser.GetEventTypeCaption(organisationEvent.EventType);
|
||||
data.Summary = organisationEvent.Summary;
|
||||
data.SportCaptionPrimary = model.GetSportCaption(organisationEvent.SportIdPrimary);
|
||||
data.RegionCaptionCountry = model.GetRegionCaption(organisationEvent.RegionIdCountry);
|
||||
data.CreatedOnFmt = Localiser.FormatDate(organisationEvent.CreateStamp.On);
|
||||
if (DateUtil.IsValid(organisationEvent.PublishedAt))
|
||||
data.PublishedOnFmt = Localiser.FormatDate(organisationEvent.PublishedAt);
|
||||
if (DateUtil.IsValid(organisationEvent.ExpiresAt))
|
||||
data.ExpiresOnFmt = Localiser.FormatDate(organisationEvent.ExpiresAt);
|
||||
data.StatusCode = organisationEvent.StatusCode;
|
||||
data.StatusDesc = organisationEvent.StatusDesc;
|
||||
}
|
||||
private void PopulateEventResponseItemData(Model_Organisation_Events model, SaxOrganisationEvent organisationEvent, EventItemData data)
|
||||
{
|
||||
PopulateEventResponseListData(model, organisationEvent, data as EventListData);
|
||||
// 'At' date/time.
|
||||
data.EventAt_Calendar = model.FormatDateForForm(organisationEvent.EventAt);
|
||||
data.EventAt_YYYYMMDD = DateUtil.Format(organisationEvent.EventAt, "yyyyMMdd");
|
||||
if (organisationEvent.HasValidEventAtTime())
|
||||
data.EventAt_HHMM = DateUtil.Format(organisationEvent.EventAt, "HH:mm");
|
||||
// 'To' date/time.
|
||||
data.EventTo_Calendar = model.FormatDateForForm(organisationEvent.EventTo);
|
||||
data.EventTo_YYYYMMDD = DateUtil.Format(organisationEvent.EventTo, "yyyyMMdd");
|
||||
if (organisationEvent.HasValidEventToTime())
|
||||
data.EventTo_HHMM = DateUtil.Format(organisationEvent.EventTo, "HH:mm");
|
||||
// Event properties.
|
||||
data.Details = organisationEvent.Details;
|
||||
data.RegionIdCountry = model.GetEncryptedRegionId(organisationEvent.RegionIdCountry);
|
||||
data.SportIdPrimary = model.GetEncryptedSportId(organisationEvent.SportIdPrimary);
|
||||
if (DateUtil.IsValid(organisationEvent.PublishedAt))
|
||||
data.PublishedOn_YYYYMMDD = DateUtil.Format(organisationEvent.PublishedAt, "yyyyMMdd");
|
||||
if (DateUtil.IsValid(organisationEvent.ExpiresAt))
|
||||
data.ExpiresOn_YYYYMMDD = DateUtil.Format(organisationEvent.ExpiresAt, "yyyyMMdd");
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Get Event List ajax request.
|
||||
//-------------------------------------------------------------------
|
||||
private class AjaxResponse_EventList : AjaxResponse_Data
|
||||
{
|
||||
// Construction.
|
||||
public AjaxResponse_EventList(SaxModel_Online model) : base(model) { }
|
||||
// Event list.
|
||||
public List<EventListData> Events { get; } = new List<EventListData>();
|
||||
// User profile.
|
||||
public class UserData
|
||||
{
|
||||
public bool CanManage { get; set; }
|
||||
}
|
||||
public UserData User { get; } = new UserData();
|
||||
// Organisation.
|
||||
public class OrganisationData
|
||||
{
|
||||
public String Id { get; set; }
|
||||
public String Name { get; set; }
|
||||
public String SportId { get; set; }
|
||||
public String SportName { get; set; }
|
||||
public String RegionId { get; set; }
|
||||
public String RegionName { get; set; }
|
||||
}
|
||||
public OrganisationData Organisation { get; } = new OrganisationData();
|
||||
// Reference data.
|
||||
public List<CodeDesc> EventTypes { get; } = new List<CodeDesc>();
|
||||
public String EventTypeDefault { get; set; }
|
||||
}
|
||||
//-------------------------------------------------------------------
|
||||
[HttpPost]
|
||||
[Route("Organisation/Ajax/GetEventList")]
|
||||
[Route("Organisation/Ajax/GetEvents")]
|
||||
public IActionResult Ajax_GetEventList(Model_Organisation_Events model)
|
||||
{
|
||||
String fn = GetType().Name + ".Ajax_GetEventList";
|
||||
String messageTitle = Localiser["organisation.caption.events"];
|
||||
AjaxResponse_EventList responseData = new AjaxResponse_EventList(model);
|
||||
|
||||
// Validate session and referrer.
|
||||
if (!ValidReferer) return Forbid();
|
||||
if (!ValidUserSession) return GetAjaxResult_InvalidSession(responseData);
|
||||
RefreshModel(model);
|
||||
SysId userAccountId = SessionUserAccountId;
|
||||
|
||||
// Record disposable items as they are created so all can be disposed when needed.
|
||||
using (DisposableCollection<IDisposable> disposableItems = new DisposableCollection<IDisposable>())
|
||||
{
|
||||
|
||||
// Organisation.
|
||||
SysId organisationId = model.ExtractSysId(model.Filter.OrganisationId);
|
||||
SaxOrganisation organisation = AccountMgr.GetOrganisationById(organisationId);
|
||||
disposableItems.Add(organisation);
|
||||
if (organisation == null || !organisation.IsStatusActive)
|
||||
{
|
||||
SaLogger.Warn(fn + " " + (organisation == null ? "Invalid" : "Inactive") + " organisation for Event list. OrganisationId: '" + model.Filter.OrganisationId + "'");
|
||||
return Json(responseData.SetPopupMessage(messageTitle, Localiser["msg.error.system"]));
|
||||
}
|
||||
|
||||
if (organisation != null)
|
||||
{
|
||||
// Store filter data.
|
||||
SessionData_Online.Filter.SetMemberOrganisation(organisation);
|
||||
|
||||
// Reference data - organisationEvent types.
|
||||
foreach (TypeCodeDesc eventType in EventTypeCodes)
|
||||
responseData.EventTypes.Add(eventType.Code, Localiser.GetEventTypeCaption((Sax.EventType)eventType.Type));
|
||||
// ToDo: Organisation default Event Type.
|
||||
responseData.EventTypeDefault = EventTypeCodes.GetCodeForType(Sax.EventType.Playing);
|
||||
|
||||
// User organisation.
|
||||
SaxUserOrganisation.Params prmUserOrganisation = new SaxUserOrganisation.Params();
|
||||
prmUserOrganisation.UserAccountIdsIncluded.Add(userAccountId);
|
||||
prmUserOrganisation.OrganisationIdsIncluded.Add(organisationId);
|
||||
prmUserOrganisation.UserAccountStatusCat = SaxUserAccount.StatusCat.ActiveOnly;
|
||||
prmUserOrganisation.StatusCat = SaxUserOrganisation.StatusCat.ActiveOnly;
|
||||
SaxUserOrganisation userOrganisation = AccountMgr.GetUserOrganisation(prmUserOrganisation);
|
||||
disposableItems.Add(userOrganisation);
|
||||
if (userOrganisation == null)
|
||||
{
|
||||
SaLogger.Warn(fn + " Invalid/inactive user organisation for Event list. UserAccountId: " + SysId.ToString(userAccountId) + ". OrganisationId: " + model.Filter.OrganisationId + ".");
|
||||
return Json(responseData.SetPopupMessage(messageTitle, Localiser["msg.error.system"]));
|
||||
}
|
||||
|
||||
// Organisation.
|
||||
responseData.Organisation.Id = SysId.ToString(organisation.Id);
|
||||
responseData.Organisation.Name = organisation.Name;
|
||||
responseData.Organisation.SportId = model.GetEncryptedSportId(organisation.SportIdPrimary);
|
||||
responseData.Organisation.SportName = model.GetSportCaption(organisation.SportIdPrimary);
|
||||
responseData.Organisation.RegionId = model.GetEncryptedRegionId(organisation.RegionIdPrimary);
|
||||
responseData.Organisation.RegionName = model.GetRegionCaption(organisation.RegionIdPrimary);
|
||||
|
||||
// User details.
|
||||
responseData.User.CanManage = userOrganisation.CanManageSchedule;
|
||||
|
||||
// Item filter.
|
||||
SaxOrganisationEvent.Params prmEvent = new SaxOrganisationEvent.Params();
|
||||
prmEvent.UserAccountIdsIncluded.Add(userAccountId);
|
||||
prmEvent.OrganisationIdsIncluded.Add(organisationId);
|
||||
switch (model.Filter.Period.PeriodType)
|
||||
{
|
||||
case Model_Organisation_Events.PeriodType.FromThisMonth:
|
||||
prmEvent.EventFrom = DateUtil.StartOfMonth(DateTime.Today);
|
||||
break;
|
||||
case Model_Organisation_Events.PeriodType.FromLastMonth:
|
||||
prmEvent.EventFrom = DateUtil.StartOfMonth(DateUtil.IncrementMonth(DateTime.Today, -1));
|
||||
break;
|
||||
case Model_Organisation_Events.PeriodType.FromNextMonth:
|
||||
prmEvent.EventFrom = DateUtil.StartOfMonth(DateUtil.IncrementMonth(DateTime.Today, 1));
|
||||
break;
|
||||
case Model_Organisation_Events.PeriodType.FromThisWeek:
|
||||
default:
|
||||
prmEvent.EventFrom = DateUtil.StartOfWorkingWeek(DateTime.Today);
|
||||
break;
|
||||
}
|
||||
prmEvent.EventFilter = model.Filter.Event;
|
||||
prmEvent.StatusCat = SaxOrganisationEvent.StatusCat.NotDeleted;
|
||||
prmEvent.SortColumns.Add(ActivityMgr.GetOrganisationEventColumnDfn(SaxOrganisationEvent.Column.EventAt_DateTime));
|
||||
model.Paging.ItemTotal = (ulong)ActivityMgr.GetOrganisationEventCount(prmEvent);
|
||||
model.PopulatePagingTo(prmEvent.ResultsPaging);
|
||||
|
||||
// Item columns.
|
||||
ColumnDfn colId = ActivityMgr.GetOrganisationEventColumnDfn(SaxOrganisationEvent.Column.Id);
|
||||
ColumnDfn colEventAt = ActivityMgr.GetOrganisationEventColumnDfn(SaxOrganisationEvent.Column.EventAt_DateTime);
|
||||
ColumnDfn colEventTo = ActivityMgr.GetOrganisationEventColumnDfn(SaxOrganisationEvent.Column.EventTo_DateTime);
|
||||
ColumnDfn colEventTypeCode = ActivityMgr.GetOrganisationEventColumnDfn(SaxOrganisationEvent.Column.EventTypeCode);
|
||||
ColumnDfn colSummary = ActivityMgr.GetOrganisationEventColumnDfn(SaxOrganisationEvent.Column.Summary);
|
||||
ColumnDfn colRegionId = ActivityMgr.GetOrganisationEventColumnDfn(SaxOrganisationEvent.Column.RegionIdCountry);
|
||||
ColumnDfn colRegionName = ActivityMgr.GetOrganisationEventColumnDfn(SaxOrganisationEvent.Column.Region_Name);
|
||||
ColumnDfn colSportId = ActivityMgr.GetOrganisationEventColumnDfn(SaxOrganisationEvent.Column.SportIdPrimary);
|
||||
ColumnDfn colSportName = ActivityMgr.GetOrganisationEventColumnDfn(SaxOrganisationEvent.Column.Sport_Name);
|
||||
ColumnDfn colPublishedOn = ActivityMgr.GetOrganisationEventColumnDfn(SaxOrganisationEvent.Column.PublishedAt_Date);
|
||||
ColumnDfn colExpiresOn = ActivityMgr.GetOrganisationEventColumnDfn(SaxOrganisationEvent.Column.ExpiresAt_Date);
|
||||
ColumnDfn colStatus = ActivityMgr.GetOrganisationEventColumnDfn(SaxOrganisationEvent.Column.Status);
|
||||
ColumnDfn colCreatedOn = ActivityMgr.GetOrganisationEventColumnDfn(SaxOrganisationEvent.Column.CreateOn_Date);
|
||||
List<ColumnDfn> columns = new List<ColumnDfn>()
|
||||
{
|
||||
colId, colEventAt, colEventTo, colEventTypeCode, colSummary,
|
||||
colRegionId, colRegionName, colSportId, colSportName,
|
||||
colPublishedOn, colExpiresOn,
|
||||
colStatus, colCreatedOn
|
||||
};
|
||||
|
||||
// Sort columns.
|
||||
colCreatedOn.SortAscending = false;
|
||||
prmEvent.SortColumns.Add(colCreatedOn);
|
||||
|
||||
// Query items.
|
||||
using (DbResultSet resultSet = ActivityMgr.ExecuteOrganisationEventQuery(columns, prmEvent))
|
||||
{
|
||||
while (resultSet != null && resultSet.HasRows && resultSet.NextRecord())
|
||||
{
|
||||
NamedValue.Map values = resultSet.GetRecordValues();
|
||||
DateTime eventAt = values.GetDateTime(colEventAt.DataName);
|
||||
DateTime? eventTo = values.GetDateTime(colEventTo.DataName);
|
||||
EventListData eventData = new EventListData()
|
||||
{
|
||||
Id = model.EncryptId(new SysId(values.GetLong(colId.DataName))),
|
||||
EventAtDateFmt = Localiser.FormatDate(values.GetDateTime(colEventAt.DataName)),
|
||||
TypeCode = values.GetString(colEventTypeCode.DataName),
|
||||
TypeDesc = Localiser.GetEventTypeCaption((Sax.EventType)EventTypeCodes.GetTypeForCode(values.GetString(colEventTypeCode.DataName))),
|
||||
Summary = ActivityMgr.GetOrganisationEventDataValue(colSummary, values).AsString(),
|
||||
RegionCaptionCountry = model.GetRegionCaption(SysId.ToSysId(values.GetString(colRegionId.DataName))),
|
||||
SportCaptionPrimary = model.GetSportCaption(SysId.ToSysId(values.GetString(colSportId.DataName))),
|
||||
CreatedOnFmt = Localiser.FormatDate(values.GetDateTime(colCreatedOn.DataName)),
|
||||
PublishedOnFmt = Localiser.FormatDate(values.GetDateTime(colPublishedOn.DataName)),
|
||||
ExpiresOnFmt = Localiser.FormatDate(values.GetDateTime(colExpiresOn.DataName)),
|
||||
StatusCode = values.GetString(colStatus.DataName),
|
||||
StatusDesc = SacsSystem.GetStatusDescForCode(values.GetString(colStatus.DataName))
|
||||
};
|
||||
if (SaxOrganisationEvent.HasValidEventTime(eventAt))
|
||||
eventData.EventAtTimeFmt = DateUtil.Format(eventAt, "HH:mm");
|
||||
if (DateUtil.IsValid(eventTo) && eventAt.Date != ((DateTime)eventTo).Date)
|
||||
eventData.EventToDateFmt = Localiser.FormatDate(eventTo);
|
||||
if (SaxOrganisationEvent.HasValidEventTime(eventTo))
|
||||
eventData.EventToTimeFmt = DateUtil.Format(eventTo, "HH:mm");
|
||||
if (DateUtil.IsValid(eventTo) && eventTo > eventAt)
|
||||
eventData.EventAtTimeFmt = DateUtil.FormatNumberOfSeconds(((DateTime)eventTo - eventAt).TotalSeconds);
|
||||
responseData.Events.Add(eventData);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (model.Paging.IsPaged)
|
||||
model.Paging.ItemCount = (ushort)responseData.Events.Count;
|
||||
|
||||
// Complete response.
|
||||
responseData.SetPaging(model);
|
||||
responseData.Success = true;
|
||||
return Json(responseData);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Get Event ajax request.
|
||||
//-------------------------------------------------------------------
|
||||
private class AjaxResponse_Event : AjaxResponse_Data
|
||||
{
|
||||
// Construction.
|
||||
public AjaxResponse_Event(SaxModel_Online model) : base(model) { }
|
||||
// Event details.
|
||||
public EventItemData Event { get; } = new EventItemData();
|
||||
}
|
||||
//-------------------------------------------------------------------
|
||||
[HttpPost]
|
||||
[Route("Organisation/Ajax/GetEvent")]
|
||||
public IActionResult Ajax_GetEvent(Model_Organisation_Events model)
|
||||
{
|
||||
String fn = GetType().Name + ".Ajax_GetEvent";
|
||||
String messageTitle = Localiser["organisation.caption.event"];
|
||||
AjaxResponse_Event responseData = new AjaxResponse_Event(model);
|
||||
|
||||
// Validate session and referrer.
|
||||
if (!ValidReferer) return Forbid();
|
||||
if (!ValidUserSession) return GetAjaxResult_InvalidSession(responseData);
|
||||
RefreshModel(model);
|
||||
|
||||
// Record disposable items as they are created so all can be disposed when needed.
|
||||
using (DisposableCollection<IDisposable> disposableItems = new DisposableCollection<IDisposable>())
|
||||
{
|
||||
|
||||
// Identify item.
|
||||
SysId eventId = model.ExtractSysId(model.EventId);
|
||||
if (!SysId.IsValid(eventId))
|
||||
return Json(responseData.SetPopupMessage(messageTitle, Localiser["msg.error.item.id.not.specified"]));
|
||||
|
||||
// Retrieve item.
|
||||
SaxOrganisationEvent organisationEvent = ActivityMgr.GetOrganisationEventById(eventId);
|
||||
disposableItems.Add(organisationEvent);
|
||||
if (organisationEvent == null)
|
||||
{
|
||||
SaLogger.Warn(fn + " Failed to retrieve Organisation Event for Id: '" + model.EventId + "'");
|
||||
return Json(responseData.SetPopupMessage(messageTitle, Localiser["msg.error.item.id.not.found"]));
|
||||
}
|
||||
|
||||
// Validate organisation.
|
||||
SaxOrganisation organisation = AccountMgr.GetOrganisationById(organisationEvent.OrganisationId);
|
||||
disposableItems.Add(organisation);
|
||||
if (organisation == null || !organisation.IsStatusActive)
|
||||
{
|
||||
SaLogger.Warn(fn + " " + (organisation == null ? "Invalid" : "Inactive") + " organisation for Event. OrganisationId: '" + organisationEvent.OrganisationId + "'");
|
||||
return Json(responseData.SetPopupMessage(messageTitle, Localiser["msg.error.system"]));
|
||||
}
|
||||
|
||||
// Make a note of the selected Organisation.
|
||||
SessionData_Online.Filter.SetMemberOrganisation(organisation);
|
||||
|
||||
// Construct response.
|
||||
PopulateEventResponseItemData(model, organisationEvent, responseData.Event);
|
||||
}
|
||||
|
||||
// Complete response.
|
||||
responseData.Success = true;
|
||||
return Json(responseData);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Store Event ajax request.
|
||||
//-------------------------------------------------------------------
|
||||
[HttpPost]
|
||||
[Route("Organisation/Ajax/StoreEvent")]
|
||||
public IActionResult Ajax_StoreEvent(Model_Organisation_Events model)
|
||||
{
|
||||
String fn = GetType().Name + ".Ajax_StoreEvent";
|
||||
String messageTitle = Localiser["organisation.caption.event"];
|
||||
AjaxResponse_Event responseData = new AjaxResponse_Event(model);
|
||||
|
||||
// Validate session and referrer.
|
||||
if (!ValidReferer) return Forbid();
|
||||
if (!ValidUserSession) return GetAjaxResult_InvalidSession(responseData);
|
||||
RefreshModel(model);
|
||||
|
||||
// Record disposable items as they are created so all can be disposed when needed.
|
||||
using (DisposableCollection<IDisposable> disposableItems = new DisposableCollection<IDisposable>())
|
||||
{
|
||||
|
||||
// Validate item properties.
|
||||
model.ValidateEventData(responseData);
|
||||
if (responseData.HasControlErrors())
|
||||
return Json(responseData);
|
||||
|
||||
// Validate Event against Id against 'Exists' flag.
|
||||
SysId eventId = model.ExtractSysId(model.EventId);
|
||||
bool eventExists = StringUtil.ToBool(model.EventExists);
|
||||
if (eventExists && !SysId.IsValid(eventId))
|
||||
{
|
||||
SaLogger.Warn(fn + " Id not specified for existing Event.");
|
||||
return Json(responseData.SetGoHome(messageTitle, Localiser["msg.error.system"]));
|
||||
}
|
||||
if (!eventExists && SysId.IsValid(eventId))
|
||||
{
|
||||
SaLogger.Warn(fn + " Id specified for new Event: '" + model.EventId + "'");
|
||||
return Json(responseData.SetGoHome(messageTitle, Localiser["msg.error.system"]));
|
||||
}
|
||||
|
||||
// Retrieve existing item.
|
||||
SaxOrganisationEvent organisationEvent = ActivityMgr.GetOrganisationEventById(eventId);
|
||||
disposableItems.Add(organisationEvent);
|
||||
if (organisationEvent == null && SysId.IsValid(eventId))
|
||||
{
|
||||
SaLogger.Warn(fn + " Failed to retrieve organisationEvent for Id: '" + model.EventId + "'");
|
||||
return Json(responseData.SetPopupMessage(messageTitle, Localiser["msg.error.item.id.not.found"]));
|
||||
}
|
||||
|
||||
// Validate the Organisation.
|
||||
SysId organisationId = model.ExtractSysId(model.EventOrganisationId);
|
||||
if (!SysId.IsValid(organisationId))
|
||||
{
|
||||
SaLogger.Warn(fn + " Organisation Id not specified for Event.");
|
||||
return Json(responseData.SetGoHome(messageTitle, Localiser["msg.error.system"]));
|
||||
}
|
||||
SaxOrganisation organisation = AccountMgr.GetOrganisationById(organisationId);
|
||||
disposableItems.Add(organisation);
|
||||
if (organisation == null || !organisation.IsStatusActive)
|
||||
{
|
||||
SaLogger.Warn(fn + " " + (organisation == null ? "Invalid" : "Inactive") + " organisation for Event. OrganisationId: '" + model.EventOrganisationId + "'");
|
||||
return Json(responseData.SetPopupMessage(messageTitle, Localiser["msg.error.system"]));
|
||||
}
|
||||
if (organisationEvent != null && !organisationEvent.OrganisationId.Equals(organisationId))
|
||||
{
|
||||
SaLogger.Warn(fn + " Inconsistent Organisation Id specified for Event. Expected: " + organisationEvent.OrganisationId + ". Found: " + organisationId);
|
||||
return Json(responseData.SetGoHome(messageTitle, Localiser["msg.error.system"]));
|
||||
}
|
||||
|
||||
// Ensure that the user has the correct role to update Events for this organisation.
|
||||
if (!AccountMgr.UserHasAnyOrganisationRole(SessionUserAccountId, organisationId, new[] { Sax.OrganisationRole.Admin, Sax.OrganisationRole.ScheduleAdmin }))
|
||||
{
|
||||
SaLogger.Warn(fn + " User doesn't have 'Event Admin' role for Organisation Id: " + organisationId);
|
||||
return Json(responseData.SetGoHome(messageTitle, Localiser["msg.error.system"]));
|
||||
}
|
||||
|
||||
// Create new item if required.
|
||||
if (organisationEvent == null)
|
||||
{
|
||||
organisationEvent = ActivityMgr.CreateOrganisationEvent(organisationId);
|
||||
disposableItems.Add(organisationEvent);
|
||||
}
|
||||
|
||||
// Populate item properties.
|
||||
if (model.EventSportIdPrimary != null)
|
||||
organisationEvent.SportIdPrimary = model.ExtractSysId(model.EventSportIdPrimary);
|
||||
if (model.EventRegionIdCountry != null)
|
||||
organisationEvent.RegionIdCountry = model.ExtractSysId(model.EventRegionIdCountry);
|
||||
if (model.EventAtDate != null)
|
||||
{
|
||||
// 'At' date.
|
||||
organisationEvent.EventAt = model.ParseDateFromForm(model.EventAtDate);
|
||||
if (model.EventAtTimeSet && !StringUtil.IsBlank(model.EventAtTime))
|
||||
{
|
||||
// For midnight (00:00) set +1 minute so that the value is treated as a valid start time.
|
||||
if (model.EventAtTime.Equals("00:00"))
|
||||
model.EventAtTime = "00:01";
|
||||
organisationEvent.EventAt = DateUtil.SetTime(organisationEvent.EventAt, DateUtil.ParseExact(model.EventAtTime, "HH:mm"));
|
||||
}
|
||||
if (model.EventToDateSet || model.EventToTimeSet)
|
||||
{
|
||||
// 'To' date.
|
||||
organisationEvent.EventTo = organisationEvent.EventAt;
|
||||
if (model.EventToDate != null && model.EventToDateSet)
|
||||
organisationEvent.EventTo = model.ParseDateFromForm(model.EventToDate);
|
||||
// 'To' time.
|
||||
if (model.EventAtTimeSet && model.EventToTimeSet && !StringUtil.IsBlank(model.EventToTime))
|
||||
{
|
||||
// For midnight (00:00) set +1 minute so that the value is treated as a valid finish time.
|
||||
if (model.EventToTime.Equals("00:00"))
|
||||
model.EventToTime = "00:01";
|
||||
organisationEvent.EventTo = DateUtil.SetTime(organisationEvent.EventTo ?? organisationEvent.EventAt, DateUtil.ParseExact(model.EventToTime, "HH:mm"));
|
||||
}
|
||||
}
|
||||
else organisationEvent.EventTo = null;
|
||||
}
|
||||
if (model.EventTypeCode != null)
|
||||
organisationEvent.EventType = (Sax.EventType)EventTypeCodes.GetTypeForCode(model.EventTypeCode);
|
||||
if (model.EventSummary != null)
|
||||
organisationEvent.Summary = model.EventSummary;
|
||||
if (model.EventDetails != null)
|
||||
organisationEvent.Details = model.EventDetails;
|
||||
if (model.EventStatusCode != null)
|
||||
organisationEvent.Status = model.EventStatus;
|
||||
|
||||
// Store item.
|
||||
bool eventCreated = false;
|
||||
if (!SysId.IsValid(organisationEvent.Id))
|
||||
{
|
||||
if (!ActivityMgr.InsertOrganisationEvent(organisationEvent, DbUpdateInfo))
|
||||
{
|
||||
SaLogger.Warn(fn + " Failed to insert organisationEvent: " + ActivityMgr.ErrorStateMessage);
|
||||
return Json(responseData.SetPopupMessage(messageTitle, Localiser["msg.error.item.insert.failed"]));
|
||||
}
|
||||
eventCreated = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!ActivityMgr.UpdateOrganisationEvent(organisationEvent, DbUpdateInfo))
|
||||
{
|
||||
SaLogger.Warn(fn + " Failed to update organisationEvent [Id:" + SysId.ToString(organisationEvent.Id) + "]: " + ActivityMgr.ErrorStateMessage);
|
||||
return Json(responseData.SetPopupMessage(messageTitle, Localiser["msg.error.item.update.failed"]));
|
||||
}
|
||||
}
|
||||
SaLogger.Info(fn + " Event " + (eventCreated ? "created" : "updated") + ". Id: " + organisationEvent.Id.ToString() + ". User: " + SessionData.User.EmailAddress + ". Organisation: " + organisation.Name, true);
|
||||
|
||||
// Store Event Activity Index data.
|
||||
ActivityConsole.StoreActivityIndex(organisationEvent, DbUpdateInfo);
|
||||
|
||||
// Construct response.
|
||||
PopulateEventResponseItemData(model, organisationEvent, responseData.Event);
|
||||
}
|
||||
|
||||
// Complete response.
|
||||
responseData.Success = true;
|
||||
return Json(responseData);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
}
|
||||
//=======================================================================
|
||||
}
|
||||
+727
@@ -0,0 +1,727 @@
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Sarand.Net.Standard.Base.App;
|
||||
using Sarand.Net.Standard.Base.Bus;
|
||||
using Sarand.Net.Standard.Base.Core;
|
||||
using Sarand.Net.Standard.Base.Dbas;
|
||||
using Sarand.Net.Standard.Base.Email;
|
||||
using Sarand.Net.Standard.Base.Utils;
|
||||
using Saxonite.Net.Core.Web.Online.Models;
|
||||
using Saxonite.Net.Standard.Base.App;
|
||||
using Saxonite.Net.Standard.Base.Bus;
|
||||
using Saxonite.Net.Standard.Base.Helpers;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Saxonite.Net.Core.Web.Online.Controllers
|
||||
{
|
||||
//=======================================================================
|
||||
// Online Organisation Controller - Members - Ajax actions.
|
||||
//=======================================================================
|
||||
partial class OrganisationController
|
||||
{
|
||||
//-------------------------------------------------------------------
|
||||
// Organisation Member data.
|
||||
private class MemberListData : AjaxResponse_Data.ItemData_Base
|
||||
{
|
||||
public String UserAccountId { get; set; }
|
||||
public bool? CurrentUser { get; set; } = null;
|
||||
public String EmailAddress { get; set; }
|
||||
public String DisplayName { get; set; }
|
||||
public String MemberRoles { get; set; }
|
||||
public List<String> RoleCodes { get; set; } = new List<string>();
|
||||
public List<CodeDesc> Roles { get; set; } = new List<CodeDesc>();
|
||||
public String AdminComment { get; set; }
|
||||
}
|
||||
private class MemberItemData : MemberListData
|
||||
{
|
||||
public String Title { get; set; }
|
||||
public String FirstName { get; set; }
|
||||
public String LastName { get; set; }
|
||||
}
|
||||
private void PopulateMemberResponseListData(Model_Organisation_Members model, SaxUserOrganisation userOrganisation, SaxUserAccount userAccount, SaxOrganisation organisation, MemberListData data)
|
||||
{
|
||||
data.Id = model.EncryptId(userOrganisation.Id);
|
||||
data.UserAccountId = model.EncryptId(userOrganisation.UserAccountId);
|
||||
if (userOrganisation.UserAccountId.Equals(SessionUserAccountId)) data.CurrentUser = true;
|
||||
data.EmailAddress = userAccount.EmailAddress;
|
||||
data.DisplayName = userAccount.GetDisplayName();
|
||||
data.RoleCodes.Clear();
|
||||
data.Roles.Clear();
|
||||
foreach (String memberRoleCode in userOrganisation.GetOrganisationRoleCodes())
|
||||
{
|
||||
if (StringUtil.IsEmpty(memberRoleCode.Trim())) continue;
|
||||
Sax.OrganisationRole organisationRole = (Sax.OrganisationRole)OrganisationRoleCodes.GetTypeForCode(memberRoleCode);
|
||||
if (organisationRole <= 0 || organisationRole == Sax.OrganisationRole.Member) continue;
|
||||
data.RoleCodes.Add(memberRoleCode);
|
||||
data.Roles.Add(memberRoleCode, Localiser.GetOrganisationRoleCaption(organisationRole));
|
||||
}
|
||||
data.MemberRoles = data.Roles.Select(item => item.Desc).ToList().Concat(", ");
|
||||
data.AdminComment = userOrganisation.AdminComment;
|
||||
// NB UserAccount status (not UserOrganisation).
|
||||
data.StatusCode = userAccount.StatusCode;
|
||||
data.StatusDesc = userAccount.StatusDesc;
|
||||
data.CreatedOnFmt = Localiser.FormatDate(userOrganisation.CreateStamp.On);
|
||||
}
|
||||
private void PopulateMemberResponseItemData(Model_Organisation_Members model, SaxUserOrganisation userOrganisation, SaxUserAccount userAccount, SaxOrganisation organisation, MemberItemData data)
|
||||
{
|
||||
PopulateMemberResponseListData(model, userOrganisation, userAccount, organisation, data as MemberListData);
|
||||
data.Title = userAccount.Title;
|
||||
data.FirstName = userAccount.FirstName;
|
||||
data.LastName = userAccount.LastName;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Get Member List ajax request.
|
||||
//-------------------------------------------------------------------
|
||||
private class AjaxResponse_MemberList : AjaxResponse_Data
|
||||
{
|
||||
// Construction.
|
||||
public AjaxResponse_MemberList(SaxModel_Online model) : base(model) { }
|
||||
// Member list.
|
||||
public List<MemberListData> Members { get; } = new List<MemberListData>();
|
||||
// User profile.
|
||||
public class UserData
|
||||
{
|
||||
public bool CanManage { get; set; }
|
||||
}
|
||||
public UserData User { get; } = new UserData();
|
||||
// Reference data.
|
||||
public List<CodeDesc> Titles { get; } = new List<CodeDesc>();
|
||||
public List<CodeDesc> MemberRoles { get; } = new List<CodeDesc>();
|
||||
}
|
||||
//-------------------------------------------------------------------
|
||||
[HttpPost]
|
||||
[Route("Organisation/Ajax/GetMemberList")]
|
||||
[Route("Organisation/Ajax/GetMembers")]
|
||||
public IActionResult Ajax_GetMemberList(Model_Organisation_Members model)
|
||||
{
|
||||
String fn = GetType().Name + ".Ajax_GetMemberList";
|
||||
String messageTitle = Localiser["organisation.members"];
|
||||
AjaxResponse_MemberList responseData = new AjaxResponse_MemberList(model);
|
||||
|
||||
// Validate session and referrer.
|
||||
if (!ValidReferer) return Forbid();
|
||||
if (!ValidUserSession) return GetAjaxResult_InvalidSession(responseData);
|
||||
RefreshModel(model);
|
||||
|
||||
// Record disposable items as they are created so all can be disposed when needed.
|
||||
using (DisposableCollection<IDisposable> disposableItems = new DisposableCollection<IDisposable>())
|
||||
{
|
||||
|
||||
// Organisation.
|
||||
SysId organisationId = model.ExtractSysId(model.Filter.OrganisationId);
|
||||
SaxOrganisation organisation = AccountMgr.GetOrganisationById(organisationId);
|
||||
disposableItems.Add(organisation);
|
||||
if (organisation == null || !organisation.IsStatusActive)
|
||||
{
|
||||
SaLogger.Warn(fn + " " + (organisation == null ? "Invalid" : "Inactive") + " organisation for Member list. OrganisationId: '" + model.Filter.OrganisationId + "'");
|
||||
return Json(responseData.SetPopupMessage(messageTitle, Localiser["msg.error.system"]));
|
||||
}
|
||||
|
||||
// Store filter data.
|
||||
SessionData_Online.Filter.SetMemberOrganisation(organisation);
|
||||
|
||||
// Reference data - titles.
|
||||
foreach (TypeCodeDesc title in SaxSystem.GetCodesOfType(Sax.CodeType.Title))
|
||||
// ToDo Title translations.
|
||||
responseData.Titles.Add(title.Code, title.Desc);
|
||||
|
||||
// Reference data - member roles.
|
||||
foreach (TypeCodeDesc memberRole in OrganisationRoleCodes.FindAll(item => item.Type != (int)Sax.OrganisationRole.Member))
|
||||
responseData.MemberRoles.Add(memberRole.Code, Localiser.GetOrganisationRoleCaption((Sax.OrganisationRole)memberRole.Type));
|
||||
|
||||
// Session User roles.
|
||||
responseData.User.CanManage = AccountMgr.UserHasAnyOrganisationRole(SessionUserAccountId, organisation.Id, new List<Sax.OrganisationRole> { Sax.OrganisationRole.Admin, Sax.OrganisationRole.MemberAdmin });
|
||||
|
||||
// Item filter.
|
||||
SaxUserOrganisation.Params prmMember = new SaxUserOrganisation.Params();
|
||||
prmMember.OrganisationIdsIncluded.Add(organisationId);
|
||||
prmMember.UserAccountStatusCat = responseData.User.CanManage ? SaxUserAccount.StatusCat.AwaitingOrActive : SaxUserAccount.StatusCat.ActiveOnly;
|
||||
prmMember.OrganisationMembersOnly = true;
|
||||
prmMember.UserFilterPartial = model.Filter.Member;
|
||||
prmMember.StatusCat = SaxUserOrganisation.StatusCat.ActiveOnly;
|
||||
model.Paging.ItemTotal = (ulong)AccountMgr.GetUserOrganisationCount(prmMember);
|
||||
model.PopulatePagingTo(prmMember.ResultsPaging);
|
||||
|
||||
// Item columns.
|
||||
ColumnDfn colId = AccountMgr.GetUserOrganisationColumnDfn(SaxUserOrganisation.Column.Id);
|
||||
ColumnDfn colUserAccountId = AccountMgr.GetUserOrganisationColumnDfn(SaxUserOrganisation.Column.UserAccountId);
|
||||
ColumnDfn colEmailAddress = responseData.User.CanManage ? AccountMgr.GetUserOrganisationColumnDfn(SaxUserOrganisation.Column.User_EmailAddress) : new ColumnDfn(-1, "");
|
||||
ColumnDfn colDisplayName = AccountMgr.GetUserOrganisationColumnDfn(SaxUserOrganisation.Column.User_DisplayName);
|
||||
ColumnDfn colOrganisationRoleCodes = responseData.User.CanManage ? AccountMgr.GetUserOrganisationColumnDfn(SaxUserOrganisation.Column.OrganisationRoleCodes) : new ColumnDfn(-1, "");
|
||||
ColumnDfn colUserStatus = AccountMgr.GetUserOrganisationColumnDfn(SaxUserOrganisation.Column.User_Status);
|
||||
ColumnDfn colAdminComment = responseData.User.CanManage ? AccountMgr.GetUserOrganisationColumnDfn(SaxUserOrganisation.Column.AdminComment) : new ColumnDfn(-1, "");
|
||||
ColumnDfn colCreatedOn = AccountMgr.GetUserOrganisationColumnDfn(SaxUserOrganisation.Column.CreateOn_Date);
|
||||
List<ColumnDfn> columns = new List<ColumnDfn>()
|
||||
{
|
||||
colId, colUserAccountId , colEmailAddress, colDisplayName,
|
||||
colOrganisationRoleCodes, colUserStatus,
|
||||
colAdminComment, colCreatedOn
|
||||
};
|
||||
|
||||
// Sort columns.
|
||||
colCreatedOn.SortAscending = false;
|
||||
prmMember.SortColumns.Add(colDisplayName);
|
||||
|
||||
// Query items.
|
||||
using (DbResultSet resultSet = AccountMgr.ExecuteUserOrganisationQuery(columns, prmMember))
|
||||
{
|
||||
while (resultSet != null && resultSet.HasRows && resultSet.NextRecord())
|
||||
{
|
||||
NamedValue.Map values = resultSet.GetRecordValues();
|
||||
MemberListData memberData = new MemberListData()
|
||||
{
|
||||
Id = model.EncryptId(new SysId(values.GetLong(colId.DataName))),
|
||||
UserAccountId = model.EncryptId(new SysId(values.GetLong(colUserAccountId.DataName))),
|
||||
EmailAddress = values.GetString(colEmailAddress.DataName),
|
||||
DisplayName = AccountMgr.GetUserOrganisationDataValue(colDisplayName, values).ToString(),
|
||||
CreatedOnFmt = Localiser.FormatDate(values.GetDateTime(colCreatedOn.DataName)),
|
||||
AdminComment = values.GetString(colAdminComment.DataName),
|
||||
// NB UserAccount status (not UserOrganisation).
|
||||
StatusCode = values.GetString(colUserStatus.DataName),
|
||||
StatusDesc = SacsSystem.GetStatusDescForCode(values.GetString(colUserStatus.DataName))
|
||||
};
|
||||
if (model.ExtractSysId(memberData.UserAccountId).Equals(SessionUserAccountId)) memberData.CurrentUser = true;
|
||||
String memberRoleCodes = values.GetString(colOrganisationRoleCodes.DataName);
|
||||
foreach (String memberRoleCode in StringListUtil.Split(memberRoleCodes, SaxUserOrganisation.UserOrgnisationRoleDelim))
|
||||
{
|
||||
if (StringUtil.IsEmpty(memberRoleCode.Trim())) continue;
|
||||
Sax.OrganisationRole organisationRole = (Sax.OrganisationRole)OrganisationRoleCodes.GetTypeForCode(memberRoleCode);
|
||||
if (organisationRole <= 0 || organisationRole == Sax.OrganisationRole.Member) continue;
|
||||
memberData.RoleCodes.Add(memberRoleCode);
|
||||
memberData.Roles.Add(memberRoleCode, Localiser.GetOrganisationRoleCaption(organisationRole));
|
||||
}
|
||||
memberData.MemberRoles = memberData.Roles.Select(item => item.Desc).ToList().Concat(", ");
|
||||
responseData.Members.Add(memberData);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (model.Paging.IsPaged)
|
||||
model.Paging.ItemCount = (ushort)responseData.Members.Count;
|
||||
|
||||
// Complete response.
|
||||
responseData.SetPaging(model);
|
||||
responseData.Success = true;
|
||||
return Json(responseData);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Get Member ajax request.
|
||||
//-------------------------------------------------------------------
|
||||
private class AjaxResponse_Member : AjaxResponse_Data
|
||||
{
|
||||
// Construction.
|
||||
public AjaxResponse_Member(SaxModel_Online model) : base(model) { }
|
||||
// Member details.
|
||||
public MemberItemData Member { get; } = new MemberItemData();
|
||||
}
|
||||
//-------------------------------------------------------------------
|
||||
[HttpPost]
|
||||
[Route("Organisation/Ajax/GetMember")]
|
||||
public IActionResult Ajax_GetMember(Model_Organisation_Members model)
|
||||
{
|
||||
String fn = GetType().Name + ".Ajax_GetMember";
|
||||
String messageTitle = Localiser["label.member"];
|
||||
AjaxResponse_Member responseData = new AjaxResponse_Member(model);
|
||||
|
||||
// Validate session and referrer.
|
||||
if (!ValidReferer) return Forbid();
|
||||
if (!ValidUserSession) return GetAjaxResult_InvalidSession(responseData);
|
||||
RefreshModel(model);
|
||||
|
||||
// Identify item.
|
||||
SysId memberId = model.ExtractSysId(model.MemberId);
|
||||
if (!SysId.IsValid(memberId))
|
||||
return Json(responseData.SetPopupMessage(messageTitle, Localiser["msg.error.item.id.not.specified"]));
|
||||
|
||||
// Record disposable items as they are created so all can be disposed when needed.
|
||||
using (DisposableCollection<IDisposable> disposableItems = new DisposableCollection<IDisposable>())
|
||||
{
|
||||
|
||||
// Retrieve item.
|
||||
SaxUserOrganisation userOrganisation = AccountMgr.GetUserOrganisationById(memberId);
|
||||
disposableItems.Add(userOrganisation);
|
||||
if (userOrganisation == null)
|
||||
{
|
||||
SaLogger.Warn(fn + " Failed to retrieve Organisation Member for Id: '" + model.MemberId + "'");
|
||||
return Json(responseData.SetPopupMessage(messageTitle, Localiser["msg.error.item.id.not.found"]));
|
||||
}
|
||||
|
||||
// Validate organisation.
|
||||
SaxOrganisation organisation = AccountMgr.GetOrganisationById(userOrganisation.OrganisationId);
|
||||
disposableItems.Add(organisation);
|
||||
if (organisation == null || !organisation.IsStatusActive)
|
||||
{
|
||||
SaLogger.Warn(fn + " " + (organisation == null ? "Invalid" : "Inactive") + " Organisation for Member. Id: '" + userOrganisation.OrganisationId + "'");
|
||||
return Json(responseData.SetPopupMessage(messageTitle, Localiser["msg.error.system"]));
|
||||
}
|
||||
|
||||
// Session User roles.
|
||||
bool userCanManageMembers = AccountMgr.UserHasAnyOrganisationRole(SessionUserAccountId, organisation.Id, new List<Sax.OrganisationRole> { Sax.OrganisationRole.Admin, Sax.OrganisationRole.MemberAdmin });
|
||||
|
||||
// Validate user account.
|
||||
SaxUserAccount userAccount = AccountMgr.GetUserAccountById(userOrganisation.UserAccountId);
|
||||
disposableItems.Add(userAccount);
|
||||
bool userActive = userAccount.IsStatusActive || (userAccount.IsStatusAwaiting && userCanManageMembers);
|
||||
if (userAccount == null || !userActive)
|
||||
{
|
||||
SaLogger.Warn(fn + " " + (organisation == null ? "Invalid" : "Inactive") + " User Account for Member. Id: '" + userOrganisation.UserAccountId + "'");
|
||||
return Json(responseData.SetPopupMessage(messageTitle, Localiser["msg.error.system"]));
|
||||
}
|
||||
|
||||
// Make a note of the selected Organisation.
|
||||
SessionData_Online.Filter.SetMemberOrganisation(organisation);
|
||||
|
||||
PopulateMemberResponseItemData(model, userOrganisation, userAccount, organisation, responseData.Member);
|
||||
}
|
||||
|
||||
// Construct response.
|
||||
responseData.Success = true;
|
||||
return Json(responseData);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Store Member ajax request.
|
||||
//-------------------------------------------------------------------
|
||||
private class AjaxResponse_StoreMember : AjaxResponse_Data
|
||||
{
|
||||
// Construction.
|
||||
public AjaxResponse_StoreMember(SaxModel_Online model) : base(model) { }
|
||||
// Member details.
|
||||
public MemberItemData Member { get; } = new MemberItemData();
|
||||
// Feedback.
|
||||
public bool? MemberNameRequired { get; set; } = null;
|
||||
}
|
||||
[HttpPost]
|
||||
[Route("Organisation/Ajax/StoreMember")]
|
||||
public IActionResult Ajax_StoreMember(Model_Organisation_Members model)
|
||||
{
|
||||
String fn = GetType().Name + ".Ajax_StoreMember";
|
||||
String messageTitle = Localiser["label.member"];
|
||||
AjaxResponse_StoreMember responseData = new AjaxResponse_StoreMember(model);
|
||||
|
||||
// Validate session and referrer.
|
||||
if (!ValidReferer) return Forbid();
|
||||
if (!ValidUserSession) return GetAjaxResult_InvalidSession(responseData);
|
||||
RefreshModel(model);
|
||||
|
||||
// Validate item properties.
|
||||
model.ValidateMemberData(responseData);
|
||||
if (responseData.HasControlErrors())
|
||||
return Json(responseData);
|
||||
|
||||
//---------------------------------------------------------------
|
||||
// User Organisation identifiers.
|
||||
// New Member:
|
||||
// Organisation Id [MemberOrganisationId].
|
||||
// Email address [MemberEmailAddress].
|
||||
// Existing member:
|
||||
// User Organisation Id [MemberId].
|
||||
//---------------------------------------------------------------
|
||||
|
||||
// Validate Member against Id against 'Exists' flag.
|
||||
SysId memberId = model.ExtractSysId(model.MemberId);
|
||||
bool memberExists = StringUtil.ToBool(model.MemberExists);
|
||||
if (memberExists && !SysId.IsValid(memberId))
|
||||
{
|
||||
SaLogger.Warn(fn + " Id not specified for existing User Organisation.");
|
||||
return Json(responseData.SetGoHome(messageTitle, Localiser["msg.error.system"]));
|
||||
}
|
||||
if (!memberExists && SysId.IsValid(memberId))
|
||||
{
|
||||
SaLogger.Warn(fn + " Id specified for new User Organisation: '" + model.MemberId + "'");
|
||||
return Json(responseData.SetGoHome(messageTitle, Localiser["msg.error.system"]));
|
||||
}
|
||||
|
||||
// Record disposable items as they are created so all can be disposed when needed.
|
||||
using (DisposableCollection<IDisposable> disposableItems = new DisposableCollection<IDisposable>())
|
||||
{
|
||||
|
||||
// Retrieve existing item.
|
||||
SaxUserOrganisation userOrganisation = AccountMgr.GetUserOrganisationById(memberId);
|
||||
disposableItems.Add(userOrganisation);
|
||||
if (userOrganisation == null && SysId.IsValid(memberId))
|
||||
{
|
||||
SaLogger.Warn(fn + " Failed to retrieve User Organisation for Id: '" + model.MemberId + "'");
|
||||
return Json(responseData.SetPopupMessage(messageTitle, Localiser["msg.error.item.id.not.found"]));
|
||||
}
|
||||
|
||||
// Validate the Organisation.
|
||||
SysId organisationId = userOrganisation != null ? userOrganisation.OrganisationId : model.ExtractSysId(model.MemberOrganisationId);
|
||||
if (!SysId.IsValid(organisationId))
|
||||
{
|
||||
SaLogger.Warn(fn + " Organisation Id not specified for Member.");
|
||||
return Json(responseData.SetGoHome(messageTitle, Localiser["msg.error.system"]));
|
||||
}
|
||||
SaxOrganisation organisation = AccountMgr.GetOrganisationById(organisationId);
|
||||
disposableItems.Add(organisation);
|
||||
if (organisation == null || !organisation.IsStatusActive)
|
||||
{
|
||||
SaLogger.Warn(fn + " " + (organisation == null ? "Invalid" : "Inactive") + " Organisation for User Organisation. OrganisationId: '" + model.MemberOrganisationId + "'");
|
||||
return Json(responseData.SetPopupMessage(messageTitle, Localiser["msg.error.system"]));
|
||||
}
|
||||
if (userOrganisation != null && !userOrganisation.OrganisationId.Equals(organisationId))
|
||||
{
|
||||
SaLogger.Warn(fn + " Inconsistent Organisation Id specified for User Organisation. Expected: " + userOrganisation.OrganisationId + ". Found: " + organisationId);
|
||||
return Json(responseData.SetGoHome(messageTitle, Localiser["msg.error.system"]));
|
||||
}
|
||||
|
||||
// Ensure that the user has the correct role to update Members for this organisation.
|
||||
bool userCanManageMembers = AccountMgr.UserHasAnyOrganisationRole(SessionUserAccountId, organisationId, new List<Sax.OrganisationRole> { Sax.OrganisationRole.Admin, Sax.OrganisationRole.MemberAdmin });
|
||||
if (!userCanManageMembers)
|
||||
{
|
||||
SaLogger.Warn(fn + " User doesn't have 'Member Admin' role for Organisation Id: " + organisationId);
|
||||
return Json(responseData.SetGoHome(messageTitle, Localiser["msg.error.system"]));
|
||||
}
|
||||
|
||||
// Validate the User Account for an existing member.
|
||||
SaxUserAccount userAccount = null;
|
||||
if (userOrganisation != null)
|
||||
{
|
||||
userAccount = AccountMgr.GetUserAccountById(userOrganisation.UserAccountId);
|
||||
disposableItems.Add(userAccount);
|
||||
bool userActive = userAccount.IsStatusActive || (userAccount.IsStatusAwaiting && userCanManageMembers);
|
||||
if (userAccount == null || !userActive)
|
||||
{
|
||||
SaLogger.Warn(fn + " " + (userAccount == null ? "Invalid" : "Inactive") + " User Account for User Organisation. UserAccountId: '" + userOrganisation.UserAccountId + "'");
|
||||
return Json(responseData.SetPopupMessage(messageTitle, Localiser["msg.error.system"]));
|
||||
}
|
||||
if (userOrganisation != null && !userOrganisation.UserAccountId.Equals(userAccount.Id))
|
||||
{
|
||||
SaLogger.Warn(fn + " Inconsistent User Account Id specified for User Organisation. Expected: " + userOrganisation.UserAccountId + ". Found: " + userAccount.Id);
|
||||
return Json(responseData.SetGoHome(messageTitle, Localiser["msg.error.system"]));
|
||||
}
|
||||
|
||||
// Validate roles for current user.
|
||||
if (userOrganisation.UserAccountId.Equals(SessionUserAccountId))
|
||||
{
|
||||
// User is modifying their own organisation member.
|
||||
if (userOrganisation.CanManageOrganisation && !model.OrganisationRoleCodes.Any(item => item.Type == (int)Sax.OrganisationRole.Admin))
|
||||
{
|
||||
// User has removed their own 'Admin' role.
|
||||
SaLogger.Warn(fn + " Unable to store member - user is attempting to remove their own 'Admin' role.");
|
||||
return Json(responseData.SetPopupMessage(messageTitle, Localiser["organisation.members.msg.remove.own.admin.role"]));
|
||||
}
|
||||
if (!userOrganisation.CanManageMembers)
|
||||
{
|
||||
SaLogger.Warn(fn + " Unable to store member - user is attempting to remove their own 'Admin' and/or 'Member Admin' role.");
|
||||
return Json(responseData.SetPopupMessage(messageTitle, Localiser["organisation.members.msg.remove.own.admin.role"]));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// New member - Lookup user by email and create new account if needed.
|
||||
if (userAccount == null)
|
||||
{
|
||||
// Check if account exists for email.
|
||||
userAccount = AccountMgr.GetUserAccountByEmailAddress(model.MemberEmailAddress);
|
||||
if (userAccount != null)
|
||||
{
|
||||
// Existing User Account - get User Organisation if available.
|
||||
userOrganisation = AccountMgr.GetUserOrganisationByUserOrganisation(userAccount.Id, organisation.Id);
|
||||
disposableItems.Add(userOrganisation);
|
||||
}
|
||||
else
|
||||
{
|
||||
// If name hasn't been specified, return to page to complete details.
|
||||
if (!StringUtil.ToBool(model.MemberNameSupplied))
|
||||
{
|
||||
responseData.SetControlError(nameof(model.MemberFirstName), Localiser["msg.validation.mandatory.value"]);
|
||||
responseData.SetControlError(nameof(model.MemberLastName), Localiser["msg.validation.mandatory.value"]);
|
||||
responseData.MemberNameRequired = true;
|
||||
responseData.Success = true;
|
||||
return Json(responseData);
|
||||
}
|
||||
|
||||
// Create new User Account.
|
||||
userAccount = AccountMgr.CreateUserAccount();
|
||||
userAccount.EmailAddress = model.MemberEmailAddress;
|
||||
userAccount.Status = SaStatus.Awaiting;
|
||||
}
|
||||
disposableItems.Add(userAccount);
|
||||
}
|
||||
|
||||
// Store user account.
|
||||
if (StringUtil.ToBool(model.MemberNameSupplied))
|
||||
{
|
||||
if (model.MemberTitle != null)
|
||||
userAccount.Title = model.MemberTitle;
|
||||
if (model.MemberFirstName != null)
|
||||
userAccount.FirstName = model.MemberFirstName;
|
||||
if (model.MemberLastName != null)
|
||||
userAccount.LastName = model.MemberLastName;
|
||||
}
|
||||
if (!SysId.IsValid(userAccount.Id))
|
||||
{
|
||||
if (!AccountMgr.InsertUserAccount(userAccount, DbUpdateInfo))
|
||||
{
|
||||
SaLogger.Warn(fn + " Failed to insert User Account: " + AccountMgr.ErrorStateMessage);
|
||||
return Json(responseData.SetPopupMessage(messageTitle, Localiser["msg.error.item.insert.failed"]));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!AccountMgr.UpdateUserAccount(userAccount, DbUpdateInfo))
|
||||
{
|
||||
SaLogger.Warn(fn + " Failed to insert User Account: " + AccountMgr.ErrorStateMessage);
|
||||
return Json(responseData.SetPopupMessage(messageTitle, Localiser["msg.error.item.update.failed"]));
|
||||
}
|
||||
}
|
||||
|
||||
// Create new item if required.
|
||||
if (userOrganisation == null)
|
||||
{
|
||||
userOrganisation = AccountMgr.CreateUserOrganisation(userAccount.Id, organisation.Id);
|
||||
disposableItems.Add(userOrganisation);
|
||||
}
|
||||
|
||||
// User Organisation Roles.
|
||||
if (model.MemberRoleCodes != null)
|
||||
userOrganisation.OrganisationRoles = SaxUserOrganisation.GetOrganisationRolesFromCodes(model.GetMemberRoleCodes());
|
||||
// Ensure user has member role.
|
||||
userOrganisation.AddOrganisationRole(Sax.OrganisationRole.Member);
|
||||
|
||||
// User organisation properties.
|
||||
if (model.MemberAdminComment != null)
|
||||
userOrganisation.AdminComment = model.MemberAdminComment;
|
||||
userOrganisation.Status = SaStatus.Active;
|
||||
|
||||
// Store item.
|
||||
if (!SysId.IsValid(userOrganisation.Id))
|
||||
{
|
||||
if (!AccountMgr.InsertUserOrganisation(userOrganisation, DbUpdateInfo))
|
||||
{
|
||||
SaLogger.Warn(fn + " Failed to insert User Organisation: " + AccountMgr.ErrorStateMessage);
|
||||
return Json(responseData.SetPopupMessage(messageTitle, Localiser["msg.error.item.insert.failed"]));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!AccountMgr.UpdateUserOrganisation(userOrganisation, DbUpdateInfo))
|
||||
{
|
||||
SaLogger.Warn(fn + " Failed to update User Organisation [Id:" + SysId.ToString(userOrganisation.Id) + "]: " + AccountMgr.ErrorStateMessage);
|
||||
return Json(responseData.SetPopupMessage(messageTitle, Localiser["msg.error.item.update.failed"]));
|
||||
}
|
||||
}
|
||||
|
||||
// Construct response.
|
||||
PopulateMemberResponseItemData(model, userOrganisation, userAccount, organisation, responseData.Member);
|
||||
}
|
||||
|
||||
// Complete response.
|
||||
responseData.Success = true;
|
||||
return Json(responseData);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Activate Member ajax request.
|
||||
//-------------------------------------------------------------------
|
||||
private class AjaxResponse_ActivateMember : AjaxResponse_Data
|
||||
{
|
||||
// Construction.
|
||||
public AjaxResponse_ActivateMember(SaxModel_Online model) : base(model) { }
|
||||
// Member details.
|
||||
public MemberItemData Member { get; } = new MemberItemData();
|
||||
}
|
||||
[HttpPost]
|
||||
[Route("Organisation/Ajax/ActivateMember")]
|
||||
public IActionResult Ajax_ActivateMember(Model_Organisation_Members model)
|
||||
{
|
||||
String fn = GetType().Name + ".Ajax_ActivateMember";
|
||||
String messageTitle = Localiser["label.member"];
|
||||
AjaxResponse_ActivateMember responseData = new AjaxResponse_ActivateMember(model);
|
||||
|
||||
// Validate session and referrer.
|
||||
if (!ValidReferer) return Forbid();
|
||||
if (!ValidUserSession) return GetAjaxResult_InvalidSession(responseData);
|
||||
RefreshModel(model);
|
||||
|
||||
// Record disposable items as they are created so all can be disposed when needed.
|
||||
using (DisposableCollection<IDisposable> disposableItems = new DisposableCollection<IDisposable>())
|
||||
{
|
||||
|
||||
// Retrieve User Organisation [MemberId).
|
||||
SysId userOrganisationId = model.ExtractSysId(model.MemberId);
|
||||
SaxUserOrganisation userOrganisation = AccountMgr.GetUserOrganisationById(userOrganisationId);
|
||||
disposableItems.Add(userOrganisation);
|
||||
if (userOrganisation == null || !userOrganisation.IsStatusActive)
|
||||
{
|
||||
SaLogger.Warn(fn + " User Organisation not found or not active. Id: " + SysId.ToString(userOrganisationId));
|
||||
return Json(responseData.SetGoHome(messageTitle, Localiser["msg.error.system"]));
|
||||
}
|
||||
|
||||
// Retrieve the Organisation.
|
||||
SaxOrganisation organisation = AccountMgr.GetOrganisationById(userOrganisation.OrganisationId);
|
||||
disposableItems.Add(organisation);
|
||||
if (organisation == null || !organisation.IsStatusActive)
|
||||
{
|
||||
SaLogger.Warn(fn + " Organisation not found or not active. Id: " + SysId.ToString(userOrganisation.OrganisationId));
|
||||
return Json(responseData.SetPopupMessage(messageTitle, Localiser["msg.error.system"]));
|
||||
}
|
||||
|
||||
// Ensure that the user has the correct role to update Members for this organisation.
|
||||
bool userCanManageMembers = AccountMgr.UserHasAnyOrganisationRole(SessionUserAccountId, organisation.Id, new List<Sax.OrganisationRole> { Sax.OrganisationRole.Admin, Sax.OrganisationRole.MemberAdmin });
|
||||
if (!userCanManageMembers)
|
||||
{
|
||||
SaLogger.Warn(fn + " User doesn't have 'Member Admin' role for Organisation Id: " + organisation.Id);
|
||||
return Json(responseData.SetGoHome(messageTitle, Localiser["msg.error.system"]));
|
||||
}
|
||||
|
||||
// Retrieve User Account.
|
||||
SaxUserAccount userAccount = null;
|
||||
userAccount = AccountMgr.GetUserAccountById(userOrganisation.UserAccountId);
|
||||
disposableItems.Add(userAccount);
|
||||
if (userAccount == null)
|
||||
{
|
||||
SaLogger.Warn(fn + " Failed to retrieve User Account. Id: " + userOrganisation.UserAccountId);
|
||||
return Json(responseData.SetPopupMessage(messageTitle, Localiser["msg.error.system"]));
|
||||
}
|
||||
if (!userAccount.IsStatusAwaiting)
|
||||
{
|
||||
SaLogger.Warn(fn + " User Account is not awaiting. Id: " + userOrganisation.UserAccountId + ". Status: " + userAccount.StatusDesc);
|
||||
return Json(responseData.SetPopupMessage(messageTitle, Localiser["msg.error.system"]));
|
||||
}
|
||||
|
||||
// Update user's status.
|
||||
userAccount.Status = SaStatus.Active;
|
||||
if (AccountMgr.UpdateUserAccount(userAccount, DbUpdateInfo))
|
||||
{
|
||||
// Send activation email.
|
||||
SaEmailData emailData = new SaEmailData();
|
||||
emailData.Config = EmailConfig;
|
||||
emailData.AddressesTo.Add(userAccount.EmailAddress);
|
||||
emailData.Subject = Localiser["account.activate.email.subject"];
|
||||
PopulateAccountActivatedEmailBody(emailData, userAccount);
|
||||
if (EmailConsole.SendEmail(emailData))
|
||||
SaLogger.Info(fn + " User Activation email sent to " + userAccount.EmailAddress, true);
|
||||
else SaLogger.Warn(fn + " Failed to send User Activation email to " + userAccount.EmailAddress);
|
||||
// Treat the activation as successful regardless of whether the email was sent.
|
||||
responseData.SetNotifyMessage(messageTitle, Localiser["account.activate.notify"]);
|
||||
}
|
||||
else
|
||||
{
|
||||
SaLogger.Warn(fn + " Failed to insert User Account: " + AccountMgr.ErrorStateMessage);
|
||||
return Json(responseData.SetPopupMessage(messageTitle, Localiser["msg.error.item.update.failed"]));
|
||||
}
|
||||
|
||||
// Construct response.
|
||||
PopulateMemberResponseItemData(model, userOrganisation, userAccount, organisation, responseData.Member);
|
||||
}
|
||||
|
||||
// Complete response.
|
||||
responseData.Success = true;
|
||||
return Json(responseData);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
private void PopulateAccountActivatedEmailBody(SaEmailData emailData, SaxUserAccount userAccount)
|
||||
{
|
||||
// Will need to handle culture (language/country) as and when introduced.
|
||||
emailData.MessageBody = SaxResourceHelper.GetResourceText(SaxResourceHelper.TextResource.Email_Security_AccountActivated_Html);
|
||||
emailData.HtmlBody = true;
|
||||
|
||||
// Replace dynamic tags.
|
||||
EmailConsole.ReplaceDynamicEmailBodyTags(emailData, null, userAccount);
|
||||
|
||||
// Replace dynamic tag for link back to change password page.
|
||||
SaEmailConsole.ReplaceDynamicEmailTag(emailData, "[#Link.RequestPassword]", SecurityController.GenerateRequestPasswordLink(this, userAccount.Id, userAccount.EmailAddress, ""));
|
||||
SaEmailConsole.ReplaceDynamicEmailTag(emailData, "[#Link.SignIn]", GetRedirectLocation(RedirectLocation.WebAppBase) + "Security/SignIn");
|
||||
SaEmailConsole.ReplaceDynamicEmailTag(emailData, "[#Link.ExpiresMinutes]", SecurityController.GetRequestPasswordEmailLinkExpiresMinutes(this).ToString());
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Remove Member ajax request.
|
||||
//-------------------------------------------------------------------
|
||||
private class AjaxResponse_RemoveMember : AjaxResponse_Data
|
||||
{
|
||||
// Construction.
|
||||
public AjaxResponse_RemoveMember(SaxModel_Online model) : base(model) { }
|
||||
// Member details.
|
||||
public MemberItemData Member { get; } = new MemberItemData();
|
||||
}
|
||||
[HttpPost]
|
||||
[Route("Organisation/Ajax/RemoveMember")]
|
||||
public IActionResult Ajax_RemoveMember(Model_Organisation_Members model)
|
||||
{
|
||||
String fn = GetType().Name + ".Ajax_RemoveMember";
|
||||
String messageTitle = Localiser["label.member"];
|
||||
AjaxResponse_RemoveMember responseData = new AjaxResponse_RemoveMember(model);
|
||||
|
||||
// Validate session and referrer.
|
||||
if (!ValidReferer) return Forbid();
|
||||
if (!ValidUserSession) return GetAjaxResult_InvalidSession(responseData);
|
||||
RefreshModel(model);
|
||||
|
||||
// Record disposable items as they are created so all can be disposed when needed.
|
||||
using (DisposableCollection<IDisposable> disposableItems = new DisposableCollection<IDisposable>())
|
||||
{
|
||||
|
||||
// Retrieve User Organisation [MemberId).
|
||||
SysId userOrganisationId = model.ExtractSysId(model.MemberId);
|
||||
SaxUserOrganisation userOrganisation = AccountMgr.GetUserOrganisationById(userOrganisationId);
|
||||
disposableItems.Add(userOrganisation);
|
||||
if (userOrganisation == null || !userOrganisation.IsStatusActive)
|
||||
{
|
||||
SaLogger.Warn(fn + " User Organisation not found or not active. Id: " + SysId.ToString(userOrganisationId));
|
||||
return Json(responseData.SetGoHome(messageTitle, Localiser["msg.error.system"]));
|
||||
}
|
||||
|
||||
// Retrieve the Organisation.
|
||||
SaxOrganisation organisation = AccountMgr.GetOrganisationById(userOrganisation.OrganisationId);
|
||||
disposableItems.Add(organisation);
|
||||
if (organisation == null || !organisation.IsStatusActive)
|
||||
{
|
||||
SaLogger.Warn(fn + " Organisation not found or not active. Id: " + SysId.ToString(userOrganisation.OrganisationId));
|
||||
return Json(responseData.SetPopupMessage(messageTitle, Localiser["msg.error.system"]));
|
||||
}
|
||||
|
||||
// Ensure that the user has the correct role to update Members for this organisation.
|
||||
bool userCanManageMembers = AccountMgr.UserHasAnyOrganisationRole(SessionUserAccountId, organisation.Id, new List<Sax.OrganisationRole> { Sax.OrganisationRole.Admin, Sax.OrganisationRole.MemberAdmin });
|
||||
if (!userCanManageMembers)
|
||||
{
|
||||
SaLogger.Warn(fn + " User doesn't have 'Member Admin' role for Organisation Id: " + organisation.Id);
|
||||
return Json(responseData.SetGoHome(messageTitle, Localiser["msg.error.system"]));
|
||||
}
|
||||
|
||||
// Retrieve User Account.
|
||||
SaxUserAccount userAccount = null;
|
||||
userAccount = AccountMgr.GetUserAccountById(userOrganisation.UserAccountId);
|
||||
disposableItems.Add(userAccount);
|
||||
if (userAccount == null)
|
||||
{
|
||||
SaLogger.Warn(fn + " Failed to retrieve User Account. Id: " + userOrganisation.UserAccountId);
|
||||
return Json(responseData.SetPopupMessage(messageTitle, Localiser["msg.error.system"]));
|
||||
}
|
||||
if (!userAccount.IsStatusAwaiting && !userAccount.IsStatusActive)
|
||||
{
|
||||
SaLogger.Warn(fn + " User Account is not awaiting or active. Id: " + userOrganisation.UserAccountId);
|
||||
return Json(responseData.SetPopupMessage(messageTitle, Localiser["msg.error.system"]));
|
||||
}
|
||||
|
||||
// Remove User Organisation roles.
|
||||
userOrganisation.ClearOrganisationRoles();
|
||||
if (AccountMgr.UpdateUserOrganisation(userOrganisation, DbUpdateInfo))
|
||||
{
|
||||
responseData.SetNotifyMessage(messageTitle, Localiser["msg.item.removed"]);
|
||||
}
|
||||
else
|
||||
{
|
||||
SaLogger.Warn(fn + " Failed to update User Organisation: " + AccountMgr.ErrorStateMessage);
|
||||
return Json(responseData.SetPopupMessage(messageTitle, Localiser["msg.error.item.update.failed"]));
|
||||
}
|
||||
|
||||
// Construct response.
|
||||
PopulateMemberResponseItemData(model, userOrganisation, userAccount, organisation, responseData.Member);
|
||||
}
|
||||
|
||||
// Complete response.
|
||||
responseData.Success = true;
|
||||
return Json(responseData);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
}
|
||||
//=======================================================================
|
||||
}
|
||||
+423
@@ -0,0 +1,423 @@
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Sarand.Net.Standard.Base.App;
|
||||
using Sarand.Net.Standard.Base.Bus;
|
||||
using Sarand.Net.Standard.Base.Core;
|
||||
using Sarand.Net.Standard.Base.Dbas;
|
||||
using Sarand.Net.Standard.Base.Utils;
|
||||
using Saxonite.Net.Core.Web.Online.Models;
|
||||
using Saxonite.Net.Standard.Base.App;
|
||||
using Saxonite.Net.Standard.Base.Bus;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Saxonite.Net.Core.Web.Online.Controllers
|
||||
{
|
||||
//=======================================================================
|
||||
// Online Organisation Controller - Opportunities - Ajax actions.
|
||||
//=======================================================================
|
||||
partial class OrganisationController
|
||||
{
|
||||
//-------------------------------------------------------------------
|
||||
// Organisation Opportunity data.
|
||||
private class OpportunityListData : AjaxResponse_Data.ItemData_Base
|
||||
{
|
||||
public String TypeCode { get; set; }
|
||||
public String TypeDesc { get; set; }
|
||||
public String Position { get; set; }
|
||||
public String Outline { get; set; }
|
||||
public String RegionCaption { get; set; }
|
||||
public String SportCaption { get; set; }
|
||||
public String PublishedOnFmt { get; set; }
|
||||
public String ExpiresOnFmt { get; set; }
|
||||
}
|
||||
private class OpportunityItemData : OpportunityListData
|
||||
{
|
||||
public String RegionIdPrimary { get; set; }
|
||||
public String SportIdPrimary { get; set; }
|
||||
public String PublishedOn_YYYYMMDD { get; set; }
|
||||
public String ExpiresOn_YYYYMMDD { get; set; }
|
||||
}
|
||||
private void PopulateOpportunityResponseListData(Model_Organisation_Opportunities model, SaxOrganisationOpportunity opportunity, OpportunityListData data)
|
||||
{
|
||||
data.Id = model.EncryptId(opportunity.Id);
|
||||
data.TypeCode = OpportunityTypeCodes.GetCodeForType(opportunity.OpportunityType);
|
||||
data.TypeDesc = Localiser.GetOpportunityTypeCaption(opportunity.OpportunityType);
|
||||
data.Position = opportunity.Position;
|
||||
data.Outline = opportunity.Outline;
|
||||
data.RegionCaption = model.GetRegionCaption(opportunity.RegionIdPrimary);
|
||||
data.SportCaption = model.GetSportCaption(opportunity.SportIdPrimary);
|
||||
data.CreatedOnFmt = Localiser.FormatDate(opportunity.CreateStamp.On);
|
||||
data.PublishedOnFmt = Localiser.FormatDate(opportunity.PublishedAt);
|
||||
data.ExpiresOnFmt = Localiser.FormatDate(opportunity.ExpiresAt);
|
||||
data.StatusCode = opportunity.StatusCode;
|
||||
data.StatusDesc = opportunity.StatusDesc;
|
||||
}
|
||||
private void PopulateOpportunityResponseItemData(Model_Organisation_Opportunities model, SaxOrganisationOpportunity opportunity, OpportunityItemData data)
|
||||
{
|
||||
PopulateOpportunityResponseListData(model, opportunity, data as OpportunityListData);
|
||||
data.RegionIdPrimary = model.GetEncryptedRegionId(opportunity.RegionIdPrimary);
|
||||
data.SportIdPrimary = model.GetEncryptedSportId(opportunity.SportIdPrimary);
|
||||
data.PublishedOn_YYYYMMDD = DateUtil.Format(opportunity.PublishedAt, "yyyyMMdd");
|
||||
data.ExpiresOn_YYYYMMDD = DateUtil.Format(opportunity.ExpiresAt, "yyyyMMdd");
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Get Opportunity List ajax request.
|
||||
//-------------------------------------------------------------------
|
||||
private class AjaxResponse_OpportunityList : AjaxResponse_Data
|
||||
{
|
||||
// Construction.
|
||||
public AjaxResponse_OpportunityList(SaxModel_Online model) : base(model) { }
|
||||
// Opportunity list.
|
||||
public List<OpportunityListData> Opportunities { get; } = new List<OpportunityListData>();
|
||||
// User profile.
|
||||
public class UserData
|
||||
{
|
||||
public bool CanManage { get; set; }
|
||||
}
|
||||
public UserData User { get; } = new UserData();
|
||||
// Organisation.
|
||||
public class OrganisationData
|
||||
{
|
||||
public String Id { get; set; }
|
||||
public String Name { get; set; }
|
||||
public String SportId { get; set; }
|
||||
public String SportName { get; set; }
|
||||
public String RegionId { get; set; }
|
||||
public String RegionName { get; set; }
|
||||
}
|
||||
public OrganisationData Organisation { get; } = new OrganisationData();
|
||||
// Reference data.
|
||||
public List<CodeDesc> OpportunityTypes { get; } = new List<CodeDesc>();
|
||||
}
|
||||
//-------------------------------------------------------------------
|
||||
[HttpPost]
|
||||
[Route("Organisation/Ajax/GetOpportunityList")]
|
||||
[Route("Organisation/Ajax/GetOpportunities")]
|
||||
public IActionResult Ajax_GetOpportunityList(Model_Organisation_Opportunities model)
|
||||
{
|
||||
String fn = GetType().Name + ".Ajax_GetOpportunityList";
|
||||
String messageTitle = Localiser["organisation.caption.opportunities"];
|
||||
AjaxResponse_OpportunityList responseData = new AjaxResponse_OpportunityList(model);
|
||||
|
||||
// Validate session and referrer.
|
||||
if (!ValidReferer) return Forbid();
|
||||
if (!ValidUserSession) return GetAjaxResult_InvalidSession(responseData);
|
||||
RefreshModel(model);
|
||||
SysId userAccountId = SessionUserAccountId;
|
||||
|
||||
// Record disposable items as they are created so all can be disposed when needed.
|
||||
using (DisposableCollection<IDisposable> disposableItems = new DisposableCollection<IDisposable>())
|
||||
{
|
||||
|
||||
// Organisation.
|
||||
SysId organisationId = model.ExtractSysId(model.Filter.OrganisationId);
|
||||
SaxOrganisation organisation = AccountMgr.GetOrganisationById(organisationId);
|
||||
disposableItems.Add(organisation);
|
||||
if (organisation == null || !organisation.IsStatusActive)
|
||||
{
|
||||
SaLogger.Warn(fn + " " + (organisation == null ? "Invalid" : "Inactive") + " organisation for Opportunity list. OrganisationId: '" + model.Filter.OrganisationId + "'");
|
||||
return Json(responseData.SetPopupMessage(messageTitle, Localiser["msg.error.system"]));
|
||||
}
|
||||
|
||||
if (organisation != null)
|
||||
{
|
||||
// Store filter data.
|
||||
SessionData_Online.Filter.SetMemberOrganisation(organisation);
|
||||
|
||||
// Reference data - opportunity types.
|
||||
foreach (TypeCodeDesc opportunityType in OpportunityTypeCodes)
|
||||
responseData.OpportunityTypes.Add(opportunityType.Code, Localiser.GetOpportunityTypeCaption((Sax.OpportunityType)opportunityType.Type));
|
||||
|
||||
// User organisation.
|
||||
SaxUserOrganisation.Params prmUserOrganisation = new SaxUserOrganisation.Params();
|
||||
prmUserOrganisation.UserAccountIdsIncluded.Add(userAccountId);
|
||||
prmUserOrganisation.OrganisationIdsIncluded.Add(organisationId);
|
||||
prmUserOrganisation.UserAccountStatusCat = SaxUserAccount.StatusCat.ActiveOnly;
|
||||
prmUserOrganisation.StatusCat = SaxUserOrganisation.StatusCat.ActiveOnly;
|
||||
SaxUserOrganisation userOrganisation = AccountMgr.GetUserOrganisation(prmUserOrganisation);
|
||||
disposableItems.Add(userOrganisation);
|
||||
if (userOrganisation == null)
|
||||
{
|
||||
SaLogger.Warn(fn + " Invalid/inactive user organisation for Opportunity list. UserAccountId: " + SysId.ToString(userAccountId) + ". OrganisationId: " + model.Filter.OrganisationId + ".");
|
||||
return Json(responseData.SetPopupMessage(messageTitle, Localiser["msg.error.system"]));
|
||||
}
|
||||
|
||||
// Organisation.
|
||||
responseData.Organisation.Id = SysId.ToString(organisation.Id);
|
||||
responseData.Organisation.Name = organisation.Name;
|
||||
responseData.Organisation.SportId = model.GetEncryptedSportId(organisation.SportIdPrimary);
|
||||
responseData.Organisation.SportName = model.GetSportCaption(organisation.SportIdPrimary);
|
||||
responseData.Organisation.RegionId = model.GetEncryptedRegionId(organisation.RegionIdPrimary);
|
||||
responseData.Organisation.RegionName = model.GetRegionCaption(organisation.RegionIdPrimary);
|
||||
|
||||
// User details.
|
||||
responseData.User.CanManage = userOrganisation.CanManageOpportunities;
|
||||
|
||||
// Item filter.
|
||||
SaxOrganisationOpportunity.Params prmOpportunity = new SaxOrganisationOpportunity.Params();
|
||||
prmOpportunity.UserAccountIdsIncluded.Add(userAccountId);
|
||||
prmOpportunity.OrganisationIdsIncluded.Add(organisationId);
|
||||
prmOpportunity.OpportunityFilter = model.Filter.Opportunity;
|
||||
prmOpportunity.StatusCat = SaxOrganisationOpportunity.StatusCat.NotDeleted;
|
||||
model.Paging.ItemTotal = (ulong)ActivityMgr.GetOrganisationOpportunityCount(prmOpportunity);
|
||||
model.PopulatePagingTo(prmOpportunity.ResultsPaging);
|
||||
|
||||
// Item columns.
|
||||
ColumnDfn colId = ActivityMgr.GetOrganisationOpportunityColumnDfn(SaxOrganisationOpportunity.Column.Id);
|
||||
ColumnDfn colOpportunityTypeCode = ActivityMgr.GetOrganisationOpportunityColumnDfn(SaxOrganisationOpportunity.Column.OpportunityTypeCode);
|
||||
ColumnDfn colPosition = ActivityMgr.GetOrganisationOpportunityColumnDfn(SaxOrganisationOpportunity.Column.Position);
|
||||
ColumnDfn colOutline = ActivityMgr.GetOrganisationOpportunityColumnDfn(SaxOrganisationOpportunity.Column.Outline);
|
||||
ColumnDfn colRegionId = ActivityMgr.GetOrganisationOpportunityColumnDfn(SaxOrganisationOpportunity.Column.RegionIdPrimary);
|
||||
ColumnDfn colRegionName = ActivityMgr.GetOrganisationOpportunityColumnDfn(SaxOrganisationOpportunity.Column.Region_Name);
|
||||
ColumnDfn colSportId = ActivityMgr.GetOrganisationOpportunityColumnDfn(SaxOrganisationOpportunity.Column.SportIdPrimary);
|
||||
ColumnDfn colSportName = ActivityMgr.GetOrganisationOpportunityColumnDfn(SaxOrganisationOpportunity.Column.Sport_Name);
|
||||
ColumnDfn colPublishedOn = ActivityMgr.GetOrganisationOpportunityColumnDfn(SaxOrganisationOpportunity.Column.PublishedAt_Date);
|
||||
ColumnDfn colExpiresOn = ActivityMgr.GetOrganisationOpportunityColumnDfn(SaxOrganisationOpportunity.Column.ExpiresAt_Date);
|
||||
ColumnDfn colStatus = ActivityMgr.GetOrganisationOpportunityColumnDfn(SaxOrganisationOpportunity.Column.Status);
|
||||
ColumnDfn colCreatedOn = ActivityMgr.GetOrganisationOpportunityColumnDfn(SaxOrganisationOpportunity.Column.CreateOn_Date);
|
||||
List<ColumnDfn> columns = new List<ColumnDfn>()
|
||||
{
|
||||
colId, colOpportunityTypeCode, colPosition, colOutline,
|
||||
colRegionId, colRegionName, colSportId, colSportName,
|
||||
colPublishedOn, colExpiresOn,
|
||||
colStatus, colCreatedOn
|
||||
};
|
||||
|
||||
// Sort columns.
|
||||
colCreatedOn.SortAscending = false;
|
||||
prmOpportunity.SortColumns.Add(colCreatedOn);
|
||||
|
||||
// Query items.
|
||||
using (DbResultSet resultSet = ActivityMgr.ExecuteOrganisationOpportunityQuery(columns, prmOpportunity))
|
||||
{
|
||||
while (resultSet != null && resultSet.HasRows && resultSet.NextRecord())
|
||||
{
|
||||
NamedValue.Map values = resultSet.GetRecordValues();
|
||||
OpportunityListData opportunityData = new OpportunityListData()
|
||||
{
|
||||
Id = model.EncryptId(new SysId(values.GetLong(colId.DataName))),
|
||||
TypeCode = values.GetString(colOpportunityTypeCode.DataName),
|
||||
TypeDesc = Localiser.GetOpportunityTypeCaption((Sax.OpportunityType)OpportunityTypeCodes.GetTypeForCode(values.GetString(colOpportunityTypeCode.DataName))),
|
||||
Position = values.GetString(colPosition.DataName),
|
||||
Outline = values.GetString(colOutline.DataName),
|
||||
RegionCaption = model.GetRegionCaption(SysId.ToSysId(values.GetString(colRegionId.DataName))),
|
||||
SportCaption = model.GetSportCaption(SysId.ToSysId(values.GetString(colSportId.DataName))),
|
||||
CreatedOnFmt = Localiser.FormatDate(values.GetDateTime(colCreatedOn.DataName)),
|
||||
PublishedOnFmt = Localiser.FormatDate(values.GetDateTime(colPublishedOn.DataName)),
|
||||
ExpiresOnFmt = Localiser.FormatDate(values.GetDateTime(colExpiresOn.DataName)),
|
||||
StatusCode = values.GetString(colStatus.DataName),
|
||||
StatusDesc = SacsSystem.GetStatusDescForCode(values.GetString(colStatus.DataName))
|
||||
};
|
||||
responseData.Opportunities.Add(opportunityData);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (model.Paging.IsPaged)
|
||||
model.Paging.ItemCount = (ushort)responseData.Opportunities.Count;
|
||||
|
||||
// Complete response.
|
||||
responseData.SetPaging(model);
|
||||
responseData.Success = true;
|
||||
return Json(responseData);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Get Opportunity ajax request.
|
||||
//-------------------------------------------------------------------
|
||||
private class AjaxResponse_Opportunity : AjaxResponse_Data
|
||||
{
|
||||
// Construction.
|
||||
public AjaxResponse_Opportunity(SaxModel_Online model) : base(model) { }
|
||||
// Opportunity details.
|
||||
public OpportunityItemData Opportunity { get; } = new OpportunityItemData();
|
||||
}
|
||||
//-------------------------------------------------------------------
|
||||
[HttpPost]
|
||||
[Route("Organisation/Ajax/GetOpportunity")]
|
||||
public IActionResult Ajax_GetOpportunity(Model_Organisation_Opportunities model)
|
||||
{
|
||||
String fn = GetType().Name + ".Ajax_GetOpportunity";
|
||||
String messageTitle = Localiser["organisation.caption.opportunity"];
|
||||
AjaxResponse_Opportunity responseData = new AjaxResponse_Opportunity(model);
|
||||
|
||||
// Validate session and referrer.
|
||||
if (!ValidReferer) return Forbid();
|
||||
if (!ValidUserSession) return GetAjaxResult_InvalidSession(responseData);
|
||||
RefreshModel(model);
|
||||
|
||||
// Record disposable items as they are created so all can be disposed when needed.
|
||||
using (DisposableCollection<IDisposable> disposableItems = new DisposableCollection<IDisposable>())
|
||||
{
|
||||
|
||||
// Identify item.
|
||||
SysId opportunityId = model.ExtractSysId(model.OpportunityId);
|
||||
if (!SysId.IsValid(opportunityId))
|
||||
return Json(responseData.SetPopupMessage(messageTitle, Localiser["msg.error.item.id.not.specified"]));
|
||||
|
||||
// Retrieve item.
|
||||
SaxOrganisationOpportunity opportunity = ActivityMgr.GetOrganisationOpportunityById(opportunityId);
|
||||
disposableItems.Add(opportunity);
|
||||
if (opportunity == null)
|
||||
{
|
||||
SaLogger.Warn(fn + " Failed to retrieve Organisation Opportunity for Id: '" + model.OpportunityId + "'");
|
||||
return Json(responseData.SetPopupMessage(messageTitle, Localiser["msg.error.item.id.not.found"]));
|
||||
}
|
||||
|
||||
// Validate organisation.
|
||||
SaxOrganisation organisation = AccountMgr.GetOrganisationById(opportunity.OrganisationId);
|
||||
disposableItems.Add(organisation);
|
||||
if (organisation == null || !organisation.IsStatusActive)
|
||||
{
|
||||
SaLogger.Warn(fn + " " + (organisation == null ? "Invalid" : "Inactive") + " organisation for Opportunity. OrganisationId: '" + opportunity.OrganisationId + "'");
|
||||
return Json(responseData.SetPopupMessage(messageTitle, Localiser["msg.error.system"]));
|
||||
}
|
||||
|
||||
// Make a note of the selected Organisation.
|
||||
SessionData_Online.Filter.SetMemberOrganisation(organisation);
|
||||
|
||||
// Construct response.
|
||||
PopulateOpportunityResponseItemData(model, opportunity, responseData.Opportunity);
|
||||
}
|
||||
|
||||
// Complete response.
|
||||
responseData.Success = true;
|
||||
return Json(responseData);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Store Opportunity ajax request.
|
||||
//-------------------------------------------------------------------
|
||||
[HttpPost]
|
||||
[Route("Organisation/Ajax/StoreOpportunity")]
|
||||
public IActionResult Ajax_StoreOpportunity(Model_Organisation_Opportunities model)
|
||||
{
|
||||
String fn = GetType().Name + ".Ajax_StoreOpportunity";
|
||||
String messageTitle = Localiser["organisation.caption.opportunity"];
|
||||
AjaxResponse_Opportunity responseData = new AjaxResponse_Opportunity(model);
|
||||
|
||||
// Validate session and referrer.
|
||||
if (!ValidReferer) return Forbid();
|
||||
if (!ValidUserSession) return GetAjaxResult_InvalidSession(responseData);
|
||||
RefreshModel(model);
|
||||
|
||||
// Record disposable items as they are created so all can be disposed when needed.
|
||||
using (DisposableCollection<IDisposable> disposableItems = new DisposableCollection<IDisposable>())
|
||||
{
|
||||
|
||||
// Validate item properties.
|
||||
model.ValidateOpportunityData(responseData);
|
||||
if (responseData.HasControlErrors())
|
||||
return Json(responseData);
|
||||
|
||||
// Validate Opportunity against Id against 'Exists' flag.
|
||||
SysId opportunityId = model.ExtractSysId(model.OpportunityId);
|
||||
bool opportunityExists = StringUtil.ToBool(model.OpportunityExists);
|
||||
if (opportunityExists && !SysId.IsValid(opportunityId))
|
||||
{
|
||||
SaLogger.Warn(fn + " Id not specified for existing Opportunity.");
|
||||
return Json(responseData.SetGoHome(messageTitle, Localiser["msg.error.system"]));
|
||||
}
|
||||
if (!opportunityExists && SysId.IsValid(opportunityId))
|
||||
{
|
||||
SaLogger.Warn(fn + " Id specified for new Opportunity: '" + model.OpportunityId + "'");
|
||||
return Json(responseData.SetGoHome(messageTitle, Localiser["msg.error.system"]));
|
||||
}
|
||||
|
||||
// Retrieve existing item.
|
||||
SaxOrganisationOpportunity opportunity = ActivityMgr.GetOrganisationOpportunityById(opportunityId);
|
||||
disposableItems.Add(opportunity);
|
||||
if (opportunity == null && SysId.IsValid(opportunityId))
|
||||
{
|
||||
SaLogger.Warn(fn + " Failed to retrieve opportunity for Id: '" + model.OpportunityId + "'");
|
||||
return Json(responseData.SetPopupMessage(messageTitle, Localiser["msg.error.item.id.not.found"]));
|
||||
}
|
||||
|
||||
// Validate the Organisation.
|
||||
SysId organisationId = model.ExtractSysId(model.OpportunityOrganisationId);
|
||||
if (!SysId.IsValid(organisationId))
|
||||
{
|
||||
SaLogger.Warn(fn + " Organisation Id not specified for Opportunity.");
|
||||
return Json(responseData.SetGoHome(messageTitle, Localiser["msg.error.system"]));
|
||||
}
|
||||
SaxOrganisation organisation = AccountMgr.GetOrganisationById(organisationId);
|
||||
disposableItems.Add(organisation);
|
||||
if (organisation == null || !organisation.IsStatusActive)
|
||||
{
|
||||
SaLogger.Warn(fn + " " + (organisation == null ? "Invalid" : "Inactive") + " organisation for Opportunity. OrganisationId: '" + model.OpportunityOrganisationId + "'");
|
||||
return Json(responseData.SetPopupMessage(messageTitle, Localiser["msg.error.system"]));
|
||||
}
|
||||
if (opportunity != null && !opportunity.OrganisationId.Equals(organisationId))
|
||||
{
|
||||
SaLogger.Warn(fn + " Inconsistent Organisation Id specified for Opportunity. Expected: " + opportunity.OrganisationId + ". Found: " + organisationId);
|
||||
return Json(responseData.SetGoHome(messageTitle, Localiser["msg.error.system"]));
|
||||
}
|
||||
|
||||
// Ensure that the user has the correct role to update Opportunities for this organisation.
|
||||
if (!AccountMgr.UserHasAnyOrganisationRole(SessionUserAccountId, organisationId, new[] { Sax.OrganisationRole.Admin, Sax.OrganisationRole.OpportunityAdmin }))
|
||||
{
|
||||
SaLogger.Warn(fn + " User doesn't have 'Opportunity Admin' role for Organisation Id: " + organisationId);
|
||||
return Json(responseData.SetGoHome(messageTitle, Localiser["msg.error.system"]));
|
||||
}
|
||||
|
||||
// Create new item if required.
|
||||
if (opportunity == null)
|
||||
{
|
||||
opportunity = ActivityMgr.CreateOrganisationOpportunity(organisationId);
|
||||
disposableItems.Add(opportunity);
|
||||
}
|
||||
|
||||
// Populate item properties.
|
||||
if (model.OpportunityRegionId != null)
|
||||
opportunity.RegionIdPrimary = model.ExtractSysId(model.OpportunityRegionId);
|
||||
if (model.OpportunitySportId != null)
|
||||
opportunity.SportIdPrimary = model.ExtractSysId(model.OpportunitySportId);
|
||||
if (model.OpportunityTypeCode != null)
|
||||
opportunity.OpportunityType = (Sax.OpportunityType)OpportunityTypeCodes.GetTypeForCode(model.OpportunityTypeCode);
|
||||
if (model.OpportunityPosition != null)
|
||||
opportunity.Position = model.OpportunityPosition;
|
||||
if (model.OpportunityOutline != null)
|
||||
opportunity.Outline = model.OpportunityOutline;
|
||||
if (model.OpportunityStatusCode != null)
|
||||
opportunity.Status = model.OpportunityStatus;
|
||||
|
||||
// Store item.
|
||||
bool opportunityCreated = false;
|
||||
if (!SysId.IsValid(opportunity.Id))
|
||||
{
|
||||
if (!ActivityMgr.InsertOrganisationOpportunity(opportunity, DbUpdateInfo))
|
||||
{
|
||||
SaLogger.Warn(fn + " Failed to insert opportunity: " + ActivityMgr.ErrorStateMessage);
|
||||
return Json(responseData.SetPopupMessage(messageTitle, Localiser["msg.error.item.insert.failed"]));
|
||||
}
|
||||
opportunityCreated = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!ActivityMgr.UpdateOrganisationOpportunity(opportunity, DbUpdateInfo))
|
||||
{
|
||||
SaLogger.Warn(fn + " Failed to update opportunity [Id:" + SysId.ToString(opportunity.Id) + "]: " + ActivityMgr.ErrorStateMessage);
|
||||
return Json(responseData.SetPopupMessage(messageTitle, Localiser["msg.error.item.update.failed"]));
|
||||
}
|
||||
}
|
||||
SaLogger.Info(fn + " Opportunity " + (opportunityCreated ? "created" : "updated") + ". Id: " + opportunity.Id.ToString() + ". User: " + SessionData.User.EmailAddress + ". Organisation: " + organisation.Name, true);
|
||||
|
||||
// Store Opportunity Activity Index data.
|
||||
ActivityConsole.StoreActivityIndex(opportunity, DbUpdateInfo);
|
||||
|
||||
// Construct response.
|
||||
PopulateOpportunityResponseItemData(model, opportunity, responseData.Opportunity);
|
||||
}
|
||||
|
||||
// Complete response.
|
||||
responseData.Success = true;
|
||||
return Json(responseData);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
}
|
||||
//=======================================================================
|
||||
}
|
||||
+214
@@ -0,0 +1,214 @@
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Sarand.Net.Standard.Base.App;
|
||||
using Sarand.Net.Standard.Base.Bus;
|
||||
using Sarand.Net.Standard.Base.Core;
|
||||
using Sarand.Net.Standard.Base.Utils;
|
||||
using Saxonite.Net.Core.Web.Online.App;
|
||||
using Saxonite.Net.Core.Web.Online.Models;
|
||||
using Saxonite.Net.Standard.Base.App;
|
||||
using Saxonite.Net.Standard.Base.Bus;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Saxonite.Net.Core.Web.Online.Controllers
|
||||
{
|
||||
//=======================================================================
|
||||
// Online Organisation Controller - Request - Ajax actions.
|
||||
//=======================================================================
|
||||
partial class OrganisationController
|
||||
{
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Request Organisation ajax request.
|
||||
//-------------------------------------------------------------------
|
||||
private class AjaxResponse_RequestOrganisation : AjaxResponse_Data
|
||||
{
|
||||
// Construction.
|
||||
public AjaxResponse_RequestOrganisation(SaxModel_Online model) : base(model) { }
|
||||
// Organisation list.
|
||||
public List<OrganisationListData> Organisations { get; } = new List<OrganisationListData>();
|
||||
}
|
||||
//-------------------------------------------------------------------
|
||||
[HttpPost]
|
||||
[Route("Organisation/Ajax/Request")]
|
||||
[Route("Organisation/Ajax/Register")]
|
||||
public IActionResult Ajax_RequestOrganisation(Model_Organisation model)
|
||||
{
|
||||
String fn = GetType().Name + ".Ajax_RequestOrganisation";
|
||||
String messageTitle = Localiser["organisation.caption.organisation.request"];
|
||||
AjaxResponse_RequestOrganisation responseData = new AjaxResponse_RequestOrganisation(model);
|
||||
|
||||
// Validate session and referrer. User does not need to be logged in.
|
||||
if (!ValidReferer) return Forbid();
|
||||
SaxSessionData_Online sessionData = SessionData_Online;
|
||||
|
||||
// Record disposable items as they are created so all can be disposed when needed.
|
||||
using (DisposableCollection<IDisposable> disposableItems = new DisposableCollection<IDisposable>())
|
||||
{
|
||||
|
||||
if (!model.ValidateOrganisationRequestData(responseData))
|
||||
return Json(responseData);
|
||||
|
||||
// Check Regions.
|
||||
SysId regionIdCountry = model.ExtractSysId(model.Organisation.RegionIdPrimary);
|
||||
SaxRegion.Data regionCountry = Internals.GetRegion(regionIdCountry);
|
||||
if (SysId.IsValid(regionIdCountry) && regionCountry == null)
|
||||
{
|
||||
SaLogger.Warn(fn + " Country region not found. Id: " + model.Organisation.RegionIdPrimary + ". " + GetLogSuffix());
|
||||
return Json(responseData.SetGoHome(messageTitle, Localiser["msg.error.system"]));
|
||||
}
|
||||
SysId regionIdAddressProvince = model.ExtractSysId(model.Organisation.Address.RegionIdProvince);
|
||||
SaxRegion.Data regionProvince = Internals.GetRegion(regionIdAddressProvince);
|
||||
if (SysId.IsValid(regionIdAddressProvince) && regionProvince == null)
|
||||
{
|
||||
SaLogger.Warn(fn + " Province region not found. Id: " + model.Organisation.Address.RegionIdProvince + ". " + GetLogSuffix());
|
||||
return Json(responseData.SetGoHome(messageTitle, Localiser["msg.error.system"]));
|
||||
}
|
||||
|
||||
// User does not need to be logged in, but user details must be supplied if not.
|
||||
SaxUserAccount userAccount = null;
|
||||
if (ValidUserSession)
|
||||
{
|
||||
// Check that an email address hasn't been supplied.
|
||||
// NB Shouldn't happen as contact controls aren't displayed if user is logged in,
|
||||
// hence 'System' error response and nothing more specific.
|
||||
if (!StringUtil.IsEmpty(model.ContactEmailAddress))
|
||||
{
|
||||
SaLogger.Warn(fn + " Contact Email supplied when user logged in. " + GetLogSuffix());
|
||||
return Json(responseData.SetGoHome(messageTitle, Localiser["msg.error.system"]));
|
||||
}
|
||||
// Retrieve user account.
|
||||
userAccount = AccountMgr.GetUserAccountById(sessionData.User.UserAccountId);
|
||||
disposableItems.Add(userAccount);
|
||||
if (userAccount == null)
|
||||
return Json(responseData.SetGoHome(messageTitle, Localiser["msg.error.system"]));
|
||||
}
|
||||
else
|
||||
{
|
||||
// Double check that contact details have been supplied - validated by model above.
|
||||
if (StringUtil.IsEmpty(model.ContactEmailAddress) || StringUtil.IsEmpty(model.ContactFirstName) || StringUtil.IsEmpty(model.ContactLastName))
|
||||
{
|
||||
SaLogger.Warn(fn + " Incomplete contact details supplied.");
|
||||
return Json(responseData.SetGoHome(messageTitle, Localiser["msg.error.system"]));
|
||||
}
|
||||
// Check that the email doesn't exist.
|
||||
// NB This is validated by the model and shouldn't be required here.
|
||||
userAccount = AccountMgr.GetUserAccountByEmailAddress(model.ContactEmailAddress);
|
||||
disposableItems.Add(userAccount);
|
||||
if (userAccount != null)
|
||||
return Json(responseData.SetGoHome(messageTitle, Localiser["msg.error.system"]));
|
||||
userAccount = AccountMgr.CreateUserAccount();
|
||||
userAccount.EmailAddress = model.ContactEmailAddress;
|
||||
userAccount.FirstName = model.ContactFirstName;
|
||||
userAccount.LastName = model.ContactLastName;
|
||||
if (!AccountMgr.InsertUserAccount(userAccount, DbUpdateInfo))
|
||||
{
|
||||
SaLogger.Warn(fn + " Failed to insert user contact - " + AccountMgr.ErrorStateMessage);
|
||||
return Json(responseData.SetGoHome(messageTitle, Localiser["msg.error.system"]));
|
||||
}
|
||||
}
|
||||
|
||||
SysId organisationSportId = model.ExtractSysId(model.Organisation.SportId);
|
||||
if (SysId.IsValid(organisationSportId))
|
||||
{
|
||||
// Add User Sport if not already present.
|
||||
// NB This will also reactivate an inactive or deleted User Sport.
|
||||
SaxUserSport.Params prmUserSport = new SaxUserSport.Params();
|
||||
prmUserSport.UserAccountIdsIncluded.Add(userAccount.Id);
|
||||
prmUserSport.SportIdsIncluded.Add(organisationSportId);
|
||||
prmUserSport.StatusCat = SaxUserSport.StatusCat.Any;
|
||||
SaxUserSport userSport = AccountMgr.GetUserSport(prmUserSport);
|
||||
if (userSport == null)
|
||||
userSport = AccountMgr.CreateUserSport(userAccount.Id, organisationSportId);
|
||||
disposableItems.Add(userSport);
|
||||
userSport.Status = SaxUserSport.DefaultStatus;
|
||||
if (!SysId.IsValid(userSport.Id))
|
||||
{
|
||||
if (!AccountMgr.InsertUserSport(userSport, DbUpdateInfo))
|
||||
{
|
||||
// Logg error but don't abort the request.
|
||||
SaLogger.Warn(fn + " Failed to insert User Sport: " + AccountMgr.ErrorStateMessage);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!AccountMgr.UpdateUserSport(userSport, DbUpdateInfo))
|
||||
{
|
||||
// Logg error but don't abort the request.
|
||||
SaLogger.Warn(fn + " Failed to update User Sport: " + AccountMgr.ErrorStateMessage);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Create Organisation.
|
||||
SaxOrganisation organisation = AccountMgr.CreateOrganisation();
|
||||
disposableItems.Add(organisation);
|
||||
organisation.Name = model.Organisation.Name;
|
||||
organisation.OrganisationType = model.Organisation.GetOrganisationType();
|
||||
organisation.OrganisationCategory = model.Organisation.GetOrganisationCategory();
|
||||
organisation.SportIdPrimary = organisationSportId;
|
||||
organisation.RegionIdPrimary = regionIdCountry;
|
||||
organisation.Status = SaStatus.Awaiting;
|
||||
if (!AccountMgr.InsertOrganisation(organisation, DbUpdateInfo))
|
||||
{
|
||||
SaLogger.Warn(fn + " Failed to insert organisation - " + AccountMgr.ErrorStateMessage);
|
||||
return Json(responseData.SetGoHome(messageTitle, Localiser["msg.error.system"]));
|
||||
}
|
||||
|
||||
// Add user as member of organisation.
|
||||
SaxUserOrganisation userOrganisation = AccountMgr.CreateUserOrganisation(userAccount.Id, organisation.Id);
|
||||
disposableItems.Add(userOrganisation);
|
||||
userOrganisation.OrganisationRoles = new[] { Sax.OrganisationRole.Member, Sax.OrganisationRole.Admin };
|
||||
if (!AccountMgr.InsertUserOrganisation(userOrganisation, DbUpdateInfo))
|
||||
{
|
||||
SaLogger.Warn(fn + " Failed to insert user organisation - " + AccountMgr.ErrorStateMessage);
|
||||
return Json(responseData.SetGoHome(messageTitle, Localiser["msg.error.system"]));
|
||||
}
|
||||
|
||||
// Create Organisation address.
|
||||
SaxItemAddress organisationAddress = ItemDataMgr.CreateItemAddress(organisation.GetItemId(), SaxItemAddress.DefaultOrganisationAddressType);
|
||||
disposableItems.Add(organisationAddress);
|
||||
organisationAddress.Line1 = model.Organisation.Address.Line1;
|
||||
organisationAddress.Line2 = model.Organisation.Address.Line2;
|
||||
organisationAddress.Line3 = model.Organisation.Address.Line3;
|
||||
organisationAddress.Town = model.Organisation.Address.Town;
|
||||
if (regionProvince != null)
|
||||
{
|
||||
organisationAddress.Province = regionProvince.Name;
|
||||
organisationAddress.RegionIdProvince = regionProvince.Id;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (model.Organisation.Address.Province != null)
|
||||
organisationAddress.Province = model.Organisation.Address.Province;
|
||||
}
|
||||
if (regionCountry != null)
|
||||
{
|
||||
organisationAddress.Country = regionCountry.Name;
|
||||
organisationAddress.RegionIdCountry = regionCountry.Id;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (model.Organisation.Address.Country != null)
|
||||
organisationAddress.Country = model.Organisation.Address.Country;
|
||||
}
|
||||
organisationAddress.PostalCode = model.Organisation.Address.PostalCode;
|
||||
if (!ItemDataMgr.InsertItemAddress(organisationAddress, DbUpdateInfo))
|
||||
{
|
||||
SaLogger.Warn(fn + " Failed to insert organisation address - " + ItemDataMgr.ErrorStateMessage);
|
||||
return Json(responseData.SetGoHome(messageTitle, Localiser["msg.error.system"]));
|
||||
}
|
||||
}
|
||||
|
||||
// Complete response.
|
||||
responseData.SetPopupMessage(messageTitle, Localiser["msg.organisation.request.success"].ToString().ReplaceAll("\n", "<br/><br/>"));
|
||||
responseData.Success = true;
|
||||
return Json(responseData);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
}
|
||||
//=======================================================================
|
||||
}
|
||||
@@ -0,0 +1,344 @@
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Sarand.Net.Standard.Base.App;
|
||||
using Sarand.Net.Standard.Base.Bus;
|
||||
using Sarand.Net.Standard.Base.Core;
|
||||
using Sarand.Net.Standard.Base.Dbas;
|
||||
using Sarand.Net.Standard.Base.Utils;
|
||||
using Saxonite.Net.Core.Web.Online.App;
|
||||
using Saxonite.Net.Core.Web.Online.Models;
|
||||
using Saxonite.Net.Standard.Base.App;
|
||||
using Saxonite.Net.Standard.Base.Bus;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Saxonite.Net.Core.Web.Online.Controllers
|
||||
{
|
||||
//=======================================================================
|
||||
// Online Organisation Controller - Ajax actions.
|
||||
//=======================================================================
|
||||
partial class OrganisationController
|
||||
{
|
||||
//-------------------------------------------------------------------
|
||||
// Organisation data.
|
||||
private class OrganisationListData : AjaxResponse_Data.ItemData_Base
|
||||
{
|
||||
public String Name { get; set; }
|
||||
public String RegionId { get; set; }
|
||||
public String RegionName { get; set; }
|
||||
public String SportId { get; set; }
|
||||
public String SportName { get; set; }
|
||||
public String LogoUrl { get; set; }
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Get Organisation List ajax request.
|
||||
//-------------------------------------------------------------------
|
||||
private class AjaxResponse_OrganisationList : AjaxResponse_Data
|
||||
{
|
||||
// Construction.
|
||||
public AjaxResponse_OrganisationList(SaxModel_Online model) : base(model) { }
|
||||
// Organisation list.
|
||||
public List<OrganisationListData> Organisations { get; } = new List<OrganisationListData>();
|
||||
}
|
||||
//-------------------------------------------------------------------
|
||||
[HttpPost]
|
||||
[Route("Organisation/Ajax/GetOrganisationList")]
|
||||
public IActionResult Ajax_GetOrganisationList(Model_Organisation model)
|
||||
{
|
||||
String fn = GetType().Name + ".Ajax_GetOrganisationList";
|
||||
String messageTitle = Localiser["organisation.caption.organisations"];
|
||||
AjaxResponse_OrganisationList responseData = new AjaxResponse_OrganisationList(model);
|
||||
|
||||
// Validate session and referrer.
|
||||
if (!ValidReferer) return Forbid();
|
||||
if (!ValidUserSession) return GetAjaxResult_InvalidSession(responseData);
|
||||
RefreshModel(model);
|
||||
|
||||
// Query columns.
|
||||
ColumnDfn colOrganisationId = AccountMgr.GetOrganisationColumnDfn(SaxOrganisation.Column.Id);
|
||||
ColumnDfn colOrganisationName = AccountMgr.GetOrganisationColumnDfn(SaxOrganisation.Column.Name);
|
||||
ColumnDfn colRegionId = AccountMgr.GetOrganisationColumnDfn(SaxOrganisation.Column.RegionId);
|
||||
ColumnDfn colRegionName = AccountMgr.GetOrganisationColumnDfn(SaxOrganisation.Column.Region_Name);
|
||||
ColumnDfn colSportId = AccountMgr.GetOrganisationColumnDfn(SaxOrganisation.Column.SportId);
|
||||
ColumnDfn colSportName = AccountMgr.GetOrganisationColumnDfn(SaxOrganisation.Column.Sport_Name);
|
||||
ColumnDfn colLogoCount = AccountMgr.GetOrganisationColumnDfn(SaxOrganisation.Column.LogoImage_Count);
|
||||
List<ColumnDfn> columns = new List<ColumnDfn>()
|
||||
{
|
||||
colOrganisationId, colOrganisationName,
|
||||
colRegionId, colRegionName,
|
||||
colSportId, colSportName,
|
||||
colLogoCount
|
||||
};
|
||||
|
||||
// Organisation filter.
|
||||
SaxOrganisation.Params prmOrganisation = new SaxOrganisation.Params();
|
||||
prmOrganisation.OrganisationFilter = model.Filter.Organisation;
|
||||
prmOrganisation.RegionIdsIncluded.AddId(model.ExtractSysId(model.Filter.RegionId));
|
||||
prmOrganisation.SportIdsIncluded.AddId(model.ExtractSysId(model.Filter.SportId));
|
||||
prmOrganisation.StatusCat = SaxOrganisation.StatusCat.ActiveOnly;
|
||||
prmOrganisation.SortColumns.Add(colOrganisationName);
|
||||
model.Paging.ItemTotal = (ulong)AccountMgr.GetOrganisationCount(prmOrganisation);
|
||||
model.PopulatePagingTo(prmOrganisation.ResultsPaging);
|
||||
using (DbResultSet resultSet = AccountMgr.ExecuteOrganisationQuery(columns, prmOrganisation))
|
||||
{
|
||||
while (resultSet != null && resultSet.HasRows && resultSet.NextRecord())
|
||||
{
|
||||
NamedValue.Map values = resultSet.GetRecordValues();
|
||||
SysId organisationId = new SysId(values.GetLong(colOrganisationId.DataName));
|
||||
OrganisationListData organisationData = new OrganisationListData()
|
||||
{
|
||||
Id = model.EncryptId(organisationId),
|
||||
Name = values.GetString(colOrganisationName.DataName),
|
||||
RegionId = model.EncryptId(new SysId(values.GetLong(colRegionId.DataName))),
|
||||
RegionName = values.GetString(colRegionName.DataName),
|
||||
SportId = model.EncryptId(new SysId(values.GetLong(colSportId.DataName))),
|
||||
SportName = values.GetString(colSportName.DataName),
|
||||
};
|
||||
// Logo.
|
||||
if (values.GetLong(colLogoCount.DataName) > 0)
|
||||
organisationData.LogoUrl = GetOrganisationLogoLink(organisationId, false);
|
||||
|
||||
// Add item to the list.
|
||||
responseData.Organisations.Add(organisationData);
|
||||
}
|
||||
}
|
||||
if (model.Paging.IsPaged)
|
||||
model.Paging.ItemCount = (ushort)responseData.Organisations.Count;
|
||||
|
||||
// Complete response.
|
||||
responseData.SetPaging(model);
|
||||
responseData.Success = true;
|
||||
return Json(responseData);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Get Member Admin Organisation List ajax request.
|
||||
//-------------------------------------------------------------------
|
||||
private class AjaxResponse_MemberAdminOrganisationList : AjaxResponse_Data
|
||||
{
|
||||
// Construction.
|
||||
public AjaxResponse_MemberAdminOrganisationList(SaxModel_Online model) : base(model) { }
|
||||
// Organisation list.
|
||||
public List<OrganisationListData> Organisations { get; } = new List<OrganisationListData>();
|
||||
}
|
||||
//-------------------------------------------------------------------
|
||||
[HttpPost]
|
||||
[Route("Organisation/Ajax/GetMemberAdminOrganisationList")]
|
||||
public IActionResult Ajax_GetMemberAdminOrganisationList(Model_Organisation model)
|
||||
{
|
||||
String fn = GetType().Name + ".Ajax_GetMemberAdminOrganisationList";
|
||||
String messageTitle = Localiser["organisation.caption.organisations"];
|
||||
AjaxResponse_MemberAdminOrganisationList responseData = new AjaxResponse_MemberAdminOrganisationList(model);
|
||||
|
||||
// Validate session and referrer.
|
||||
if (!ValidReferer) return Forbid();
|
||||
if (!ValidUserSession) return GetAjaxResult_InvalidSession(responseData);
|
||||
RefreshModel(model);
|
||||
|
||||
// Query columns.
|
||||
ColumnDfn colOrganisationId = AccountMgr.GetUserOrganisationColumnDfn(SaxUserOrganisation.Column.OrganisationId);
|
||||
ColumnDfn colOrganisationName = AccountMgr.GetUserOrganisationColumnDfn(SaxUserOrganisation.Column.Organisation_Name);
|
||||
ColumnDfn colRegionId = AccountMgr.GetUserOrganisationColumnDfn(SaxUserOrganisation.Column.Organisation_RegionId);
|
||||
ColumnDfn colRegionName = AccountMgr.GetUserOrganisationColumnDfn(SaxUserOrganisation.Column.Organisation_Region_Name);
|
||||
ColumnDfn colSportId = AccountMgr.GetUserOrganisationColumnDfn(SaxUserOrganisation.Column.Organisation_SportId);
|
||||
ColumnDfn colSportName = AccountMgr.GetUserOrganisationColumnDfn(SaxUserOrganisation.Column.Organisation_Sport_Name);
|
||||
List<ColumnDfn> columns = new List<ColumnDfn>()
|
||||
{
|
||||
colOrganisationId, colOrganisationName,
|
||||
colRegionId, colRegionName,
|
||||
colSportId, colSportName
|
||||
};
|
||||
|
||||
// Organisation filter
|
||||
SaxUserOrganisation.Params prmUserOrganisation = new SaxUserOrganisation.Params();
|
||||
prmUserOrganisation.UserAccountIdsIncluded.Add(SessionUserAccountId);
|
||||
prmUserOrganisation.OrganisationStatusCat = SaxOrganisation.StatusCat.ActiveOnly;
|
||||
prmUserOrganisation.OrganisationMembersOnly = true;
|
||||
prmUserOrganisation.OrganisationRolesAny.Add(Sax.OrganisationRole.Admin);
|
||||
prmUserOrganisation.OrganisationRolesAny.Add(Sax.OrganisationRole.MemberAdmin);
|
||||
prmUserOrganisation.StatusCat = SaxUserOrganisation.StatusCat.ActiveOnly;
|
||||
prmUserOrganisation.SortColumns.Add(colOrganisationName);
|
||||
model.Paging.ItemTotal = (ulong)AccountMgr.GetUserOrganisationCount(prmUserOrganisation);
|
||||
model.PopulatePagingTo(prmUserOrganisation.ResultsPaging);
|
||||
using (DbResultSet resultSet = AccountMgr.ExecuteUserOrganisationQuery(columns, prmUserOrganisation))
|
||||
{
|
||||
while (resultSet != null && resultSet.HasRows && resultSet.NextRecord())
|
||||
{
|
||||
NamedValue.Map values = resultSet.GetRecordValues();
|
||||
OrganisationListData organisationData = new OrganisationListData()
|
||||
{
|
||||
Id = model.EncryptId(new SysId(values.GetLong(colOrganisationId.DataName))),
|
||||
Name = values.GetString(colOrganisationName.DataName),
|
||||
RegionId = model.EncryptId(new SysId(values.GetLong(colRegionId.DataName))),
|
||||
RegionName = values.GetString(colRegionName.DataName),
|
||||
SportId = model.EncryptId(new SysId(values.GetLong(colSportId.DataName))),
|
||||
SportName = values.GetString(colSportName.DataName),
|
||||
};
|
||||
responseData.Organisations.Add(organisationData);
|
||||
}
|
||||
}
|
||||
if (model.Paging.IsPaged)
|
||||
model.Paging.ItemCount = (ushort)responseData.Organisations.Count;
|
||||
|
||||
// Complete response.
|
||||
responseData.SetPaging(model);
|
||||
responseData.Success = true;
|
||||
return Json(responseData);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Get Event Admin Organisation List ajax request.
|
||||
//-------------------------------------------------------------------
|
||||
private class AjaxResponse_EventAdminOrganisationList : AjaxResponse_Data
|
||||
{
|
||||
// Construction.
|
||||
public AjaxResponse_EventAdminOrganisationList(SaxModel_Online model) : base(model) { }
|
||||
// Organisation list.
|
||||
public List<OrganisationListData> Organisations { get; } = new List<OrganisationListData>();
|
||||
}
|
||||
//-------------------------------------------------------------------
|
||||
[HttpPost]
|
||||
[Route("Organisation/Ajax/GetEventAdminOrganisationList")]
|
||||
public IActionResult Ajax_GetEventAdminOrganisationList(Model_Organisation model)
|
||||
{
|
||||
String fn = GetType().Name + ".Ajax_GetEventAdminOrganisationList";
|
||||
String messageTitle = Localiser["organisation.caption.organisations"];
|
||||
AjaxResponse_EventAdminOrganisationList responseData = new AjaxResponse_EventAdminOrganisationList(model);
|
||||
|
||||
// Validate session and referrer.
|
||||
if (!ValidReferer) return Forbid();
|
||||
if (!ValidUserSession) return GetAjaxResult_InvalidSession(responseData);
|
||||
RefreshModel(model);
|
||||
|
||||
// Query columns.
|
||||
ColumnDfn colOrganisationId = AccountMgr.GetUserOrganisationColumnDfn(SaxUserOrganisation.Column.OrganisationId);
|
||||
ColumnDfn colOrganisationName = AccountMgr.GetUserOrganisationColumnDfn(SaxUserOrganisation.Column.Organisation_Name);
|
||||
ColumnDfn colRegionId = AccountMgr.GetUserOrganisationColumnDfn(SaxUserOrganisation.Column.Organisation_RegionId);
|
||||
ColumnDfn colRegionName = AccountMgr.GetUserOrganisationColumnDfn(SaxUserOrganisation.Column.Organisation_Region_Name);
|
||||
ColumnDfn colSportId = AccountMgr.GetUserOrganisationColumnDfn(SaxUserOrganisation.Column.Organisation_SportId);
|
||||
ColumnDfn colSportName = AccountMgr.GetUserOrganisationColumnDfn(SaxUserOrganisation.Column.Organisation_Sport_Name);
|
||||
List<ColumnDfn> columns = new List<ColumnDfn>()
|
||||
{
|
||||
colOrganisationId, colOrganisationName,
|
||||
colRegionId, colRegionName,
|
||||
colSportId, colSportName
|
||||
};
|
||||
|
||||
// Organisation filter
|
||||
SaxUserOrganisation.Params prmUserOrganisation = new SaxUserOrganisation.Params();
|
||||
prmUserOrganisation.UserAccountIdsIncluded.Add(SessionUserAccountId);
|
||||
prmUserOrganisation.OrganisationStatusCat = SaxOrganisation.StatusCat.ActiveOnly;
|
||||
prmUserOrganisation.OrganisationMembersOnly = true;
|
||||
prmUserOrganisation.OrganisationRolesAny.Add(Sax.OrganisationRole.Admin);
|
||||
prmUserOrganisation.OrganisationRolesAny.Add(Sax.OrganisationRole.ScheduleAdmin);
|
||||
prmUserOrganisation.StatusCat = SaxUserOrganisation.StatusCat.ActiveOnly;
|
||||
prmUserOrganisation.SortColumns.Add(colOrganisationName);
|
||||
model.Paging.ItemTotal = (ulong)AccountMgr.GetUserOrganisationCount(prmUserOrganisation);
|
||||
model.PopulatePagingTo(prmUserOrganisation.ResultsPaging);
|
||||
using (DbResultSet resultSet = AccountMgr.ExecuteUserOrganisationQuery(columns, prmUserOrganisation))
|
||||
{
|
||||
while (resultSet != null && resultSet.HasRows && resultSet.NextRecord())
|
||||
{
|
||||
NamedValue.Map values = resultSet.GetRecordValues();
|
||||
OrganisationListData organisationData = new OrganisationListData()
|
||||
{
|
||||
Id = model.EncryptId(new SysId(values.GetLong(colOrganisationId.DataName))),
|
||||
Name = values.GetString(colOrganisationName.DataName),
|
||||
RegionId = model.EncryptId(new SysId(values.GetLong(colRegionId.DataName))),
|
||||
RegionName = values.GetString(colRegionName.DataName),
|
||||
SportId = model.EncryptId(new SysId(values.GetLong(colSportId.DataName))),
|
||||
SportName = values.GetString(colSportName.DataName),
|
||||
};
|
||||
responseData.Organisations.Add(organisationData);
|
||||
}
|
||||
}
|
||||
if (model.Paging.IsPaged)
|
||||
model.Paging.ItemCount = (ushort)responseData.Organisations.Count;
|
||||
|
||||
// Complete response.
|
||||
responseData.SetPaging(model);
|
||||
responseData.Success = true;
|
||||
return Json(responseData);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Get Opportunity Admin Organisation List ajax request.
|
||||
//-------------------------------------------------------------------
|
||||
private class AjaxResponse_OpportunityAdminOrganisationList : AjaxResponse_Data
|
||||
{
|
||||
// Construction.
|
||||
public AjaxResponse_OpportunityAdminOrganisationList(SaxModel_Online model) : base(model) { }
|
||||
// Organisation list.
|
||||
public List<OrganisationListData> Organisations { get; } = new List<OrganisationListData>();
|
||||
}
|
||||
//-------------------------------------------------------------------
|
||||
[HttpPost]
|
||||
[Route("Organisation/Ajax/GetOpportunityAdminOrganisationList")]
|
||||
public IActionResult Ajax_GetOpportunityAdminOrganisationList(Model_Organisation model)
|
||||
{
|
||||
String fn = GetType().Name + ".Ajax_GetOpportunityAdminOrganisationList";
|
||||
String messageTitle = Localiser["organisation.caption.organisations"];
|
||||
AjaxResponse_OpportunityAdminOrganisationList responseData = new AjaxResponse_OpportunityAdminOrganisationList(model);
|
||||
|
||||
// Validate session and referrer.
|
||||
if (!ValidReferer) return Forbid();
|
||||
if (!ValidUserSession) return GetAjaxResult_InvalidSession(responseData);
|
||||
RefreshModel(model);
|
||||
|
||||
// Query columns.
|
||||
ColumnDfn colOrganisationId = AccountMgr.GetUserOrganisationColumnDfn(SaxUserOrganisation.Column.OrganisationId);
|
||||
ColumnDfn colOrganisationName = AccountMgr.GetUserOrganisationColumnDfn(SaxUserOrganisation.Column.Organisation_Name);
|
||||
ColumnDfn colRegionId = AccountMgr.GetUserOrganisationColumnDfn(SaxUserOrganisation.Column.Organisation_RegionId);
|
||||
ColumnDfn colRegionName = AccountMgr.GetUserOrganisationColumnDfn(SaxUserOrganisation.Column.Organisation_Region_Name);
|
||||
ColumnDfn colSportId = AccountMgr.GetUserOrganisationColumnDfn(SaxUserOrganisation.Column.Organisation_SportId);
|
||||
ColumnDfn colSportName = AccountMgr.GetUserOrganisationColumnDfn(SaxUserOrganisation.Column.Organisation_Sport_Name);
|
||||
List<ColumnDfn> columns = new List<ColumnDfn>()
|
||||
{
|
||||
colOrganisationId, colOrganisationName,
|
||||
colRegionId, colRegionName,
|
||||
colSportId, colSportName
|
||||
};
|
||||
|
||||
// Organisation filter
|
||||
SaxUserOrganisation.Params prmUserOrganisation = new SaxUserOrganisation.Params();
|
||||
prmUserOrganisation.UserAccountIdsIncluded.Add(SessionUserAccountId);
|
||||
prmUserOrganisation.OrganisationStatusCat = SaxOrganisation.StatusCat.ActiveOnly;
|
||||
prmUserOrganisation.OrganisationMembersOnly = true;
|
||||
prmUserOrganisation.OrganisationRolesAny.Add(Sax.OrganisationRole.Admin);
|
||||
prmUserOrganisation.OrganisationRolesAny.Add(Sax.OrganisationRole.OpportunityAdmin);
|
||||
prmUserOrganisation.StatusCat = SaxUserOrganisation.StatusCat.ActiveOnly;
|
||||
prmUserOrganisation.SortColumns.Add(colOrganisationName);
|
||||
model.Paging.ItemTotal = (ulong)AccountMgr.GetUserOrganisationCount(prmUserOrganisation);
|
||||
model.PopulatePagingTo(prmUserOrganisation.ResultsPaging);
|
||||
using (DbResultSet resultSet = AccountMgr.ExecuteUserOrganisationQuery(columns, prmUserOrganisation))
|
||||
{
|
||||
while (resultSet != null && resultSet.HasRows && resultSet.NextRecord())
|
||||
{
|
||||
NamedValue.Map values = resultSet.GetRecordValues();
|
||||
OrganisationListData organisationData = new OrganisationListData()
|
||||
{
|
||||
Id = model.EncryptId(new SysId(values.GetLong(colOrganisationId.DataName))),
|
||||
Name = values.GetString(colOrganisationName.DataName),
|
||||
RegionId = model.EncryptId(new SysId(values.GetLong(colRegionId.DataName))),
|
||||
RegionName = values.GetString(colRegionName.DataName),
|
||||
SportId = model.EncryptId(new SysId(values.GetLong(colSportId.DataName))),
|
||||
SportName = values.GetString(colSportName.DataName),
|
||||
};
|
||||
responseData.Organisations.Add(organisationData);
|
||||
}
|
||||
}
|
||||
if (model.Paging.IsPaged)
|
||||
model.Paging.ItemCount = (ushort)responseData.Organisations.Count;
|
||||
|
||||
// Complete response.
|
||||
responseData.SetPaging(model);
|
||||
responseData.Success = true;
|
||||
return Json(responseData);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
}
|
||||
//=======================================================================
|
||||
}
|
||||
@@ -0,0 +1,193 @@
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Sarand.Net.Standard.Base.Bus;
|
||||
using Sarand.Net.Standard.Base.Core;
|
||||
using Sarand.Net.Standard.Base.Dbas;
|
||||
using Sarand.Net.Standard.Base.Utils;
|
||||
using Saxonite.Net.Core.Web.Base.App;
|
||||
using Saxonite.Net.Core.Web.Online.Models;
|
||||
using Saxonite.Net.Standard.Base.App;
|
||||
using Saxonite.Net.Standard.Base.Bus;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Saxonite.Net.Core.Web.Online.Controllers
|
||||
{
|
||||
//=======================================================================
|
||||
// Online Organisation Controller.
|
||||
//=======================================================================
|
||||
public partial class OrganisationController : SaxController_Online
|
||||
{
|
||||
//-------------------------------------------------------------------
|
||||
// Construction.
|
||||
public OrganisationController(SaxLocaliser localiser, ILogger<HomeController> logger) :
|
||||
base(localiser, logger)
|
||||
{
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
[HttpGet]
|
||||
public IActionResult Index()
|
||||
{
|
||||
// Validate session.
|
||||
if (!ValidUserSession)
|
||||
return RedirectToAction("", "");
|
||||
|
||||
// No 'Index' view as yet - default to home page.
|
||||
return RedirectToAction("", "");
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
[HttpGet]
|
||||
public IActionResult Members()
|
||||
{
|
||||
// Validate session.
|
||||
if (!ValidUserSession)
|
||||
return RedirectToAction("", "");
|
||||
|
||||
// Model.
|
||||
Model_Organisation_Members model = new Model_Organisation_Members(Localiser);
|
||||
|
||||
// Get a suitable organisation for the filter.
|
||||
SysId filterOrganisationId = SessionData_Online.Filter.OrganisationIdMember;
|
||||
String filterOrganisationCaption = SessionData_Online.Filter.OrganisationCaptionMember;
|
||||
OrganisationData organisationData = GetOrganisationForFilter(filterOrganisationId, filterOrganisationCaption, Sax.OrganisationRole.MemberAdmin);
|
||||
if (organisationData == null)
|
||||
return RedirectToAction("", "");
|
||||
|
||||
// Make a note of the filter values.
|
||||
model.Filter.OrganisationId = model.EncryptId(organisationData.Id);
|
||||
model.Filter.OrganisationCaption = organisationData.Caption;
|
||||
SessionData_Online.Filter.OrganisationIdMember = organisationData.Id;
|
||||
SessionData_Online.Filter.OrganisationCaptionMember = organisationData.Caption;
|
||||
|
||||
return View(model);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
[HttpGet]
|
||||
public IActionResult Events()
|
||||
{
|
||||
// Validate session.
|
||||
if (!ValidUserSession)
|
||||
return RedirectToAction("", "");
|
||||
|
||||
// Model.
|
||||
Model_Organisation_Events model = new Model_Organisation_Events(Localiser);
|
||||
|
||||
// Get a suitable organisation for the filter.
|
||||
SysId filterOrganisationId = SessionData_Online.Filter.OrganisationIdMember;
|
||||
String filterOrganisationCaption = SessionData_Online.Filter.OrganisationCaptionMember;
|
||||
OrganisationData organisationData = GetOrganisationForFilter(filterOrganisationId, filterOrganisationCaption, Sax.OrganisationRole.ScheduleAdmin);
|
||||
if (organisationData == null)
|
||||
return RedirectToAction("", "");
|
||||
|
||||
// Make a note of the filter values.
|
||||
model.Filter.OrganisationId = model.EncryptId(organisationData.Id);
|
||||
model.Filter.OrganisationCaption = organisationData.Caption;
|
||||
SessionData_Online.Filter.OrganisationIdMember = organisationData.Id;
|
||||
SessionData_Online.Filter.OrganisationCaptionMember = organisationData.Caption;
|
||||
|
||||
return View(model);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
[HttpGet]
|
||||
public IActionResult Opportunities()
|
||||
{
|
||||
// Validate session.
|
||||
if (!ValidUserSession)
|
||||
return RedirectToAction("", "");
|
||||
|
||||
// Model.
|
||||
Model_Organisation_Opportunities model = new Model_Organisation_Opportunities(Localiser);
|
||||
|
||||
// Get a suitable organisation for the filter.
|
||||
SysId filterOrganisationId = SessionData_Online.Filter.OrganisationIdMember;
|
||||
String filterOrganisationCaption = SessionData_Online.Filter.OrganisationCaptionMember;
|
||||
OrganisationData organisationData = GetOrganisationForFilter(filterOrganisationId, filterOrganisationCaption, Sax.OrganisationRole.OpportunityAdmin);
|
||||
if (organisationData == null)
|
||||
return RedirectToAction("", "");
|
||||
|
||||
// Make a note of the filter values.
|
||||
model.Filter.OrganisationId = model.EncryptId(organisationData.Id);
|
||||
model.Filter.OrganisationCaption = organisationData.Caption;
|
||||
SessionData_Online.Filter.OrganisationIdMember = organisationData.Id;
|
||||
SessionData_Online.Filter.OrganisationCaptionMember = organisationData.Caption;
|
||||
|
||||
return View(model);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
public class OrganisationData
|
||||
{
|
||||
public OrganisationData(SysId id) { Id = id; }
|
||||
public SysId Id { get; }
|
||||
public String Caption { get; set; }
|
||||
}
|
||||
private OrganisationData GetOrganisationForFilter(SysId filterOrganisationId, String filterOrganisationCaption, Sax.OrganisationRole organisationRole)
|
||||
{
|
||||
OrganisationData organisationData = null;
|
||||
|
||||
// Roles (any) required for organisation list.
|
||||
List<Sax.OrganisationRole> requiredRoles = new List<Sax.OrganisationRole>() { Sax.OrganisationRole.Admin };
|
||||
if (organisationRole > 0)
|
||||
requiredRoles.Add(organisationRole);
|
||||
|
||||
// Filter to identify suitable organisations that user is a member of and has the appropriate rights.
|
||||
SaxUserOrganisation.Params prmUserOrganisation = new SaxUserOrganisation.Params();
|
||||
prmUserOrganisation.UserAccountIdsIncluded.Add(SessionUserAccountId);
|
||||
prmUserOrganisation.OrganisationStatusCat = SaxOrganisation.StatusCat.ActiveOnly;
|
||||
prmUserOrganisation.OrganisationMembersOnly = true;
|
||||
prmUserOrganisation.OrganisationRolesAny.UnionWith(requiredRoles);
|
||||
prmUserOrganisation.StatusCat = SaxUserOrganisation.StatusCat.ActiveOnly;
|
||||
|
||||
if (organisationRole == Sax.OrganisationRole.ScheduleAdmin)
|
||||
{
|
||||
prmUserOrganisation.OrganisationHasScheduledEvents = true;
|
||||
}
|
||||
|
||||
// Restrict to specified Organisation.
|
||||
if (SysId.IsValid(filterOrganisationId))
|
||||
{
|
||||
// Verify that the specified organisation is valid for the filter conditions.
|
||||
prmUserOrganisation.OrganisationIdsIncluded.Add(filterOrganisationId);
|
||||
if (AccountMgr.GetUserOrganisationCount(prmUserOrganisation) < 1)
|
||||
// Specified organisation is not valid - remove restriction.
|
||||
prmUserOrganisation.OrganisationIdsIncluded.Clear();
|
||||
}
|
||||
|
||||
// Clear 'Scheduled Events' flag if no organisations available.
|
||||
if (prmUserOrganisation.OrganisationHasScheduledEvents && AccountMgr.GetUserOrganisationCount(prmUserOrganisation) < 1)
|
||||
prmUserOrganisation.OrganisationHasScheduledEvents = false;
|
||||
|
||||
// Pick the first valid Organisation.
|
||||
ColumnDfn colOrganisationId = AccountMgr.GetUserOrganisationColumnDfn(SaxUserOrganisation.Column.OrganisationId);
|
||||
ColumnDfn colOrganisationName = AccountMgr.GetUserOrganisationColumnDfn(SaxUserOrganisation.Column.Organisation_Name);
|
||||
prmUserOrganisation.SortColumns.Add(colOrganisationName);
|
||||
prmUserOrganisation.ResultsPaging.PageLength = 1;
|
||||
prmUserOrganisation.ResultsPaging.PageNo = 1;
|
||||
using (DbResultSet resultSet = AccountMgr.ExecuteUserOrganisationQuery(new List<ColumnDfn>() { colOrganisationId, colOrganisationName }, prmUserOrganisation))
|
||||
{
|
||||
if (resultSet != null && resultSet.HasRows && resultSet.NextRecord())
|
||||
{
|
||||
NamedValue.Map values = resultSet.GetRecordValues();
|
||||
SysId organisationId = new SysId(values.GetLong(colOrganisationId.DataName));
|
||||
if (SysId.IsValid(organisationId))
|
||||
{
|
||||
organisationData = new OrganisationData(organisationId)
|
||||
{
|
||||
Caption = values.GetString(colOrganisationName.DataName)
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
return organisationData;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
}
|
||||
//=======================================================================
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Saxonite.Net.Core.Web.Online.Models;
|
||||
using Saxonite.Net.Core.Web.Base.App;
|
||||
using Saxonite.Net.Core.Web.Base.Controllers;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Saxonite.Net.Core.Web.Online.Controllers
|
||||
{
|
||||
//=======================================================================
|
||||
public class PoliciesController : SaxController_Online
|
||||
{
|
||||
//-------------------------------------------------------------------
|
||||
// Construction.
|
||||
public PoliciesController(SaxLocaliser localiser, ILogger<HomeController> logger) :
|
||||
base(localiser, logger)
|
||||
{
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
[HttpGet]
|
||||
public IActionResult Index()
|
||||
{
|
||||
Model_Policies model = new Model_Policies(Localiser);
|
||||
return View(model);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
[HttpGet]
|
||||
public IActionResult Privacy()
|
||||
{
|
||||
Model_Policies model = new Model_Policies(Localiser);
|
||||
return View(model);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
}
|
||||
//=======================================================================
|
||||
}
|
||||
+64
@@ -0,0 +1,64 @@
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Sarand.Net.Standard.Base.App;
|
||||
using Sarand.Net.Standard.Base.Utils;
|
||||
using Saxonite.Net.Core.Web.Base.Models;
|
||||
using Saxonite.Net.Core.Web.Online.Models;
|
||||
using Saxonite.Net.Standard.Base.App;
|
||||
using Saxonite.Net.Standard.Base.Helpers;
|
||||
using System;
|
||||
|
||||
namespace Saxonite.Net.Core.Web.Online.Controllers
|
||||
{
|
||||
//=======================================================================
|
||||
// Online Reference Controller - Contact Method Ajax actions only.
|
||||
//=======================================================================
|
||||
partial class ReferenceController
|
||||
{
|
||||
//-------------------------------------------------------------------
|
||||
// Validate Contact Method.
|
||||
//-------------------------------------------------------------------
|
||||
private class AjaxResponse_ValidateContactMethod : AjaxResponse_Data
|
||||
{
|
||||
public AjaxResponse_ValidateContactMethod(SaxModel_Base model) : base(model) { }
|
||||
}
|
||||
[HttpPost]
|
||||
[Route("Reference/Ajax/ValidateContactMethod")]
|
||||
public IActionResult Ajax_ValidateContactMethod(Model_ContactMethod model)
|
||||
{
|
||||
String fn = GetType().Name + ".Ajax_ValidateContactMethod";
|
||||
String messageTitle = Localiser["caption.contact.method"];
|
||||
AjaxResponse_ValidateContactMethod responseData = new AjaxResponse_ValidateContactMethod(model);
|
||||
|
||||
// Validate session and referrer.
|
||||
if (!ValidReferer) return Forbid();
|
||||
if (!ValidUserSession) return GetAjaxResult_InvalidSession(responseData);
|
||||
|
||||
// Validate method.
|
||||
Sax.ContactMethod method = EnumUtil.ParseEnum(model.ContactMethod, Sax.ContactMethod.Unknown);
|
||||
if (model.ContactMethod.IsEmpty() || (int)method < 1)
|
||||
responseData.SetControlError(nameof(model.ContactMethod), Localiser["msg.validation.mandatory.value"]);
|
||||
|
||||
// Validate method.
|
||||
if (model.ContactValue.IsEmpty())
|
||||
responseData.SetControlError(nameof(model.ContactValue), Localiser["msg.validation.mandatory.value"]);
|
||||
|
||||
// Method specific value validation.
|
||||
if (!SaxContactMethodHelper.IsValidContactMethodValue(method, model.ContactValue))
|
||||
{
|
||||
// Log invalid values so that the validation can be adjusted if needed.
|
||||
SaLogger.Warn(fn + " Invalid contact method value. Mathod: " + method.ToString() + ". Value: " + model.ContactValue);
|
||||
responseData.SetControlError(nameof(model.ContactValue), Localiser["msg.validation.invalid.value"]);
|
||||
}
|
||||
|
||||
if (responseData.HasControlErrors())
|
||||
return Json(responseData);
|
||||
|
||||
// Complete response.
|
||||
responseData.Success = true;
|
||||
return Json(responseData);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
}
|
||||
//=======================================================================
|
||||
}
|
||||
@@ -0,0 +1,94 @@
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Sarand.Net.Standard.Base.App;
|
||||
using Sarand.Net.Standard.Base.Bus;
|
||||
using Sarand.Net.Standard.Base.Core;
|
||||
using Sarand.Net.Standard.Base.Dbas;
|
||||
using Saxonite.Net.Core.Web.Base.App;
|
||||
using Saxonite.Net.Core.Web.Online.Models;
|
||||
using Saxonite.Net.Standard.Base.App;
|
||||
using Saxonite.Net.Standard.Base.Bus;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Saxonite.Net.Core.Web.Online.Controllers
|
||||
{
|
||||
//=======================================================================
|
||||
// Online Reference Controller - Ajax actions only.
|
||||
//=======================================================================
|
||||
public partial class ReferenceController : SaxController_Online
|
||||
{
|
||||
//-------------------------------------------------------------------
|
||||
// Construction.
|
||||
public ReferenceController(SaxLocaliser localiser, ILogger<HomeController> logger) :
|
||||
base(localiser, logger)
|
||||
{}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Sports
|
||||
//-------------------------------------------------------------------
|
||||
private class AjaxResponse_SportList : AjaxResponse_Base
|
||||
{
|
||||
public List<SaxModel_Online.SportData> Sports { get; } = new List<SaxModel_Online.SportData>();
|
||||
}
|
||||
//-------------------------------------------------------------------
|
||||
[HttpPost]
|
||||
[Route("Reference/Ajax/GetSports")]
|
||||
public IActionResult Ajax_GetSportList(Model_Reference model)
|
||||
{
|
||||
String fn = GetType().Name + ".Ajax_GetSportList";
|
||||
String messageTitle = Localiser["reference.caption.sports"];
|
||||
AjaxResponse_SportList responseData = new AjaxResponse_SportList();
|
||||
|
||||
// Validate session and referrer.
|
||||
if (!ValidReferer) return Forbid();
|
||||
// User doesn't have to be logged in, eg. to register organisation.
|
||||
//if (!ValidUserSession) return GetAjaxResult_InvalidSession(responseData);
|
||||
|
||||
// Populate sports.
|
||||
foreach (SaxModel_Online.SportData sportData in model.GetSportDataList_Active())
|
||||
responseData.Sports.Add(sportData);
|
||||
|
||||
// Complete response.
|
||||
responseData.Success = true;
|
||||
|
||||
return Json(responseData);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Regions
|
||||
//-------------------------------------------------------------------
|
||||
private class AjaxResponse_RegionList : AjaxResponse_Base
|
||||
{
|
||||
public List<SaxModel_Online.RegionData> Regions { get; } = new List<SaxModel_Online.RegionData>();
|
||||
}
|
||||
//-------------------------------------------------------------------
|
||||
[HttpPost]
|
||||
[Route("Reference/Ajax/GetRegions")]
|
||||
public IActionResult Ajax_GetRegionList(Model_Reference model)
|
||||
{
|
||||
String fn = GetType().Name + ".Ajax_GetRegionList";
|
||||
String messageTitle = Localiser["reference.caption.regions"];
|
||||
AjaxResponse_RegionList responseData = new AjaxResponse_RegionList();
|
||||
|
||||
// Validate session and referrer.
|
||||
if (!ValidReferer) return Forbid();
|
||||
// User doesn't have to be logged in to query regions, eg. for organisation request.
|
||||
//if (!ValidUserSession) return GetAjaxResult_InvalidSession(responseData);
|
||||
|
||||
// Populate regions.
|
||||
foreach (SaxModel_Online.RegionData regionData in model.GetRegionDataList_Active())
|
||||
responseData.Regions.Add(regionData);
|
||||
|
||||
// Complete response.
|
||||
responseData.Success = true;
|
||||
|
||||
return Json(responseData);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
}
|
||||
//=======================================================================
|
||||
}
|
||||
@@ -0,0 +1,321 @@
|
||||
using Newtonsoft.Json;
|
||||
using Sarand.Net.Standard.Base.App;
|
||||
using Sarand.Net.Standard.Base.Bus;
|
||||
using Sarand.Net.Standard.Base.Core;
|
||||
using Sarand.Net.Standard.Base.Dbas;
|
||||
using Sarand.Net.Standard.Base.Helpers;
|
||||
using Sarand.Net.Standard.Base.Utils;
|
||||
using Saxonite.Net.Core.Web.Base.App;
|
||||
using Saxonite.Net.Core.Web.Base.Controllers;
|
||||
using Saxonite.Net.Core.Web.Online.App;
|
||||
using Saxonite.Net.Standard.Base.App;
|
||||
using Saxonite.Net.Standard.Base.Bus;
|
||||
using Saxonite.Net.Standard.Base.Data;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Specialized;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using System.Web;
|
||||
|
||||
namespace Saxonite.Net.Core.Web.Online.Controllers
|
||||
{
|
||||
//=======================================================================
|
||||
public class SaxController_Online : SaxController_Web
|
||||
{
|
||||
//-------------------------------------------------------------------
|
||||
// Data members.
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Protected construction.
|
||||
protected SaxController_Online(SaxLocaliser localiser, Microsoft.Extensions.Logging.ILogger<HomeController> logger) : base(localiser)
|
||||
{
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Session data.
|
||||
//-------------------------------------------------------------------
|
||||
/// <summary>Online session data</summary>
|
||||
protected SaxSessionData_Online SessionData_Online { get { return SessionData as SaxSessionData_Online; } }
|
||||
protected override SaxSessionData DeserializeSessionData(String sessionDataJson)
|
||||
{
|
||||
return JsonConvert.DeserializeObject<SaxSessionData_Online>(sessionDataJson, SaxSessionDataJsonSerializerSettings);
|
||||
}
|
||||
// Security profile.
|
||||
public bool UserIsJournalist { get { return SessionData != null && SessionData.User != null && SessionData.User.IsJournalist; } }
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// User Session.
|
||||
//-------------------------------------------------------------------
|
||||
/// <summary>
|
||||
/// Sign the account in.
|
||||
/// <para>- Record login time and clear invalid login data.</para>
|
||||
/// <para>- Open user session - store details against Sesion Data.</para>
|
||||
/// <para>- Set 'Keep logged in' cookie if required.</para>
|
||||
/// </summary>
|
||||
protected bool SignUserIn(SaxUserAccount userAccount, List<SaxUserRole> userRoles, List<SaxUserConfig> userConfigs, bool keepLoggedIn, ref String errorMessage)
|
||||
{
|
||||
String fn = GetType().Name + ".SignUserIn";
|
||||
|
||||
// Validate User Account, just in case - should have been done before arriving here!
|
||||
if (userAccount == null)
|
||||
{
|
||||
SaLogger.Error(fn + " Unable to sign account in - null user account.");
|
||||
errorMessage = Localiser["security.msg.signin.invalid"];
|
||||
return false;
|
||||
}
|
||||
if (!userAccount.IsStatusActive)
|
||||
{
|
||||
SaLogger.Error(fn + " Unable to sign account in - user account is not active. Email: " + userAccount.EmailAddress);
|
||||
errorMessage = Localiser["security.msg.signin.invalid"];
|
||||
return false;
|
||||
}
|
||||
|
||||
// 'Keep logged in' can be switched off by the application configuration.
|
||||
keepLoggedIn = App.AppConfig.Security.SignIn.KeepLoggedIn.Allowed && keepLoggedIn;
|
||||
|
||||
// Log user in.
|
||||
userAccount.KeepLoggedIn = keepLoggedIn;
|
||||
userAccount.LastLoginAt = DateTime.Now;
|
||||
userAccount.InvalidLoginCount = 0;
|
||||
//userAccount.LastInvalidLoginAt = null;
|
||||
if (!AccountMgr.UpdateUserAccount(userAccount, DbUpdateInfo))
|
||||
{
|
||||
SaLogger.Warn(fn + " Failed to update account for " + userAccount.EmailAddress + ": " + AccountMgr.ErrorStateMessage);
|
||||
errorMessage = Localiser["security.msg.signin.invalid"];
|
||||
return false;
|
||||
}
|
||||
SaLogger.Info(fn + " User session opened for " + userAccount.EmailAddress, true);
|
||||
|
||||
// Create session.
|
||||
OpenUserSession(SessionContext, userAccount, userRoles);
|
||||
RefreshSessionProfileSports();
|
||||
|
||||
// Refresh User configuration.
|
||||
foreach (SaxUserConfig userConfig in userConfigs)
|
||||
{
|
||||
switch (userConfig.ConfigType)
|
||||
{
|
||||
case Sax.UserConfigType.Online_Profile:
|
||||
SessionData_Online.UserConfig.Profile = SaxConfigData.ProfileData.FromXml(userConfig.ConfigData);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Send the 'Keep Logged In' cookie if requested.
|
||||
if (userAccount.KeepLoggedIn)
|
||||
SetKeepLoggedInCookie();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
/// <summary>Populate the user's profile contact details to the session.</summary>
|
||||
protected bool RefreshSessionProfileContact(SaxUserAccount userAccount)
|
||||
{
|
||||
String fn = GetType().Name + ".RefreshSessionProfileContact";
|
||||
SaxSessionData_Online sessionData = SessionData_Online;
|
||||
SysId userAccountId = sessionData?.User.UserAccountId ?? null;
|
||||
if (!SysId.IsValid(userAccountId)) return false;
|
||||
if (!SysId.IsValid(userAccount?.Id ?? null)) return false;
|
||||
if (!userAccountId.Equals(userAccount.Id)) return false;
|
||||
|
||||
sessionData.RefreshUser(userAccount);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
/// <summary>Populate the user's profile sports to the session.</summary>
|
||||
protected bool RefreshSessionProfileSports()
|
||||
{
|
||||
String fn = GetType().Name + ".RefreshSessionProfileSports";
|
||||
SaxSessionData_Online sessionData = SessionData_Online;
|
||||
SysId userAccountId = sessionData?.User.UserAccountId ?? null;
|
||||
if (!SysId.IsValid(userAccountId)) return false;
|
||||
sessionData.Profile.ClearSports();
|
||||
|
||||
// Read discrete values to avoid loading the entire UserSport records which can be substantial.
|
||||
ColumnDfn colSportId = AccountMgr.GetUserSportColumnDfn(SaxUserSport.Column.SportId);
|
||||
ColumnDfn colSportName = AccountMgr.GetUserSportColumnDfn(SaxUserSport.Column.Sport_Name);
|
||||
ColumnDfn colParticipating = AccountMgr.GetUserSportColumnDfn(SaxUserSport.Column.SportParticipating);
|
||||
ColumnDfn colPreparing = AccountMgr.GetUserSportColumnDfn(SaxUserSport.Column.SportPreparing);
|
||||
ColumnDfn colOfficiating = AccountMgr.GetUserSportColumnDfn(SaxUserSport.Column.SportOfficiating);
|
||||
ColumnDfn colStatus = AccountMgr.GetUserSportColumnDfn(SaxUserSport.Column.Status);
|
||||
|
||||
SaxUserSport.Params prmUserSport = new SaxUserSport.Params();
|
||||
prmUserSport.UserAccountIdsIncluded.Add(userAccountId);
|
||||
prmUserSport.StatusCat = SaxUserSport.StatusCat.ActiveOnly;
|
||||
using (DbResultSet resultSet = AccountMgr.ExecuteUserSportQuery(new List<ColumnDfn>() { colSportId, colSportName, colParticipating, colOfficiating, colStatus }, prmUserSport))
|
||||
{
|
||||
while (resultSet != null && resultSet.NextRecord())
|
||||
{
|
||||
NamedValue.Map values = resultSet.GetRecordValues();
|
||||
SysId sportId = new SysId(values.GetLong(colSportId.DataName));
|
||||
String sportName = values.GetString(colSportName.DataName);
|
||||
Sax.SportParticipating participating = (Sax.SportParticipating)values.GetLong(colParticipating.DataName);
|
||||
Sax.SportPreparing preparing = (Sax.SportPreparing)values.GetLong(colPreparing.DataName);
|
||||
Sax.SportOfficiating officiating = (Sax.SportOfficiating)values.GetLong(colOfficiating.DataName);
|
||||
SaStatus status = SacsSystem.GetStatusForCode(values.GetString(colStatus.DataName));
|
||||
sessionData.Profile.AddSport(sportId, status);
|
||||
}
|
||||
}
|
||||
SaLogger.Debug(fn + " Profile Sports: " + sessionData.Profile.SportCount);
|
||||
return true;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
/// <summary>Start a new user session on sign-in.</summary>
|
||||
protected bool OpenUserSession(SaxSessionContext sessionContext, SaxUserAccount userAccount, List<SaxUserRole> userRoles)
|
||||
{
|
||||
// Validate user properties.
|
||||
if (!SysId.IsValid(userAccount.Id)) return false;
|
||||
if (StringUtil.IsEmpty(userAccount.EmailAddress)) return false;
|
||||
|
||||
// Close previous session.
|
||||
CloseUserSession();
|
||||
|
||||
// Open session.
|
||||
return SetSessionData(new SaxSessionData_Online(sessionContext, userAccount, userRoles));
|
||||
}
|
||||
protected void CloseUserSession()
|
||||
{
|
||||
ClearSessionData();
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Image utilities.
|
||||
//-------------------------------------------------------------------
|
||||
/// <summary>
|
||||
/// Construct URL to display Organisation logo.
|
||||
/// <para>- Option to allow for 'Upload' image if active.</para>
|
||||
/// </summary>
|
||||
public String GetOrganisationLogoLink(SysId organisationId, bool uploadImage)
|
||||
{
|
||||
String imageLink = "Image/Organisation/Logo" + (uploadImage ? "/Upload" : "") + "?";
|
||||
NameValueCollection parameters = new NameValueCollection();
|
||||
parameters.Add(ImageController.ParamName_OrganisationId, SysId.ToString(organisationId));
|
||||
return imageLink + ImageController.ParamName_OrganisationLogoEncrypted + "=" + EncryptOnlineParams(parameters);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Construct URL to display specific item image.
|
||||
/// </summary>
|
||||
public String GetItemImageLink(SysId itemImageId)
|
||||
{
|
||||
String imageLink = "Image/Item?";
|
||||
NameValueCollection parameters = new NameValueCollection();
|
||||
parameters.Add(ImageController.ParamName_ItemImageId, SysId.ToString(itemImageId));
|
||||
return imageLink + ImageController.ParamName_ItemImageEncrypted + "=" + EncryptOnlineParams(parameters);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Keep Logged In.
|
||||
//-------------------------------------------------------------------
|
||||
/// <summary>Keep-Logged-In cookie.</summary>
|
||||
protected void SetKeepLoggedInCookie()
|
||||
{
|
||||
String keepLoggedInCookieValue = GenerateKeepLoggedInCookieValue();
|
||||
int cookieExpiresDays = Math.Max(Sax.Config.Security.SignIn.KeepLoggedIn.CookieExpiresDays_Min, Math.Min(Sax.Config.Security.SignIn.KeepLoggedIn.CookieExpiresDays_Max, AppConfig.Security.SignIn.KeepLoggedIn.CookieExpiresDays));
|
||||
SetResponseCookie(KeepLoggedIn.CookieName, keepLoggedInCookieValue, DateTime.Now.AddDays(cookieExpiresDays), true);
|
||||
SaLogger.Info(this.GetType().Name + ".SetKeepLoggedInCookie 'Keep Logged In' cookie set. Value: " + keepLoggedInCookieValue);
|
||||
}
|
||||
|
||||
/// <summary>Set the 'Keep Logged In' response cookie to expired with no data.</summary>
|
||||
public void ClearKeepLoggedInCookie()
|
||||
{
|
||||
if (StringUtil.IsEmpty(GetRequestCookie(KeepLoggedIn.CookieName))) return;
|
||||
// Clear cookie by setting expiry date in the past.
|
||||
SetResponseCookie(KeepLoggedIn.CookieName, "", DateTime.Today.AddDays(-7), true);
|
||||
SaLogger.Info($"{SysUtil.Fn} 'Keep Logged In' cookie cleared.");
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// 'Keep Logged In' cookie and encryption config.
|
||||
// NB - IV value is generated from the key and fixed so that it doesn't change when the application restarts
|
||||
// to ensure that cookie value can be decrypted even if application restarts in the meantime.
|
||||
// - Generating IV from same key results in different value each time.
|
||||
// - IV Must be regenerated if key is changed: uncomment 'Generated' variable and copy resulting value to IV variable.
|
||||
// NB - 'Keep Logged In' is termed 'Remember Me' in the Online application.
|
||||
public static class KeepLoggedIn
|
||||
{
|
||||
public static String CookieName = "SAXRM";
|
||||
public static String Base64Key = SacsEncryptionHelper.EncodePlainKey("<=Saxonite^OnlIne{R$Member-m3}~>", SacsEncryptionHelper.KeyLength);
|
||||
public const String Purpose = "Saxonite.Online.KeepLoggedIn";
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Keep-logged-in cookie value.
|
||||
private static readonly String ParamName_KeepLoggedIn_UserAccountId = "uai";
|
||||
private String GenerateKeepLoggedInCookieValue()
|
||||
{
|
||||
NameValueCollection keepLoggedInParams = new NameValueCollection();
|
||||
keepLoggedInParams.Add(ParamName_KeepLoggedIn_UserAccountId, SysId.ToString(SessionData_Online.User.UserAccountId));
|
||||
return EncryptParameters(keepLoggedInParams, KeepLoggedIn.Base64Key, KeepLoggedIn.Purpose);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
public class KeepLoggedInParams
|
||||
{
|
||||
public SysId UserAccountId { get; set; }
|
||||
/// <summary>Retrieve the list of valid parameters in printable format [Name: Value].</summary>
|
||||
public List<String> GetValidParams()
|
||||
{
|
||||
List<String> values = new List<String>();
|
||||
if (SysId.IsValid(UserAccountId))
|
||||
values.Add("UserAccountId: " + SysId.ToString(UserAccountId));
|
||||
return values;
|
||||
}
|
||||
}
|
||||
public KeepLoggedInParams ExtractKeepLoggedInParams(String encryptedParams)
|
||||
{
|
||||
KeepLoggedInParams keepLoggedInParams = new KeepLoggedInParams();
|
||||
if (!StringUtil.IsEmpty(encryptedParams))
|
||||
{
|
||||
NameValueCollection linkParams = DecryptParameters(encryptedParams, KeepLoggedIn.Base64Key, KeepLoggedIn.Purpose);
|
||||
keepLoggedInParams.UserAccountId = new SysId(StringUtil.ToInt(linkParams.Get(ParamName_KeepLoggedIn_UserAccountId)));
|
||||
}
|
||||
if (DebugMode) SaLogger.Info($"{SysUtil.Fn} UserAccountId: {SysId.ToString(keepLoggedInParams.UserAccountId)}");
|
||||
return keepLoggedInParams;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Parameter encryption, eg. for images.
|
||||
//-------------------------------------------------------------------
|
||||
// Purpose-bound AES-GCM envelopes use a fresh nonce for every encrypted value.
|
||||
public static String Base64Key_OnlineApp { get; } = SacsEncryptionHelper.EncodePlainKey("Saxonite#Online@Encrypt+" + DateTime.Today.Format("ddMMyyyy"), SacsEncryptionHelper.KeyLength);
|
||||
private const String Purpose_OnlineApp = "Saxonite.Online.Parameters";
|
||||
protected String EncryptOnlineParams(NameValueCollection parameters)
|
||||
{
|
||||
return HttpUtility.UrlEncode(EncryptParameters(parameters, Base64Key_OnlineApp, Purpose_OnlineApp));
|
||||
}
|
||||
protected NameValueCollection ExtractOnlineParams(String encryptedParams)
|
||||
{
|
||||
return DecryptParameters(encryptedParams, Base64Key_OnlineApp, Purpose_OnlineApp);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Logging.
|
||||
//-------------------------------------------------------------------
|
||||
/// <summary>
|
||||
/// Log suffix:
|
||||
/// <para>- User's email address.</para>
|
||||
/// <para>- Prefixed with space.</para>
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
protected String GetLogSuffix()
|
||||
{
|
||||
List<String> logSuffix = new List<string>();
|
||||
SaxSessionData_Online sessionData = SessionData_Online;
|
||||
if (sessionData != null)
|
||||
{
|
||||
if (!StringUtil.IsEmpty(sessionData.User.EmailAddress))
|
||||
logSuffix.Add("User: " + sessionData.User.EmailAddress);
|
||||
}
|
||||
return logSuffix.Concat("", " ", ".");
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
}
|
||||
//=======================================================================
|
||||
}
|
||||
+403
@@ -0,0 +1,403 @@
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Saxonite.Net.Core.Web.Online.Models;
|
||||
using Saxonite.Net.Core.Web.Base.App;
|
||||
using Saxonite.Net.Core.Web.Base.Controllers;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Saxonite.Net.Standard.Base.Bus;
|
||||
using Sarand.Net.Standard.Base.App;
|
||||
using Sarand.Net.Standard.Base.Bus;
|
||||
using Sarand.Net.Standard.Base.Utils;
|
||||
using Sarand.Net.Standard.Base.Core;
|
||||
using Sarand.Net.Standard.Base.Dbas;
|
||||
using Saxonite.Net.Standard.Base.App;
|
||||
using Saxonite.Net.Core.Web.Online.Helpers;
|
||||
using Org.BouncyCastle.Security;
|
||||
using static Saxonite.Net.Standard.Base.App.Sax;
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace Saxonite.Net.Core.Web.Online.Controllers
|
||||
{
|
||||
//=======================================================================
|
||||
// Online Search Controller - Organisations - Ajax actions.
|
||||
//=======================================================================
|
||||
partial class SearchController
|
||||
{
|
||||
//-------------------------------------------------------------------
|
||||
// Account - Get Organisations.
|
||||
//-------------------------------------------------------------------
|
||||
private class OrganisationListData : AjaxResponse_Data.ItemData_Base
|
||||
{
|
||||
public String Name { get; set; }
|
||||
public String CategoryDesc { get; set; }
|
||||
public String SportName { get; set; }
|
||||
public String RegionName { get; set; }
|
||||
public String LogoUrl { get; set; }
|
||||
}
|
||||
private class AjaxResponse_Search_Organisations : AjaxResponse_Data
|
||||
{
|
||||
// Construction.
|
||||
public AjaxResponse_Search_Organisations(SaxModel_Online model) : base(model) { }
|
||||
// Organisation list.
|
||||
public List<OrganisationListData> Organisations { get; } = new List<OrganisationListData>();
|
||||
}
|
||||
// Ajax request.
|
||||
[HttpPost]
|
||||
[Route("Search/Ajax/Organisations")]
|
||||
[Route("Search/Ajax/GetOrganisations")]
|
||||
public IActionResult Ajax_GetOrganisations(Model_Search_Organisations model)
|
||||
{
|
||||
String fn = GetType().Name + ".Ajax_GetOrganisations";
|
||||
AjaxResponse_Search_Organisations responseData = new AjaxResponse_Search_Organisations(model);
|
||||
String messageTitle = Localiser["organisation.caption.organisations"];
|
||||
|
||||
// Validate session and referrer.
|
||||
if (!ValidReferer) return Forbid();
|
||||
if (!ValidUserSession) return GetAjaxResult_InvalidSession(responseData);
|
||||
RefreshModel(model);
|
||||
|
||||
// Ensure data is paged to avoid leaking large volumes.
|
||||
model.Paging.PageNo = Math.Max(1, model.Paging.PageNo);
|
||||
model.Paging.PageLength = Math.Max(Math.Min(Sax.Config.Online.Search.Organisations.PageLengthMax, model.Paging.PageLength), (ushort)1);
|
||||
|
||||
// Query organisations that user is a member of.
|
||||
SaxOrganisation.Params prmOrganisation = new SaxOrganisation.Params();
|
||||
prmOrganisation.OrganisationFilter = model.Filter.Organisation;
|
||||
prmOrganisation.OrganisationType = model.FilterOrganisationType;
|
||||
prmOrganisation.OrganisationCategory = model.FilterOrganisationCategory;
|
||||
prmOrganisation.OrganisationCategoriesExcluded.Add(Sax.OrganisationCategory.Partner);
|
||||
prmOrganisation.OrganisationCategoriesExcluded.Add(Sax.OrganisationCategory.Other);
|
||||
if (SysId.IsValid(model.FilterSportId))
|
||||
prmOrganisation.SportIdsIncluded.Add(model.FilterSportId);
|
||||
if (SysId.IsValid(model.FilterRegionId))
|
||||
prmOrganisation.RegionIdsIncluded.Add(model.FilterRegionId);
|
||||
prmOrganisation.StatusCat = SaxOrganisation.StatusCat.ActiveOnly;
|
||||
model.Paging.ItemTotal = (ulong)AccountMgr.GetOrganisationCount(prmOrganisation);
|
||||
model.PopulatePagingTo(prmOrganisation.ResultsPaging);
|
||||
|
||||
List<SaxOrganisation> organisations = AccountMgr.GetOrganisationList(prmOrganisation);
|
||||
List<SysId> organisationIds = organisations.GetIds();
|
||||
|
||||
// Item columns.
|
||||
ColumnDfn colId = AccountMgr.GetOrganisationColumnDfn(SaxOrganisation.Column.Id);
|
||||
ColumnDfn colName = AccountMgr.GetOrganisationColumnDfn(SaxOrganisation.Column.Name);
|
||||
ColumnDfn colCategory = AccountMgr.GetOrganisationColumnDfn(SaxOrganisation.Column.OrganisationCategory_Desc);
|
||||
ColumnDfn colSportId = AccountMgr.GetOrganisationColumnDfn(SaxOrganisation.Column.SportId);
|
||||
ColumnDfn colSportName = AccountMgr.GetOrganisationColumnDfn(SaxOrganisation.Column.Sport_Name);
|
||||
ColumnDfn colRegionId = AccountMgr.GetOrganisationColumnDfn(SaxOrganisation.Column.RegionId);
|
||||
ColumnDfn colRegionName = AccountMgr.GetOrganisationColumnDfn(SaxOrganisation.Column.Region_Name);
|
||||
ColumnDfn colLogoCount = AccountMgr.GetOrganisationColumnDfn(SaxOrganisation.Column.LogoImage_Count);
|
||||
List<ColumnDfn> columns = new List<ColumnDfn>()
|
||||
{
|
||||
colId, colName, colCategory,
|
||||
colSportId, colSportName,
|
||||
colRegionId, colRegionName,
|
||||
colLogoCount
|
||||
};
|
||||
|
||||
// Sort columns.
|
||||
colName.SortAscending = true;
|
||||
prmOrganisation.SortColumns.Add(colName);
|
||||
|
||||
// Query items.
|
||||
using (DbResultSet resultSet = AccountMgr.ExecuteOrganisationQuery(columns, prmOrganisation))
|
||||
{
|
||||
while (resultSet != null && resultSet.HasRows && resultSet.NextRecord())
|
||||
{
|
||||
NamedValue.Map values = resultSet.GetRecordValues();
|
||||
SysId organisationId = new SysId(values.GetLong(colId.DataName));
|
||||
Sax.OrganisationCategory category = (Sax.OrganisationCategory)OrganisationCategoryCodes.GetTypeForCode(values.GetString(colCategory.DataName));
|
||||
OrganisationListData organisationData = new OrganisationListData()
|
||||
{
|
||||
Id = model.EncryptId(organisationId),
|
||||
Name = values.GetString(colName.DataName),
|
||||
CategoryDesc = Localiser.GetOrganisationCategoryCaption(category),
|
||||
SportName = values.GetString(colSportName.DataName),
|
||||
RegionName = values.GetString(colRegionName.DataName),
|
||||
};
|
||||
// Logo.
|
||||
if (values.GetLong(colLogoCount.DataName) > 0)
|
||||
organisationData.LogoUrl = GetOrganisationLogoLink(organisationId, false);
|
||||
|
||||
// Add item to the list.
|
||||
responseData.Organisations.Add(organisationData);
|
||||
}
|
||||
}
|
||||
if (model.Paging.IsPaged)
|
||||
model.Paging.ItemCount = (ushort)responseData.Organisations.Count;
|
||||
|
||||
// Complete response.
|
||||
responseData.SetPaging(model);
|
||||
responseData.Success = true;
|
||||
return Json(responseData);
|
||||
}
|
||||
//-------------------------------------------------------------------
|
||||
// Account - Get Organisation.
|
||||
//-------------------------------------------------------------------
|
||||
/// <summary>
|
||||
/// Associations are grouped by type and direction (parent->child).
|
||||
/// <br>The organisation specified in each case is the 'other' organisation (not the current 'target' organisation).</br>
|
||||
/// </summary>
|
||||
private class AssociationTypeData
|
||||
{
|
||||
public String Caption { get; set; }
|
||||
public List<AssociationOrganisationData> Organisations { get; } = new List<AssociationOrganisationData>();
|
||||
}
|
||||
/// <summary>
|
||||
/// Association Organisation - the one that is not the current 'target' organisation.
|
||||
/// <br>Region and Sport are only populate if different from the 'target' organisation.</br>
|
||||
/// </summary>
|
||||
private class AssociationOrganisationData
|
||||
{
|
||||
[JsonIgnore]
|
||||
public SysId OrganisationId { get; set; }
|
||||
public String Id { get; set; }
|
||||
public String Name { get; set; }
|
||||
public String Display
|
||||
{
|
||||
get
|
||||
{
|
||||
String display = Name;
|
||||
if (!StringUtil.IsBlank(Sport) || !StringUtil.IsBlank(Region))
|
||||
display += " (" + String.Join(", ", new List<String> { Sport, Region }.Where(item => !StringUtil.IsBlank(item))) + ")";
|
||||
return display;
|
||||
}
|
||||
}
|
||||
public String Region { get; set; }
|
||||
public String Sport { get; set; }
|
||||
public String LogoUrl { get; set; }
|
||||
}
|
||||
private class OrganisationItemData : OrganisationListData
|
||||
{
|
||||
public String TypeDesc { get; set; }
|
||||
public String About { get; set; }
|
||||
public String Facilities { get; set; }
|
||||
public List<AjaxResponse_Data.ItemLabelValue> Contacts { get; set; }
|
||||
public String Address { get; set; }
|
||||
public String PostalCode { get; set; }
|
||||
public List<AssociationTypeData> Associations { get; } = new List<AssociationTypeData>();
|
||||
}
|
||||
private class AjaxResponse_Search_Organisation : AjaxResponse_Data
|
||||
{
|
||||
// Construction.
|
||||
public AjaxResponse_Search_Organisation(SaxModel_Online model) : base(model) { }
|
||||
// Organisation list.
|
||||
public OrganisationItemData Organisation { get; set; }
|
||||
}
|
||||
// Ajax request.
|
||||
[HttpPost]
|
||||
[Route("Search/Ajax/Organisation")]
|
||||
[Route("Search/Ajax/GetOrganisation")]
|
||||
public IActionResult Ajax_GetOrganisation(Model_Search_Organisations model)
|
||||
{
|
||||
String fn = GetType().Name + ".Ajax_GetOrganisation";
|
||||
AjaxResponse_Search_Organisation responseData = new AjaxResponse_Search_Organisation(model);
|
||||
String messageTitle = Localiser["label.organisation"];
|
||||
|
||||
// Validate session and referrer.
|
||||
if (!ValidReferer) return Forbid();
|
||||
if (!ValidUserSession) return GetAjaxResult_InvalidSession(responseData);
|
||||
RefreshModel(model);
|
||||
|
||||
// Record disposable items as they are created so all can be disposed when needed.
|
||||
using (DisposableCollection<IDisposable> disposableItems = new DisposableCollection<IDisposable>())
|
||||
{
|
||||
|
||||
// Retrieve organisation.
|
||||
SysId organisationId = model.ExtractSysId(model.OrganisationId);
|
||||
if (!SysId.IsValid(organisationId))
|
||||
{
|
||||
SaLogger.Warn(fn + " Organisation Id not supplied.");
|
||||
return Json(responseData);
|
||||
}
|
||||
SaxOrganisation organisation = AccountMgr.GetOrganisationById(organisationId);
|
||||
if (organisation == null)
|
||||
{
|
||||
SaLogger.Warn(fn + " Failed to retrieve organisation. Id: " + model.OrganisationId);
|
||||
return Json(responseData);
|
||||
}
|
||||
disposableItems.Add(organisation);
|
||||
|
||||
// ToDo May-2022 TESTING.
|
||||
//SaLogger.Info(fn + " Organisation: " + organisation.Name + "\nAbout: " + organisation.About + "\nFacilities: " + organisation.Facilities, true);
|
||||
|
||||
// Populate response.
|
||||
OrganisationItemData organisationData = new OrganisationItemData()
|
||||
{
|
||||
Id = model.EncryptId(organisation.Id),
|
||||
Name = organisation.Name,
|
||||
CategoryDesc = Localiser.GetOrganisationCategoryCaption(organisation.OrganisationCategory),
|
||||
TypeDesc = Localiser.GetOrganisationTypeCaption(organisation.OrganisationType),
|
||||
SportName = model.GetSportCaption(organisation.SportIdPrimary),
|
||||
RegionName = model.GetRegionCaption(organisation.RegionIdPrimary),
|
||||
About = organisation.About,
|
||||
Facilities = organisation.Facilities,
|
||||
};
|
||||
responseData.Organisation = organisationData;
|
||||
|
||||
// Contacts.
|
||||
SaxContactData contactData = new SaxContactData(organisation.ContactData);
|
||||
if (contactData.Methods.Count > 0)
|
||||
{
|
||||
responseData.Organisation.Contacts = new List<AjaxResponse_Data.ItemLabelValue>();
|
||||
foreach (Sax.ContactMethod method in contactData.Methods)
|
||||
{
|
||||
AjaxResponse_Data.ItemLabelValue contact = new AjaxResponse_Data.ItemLabelValue()
|
||||
{
|
||||
Label = Localiser.GetContactMethodCaption(method),
|
||||
Value = SaxContactMethodHelper_Online.GetContactMethodHtml(method, contactData.GetContactMethodValue(method), Localiser)
|
||||
};
|
||||
responseData.Organisation.Contacts.Add(contact);
|
||||
}
|
||||
}
|
||||
|
||||
// Organisation address.
|
||||
SaxItemAddress address = ItemDataMgr.GetFirstItemAddressByItemAndType(organisation.GetItemId());
|
||||
if (address != null)
|
||||
{
|
||||
String addressLines = (new List<string>() { address.Line1, address.Line2, address.Line3 }).Concat(", ", "", "", true, true);
|
||||
String addressTownProvince = (new List<string>() { address.Town, address.Province }).Concat(", ", "", "", true, true);
|
||||
organisationData.Address = (new List<String>() { addressLines, addressTownProvince }).Concat("\n", "", "", true, true);
|
||||
organisationData.PostalCode = address.PostalCode;
|
||||
}
|
||||
|
||||
// Associations.
|
||||
Dictionary<SaxItemAssociation.TypeOptionData, List<AssociationOrganisationData>> associationTypeGroups = new Dictionary<SaxItemAssociation.TypeOptionData, List<AssociationOrganisationData>>();
|
||||
ColumnDfn colId = ItemDataMgr.GetItemAssociationColumnDfn(SaxItemAssociation.Column.Id);
|
||||
ColumnDfn colAssociationType = ItemDataMgr.GetItemAssociationColumnDfn(SaxItemAssociation.Column.AssociationType);
|
||||
ColumnDfn colItemTypeFrom = ItemDataMgr.GetItemAssociationColumnDfn(SaxItemAssociation.Column.ItemTypeFrom);
|
||||
ColumnDfn colItemIdFrom = ItemDataMgr.GetItemAssociationColumnDfn(SaxItemAssociation.Column.ItemIdFrom);
|
||||
ColumnDfn colOrganisationFrom_Name = ItemDataMgr.GetItemAssociationColumnDfn(SaxItemAssociation.Column.OrganisationFrom_Name);
|
||||
ColumnDfn colOrganisationFrom_SportIdPrimary = ItemDataMgr.GetItemAssociationColumnDfn(SaxItemAssociation.Column.OrganisationFrom_SportIdPrimary);
|
||||
ColumnDfn colOrganisationFrom_RegionIdPrimary = ItemDataMgr.GetItemAssociationColumnDfn(SaxItemAssociation.Column.OrganisationFrom_RegionIdPrimary);
|
||||
ColumnDfn colItemTypeTo = ItemDataMgr.GetItemAssociationColumnDfn(SaxItemAssociation.Column.ItemTypeTo);
|
||||
ColumnDfn colItemIdTo = ItemDataMgr.GetItemAssociationColumnDfn(SaxItemAssociation.Column.ItemIdTo);
|
||||
ColumnDfn colOrganisationTo_Name = ItemDataMgr.GetItemAssociationColumnDfn(SaxItemAssociation.Column.OrganisationTo_Name);
|
||||
ColumnDfn colOrganisationTo_SportIdPrimary = ItemDataMgr.GetItemAssociationColumnDfn(SaxItemAssociation.Column.OrganisationTo_SportIdPrimary);
|
||||
ColumnDfn colOrganisationTo_RegionIdPrimary = ItemDataMgr.GetItemAssociationColumnDfn(SaxItemAssociation.Column.OrganisationTo_RegionIdPrimary);
|
||||
List<ColumnDfn> associationCols = new List<ColumnDfn>()
|
||||
{
|
||||
colId, colAssociationType,
|
||||
colItemTypeFrom, colItemIdFrom, colOrganisationFrom_Name, colOrganisationFrom_SportIdPrimary, colOrganisationFrom_RegionIdPrimary,
|
||||
colItemTypeTo, colItemIdTo, colOrganisationTo_Name, colOrganisationTo_SportIdPrimary, colOrganisationTo_RegionIdPrimary
|
||||
};
|
||||
List<SysId> assocOrganisationIds = new List<SysId>();
|
||||
SaxItemAssociation.Params prmAssociations = new SaxItemAssociation.Params();
|
||||
prmAssociations.ItemIdsIncluded.Add(organisation.GetItemId());
|
||||
prmAssociations.StatusCat = SaxItemAssociation.StatusCat.ActiveOnly;
|
||||
using (DbResultSet resultSet = ItemDataMgr.ExecuteItemAssociationQuery(associationCols, prmAssociations))
|
||||
{
|
||||
while (resultSet != null && resultSet.HasRows && resultSet.NextRecord())
|
||||
{
|
||||
NamedValue.Map values = resultSet.GetRecordValues();
|
||||
SysId associationId = new SysId(values.GetLong(colId.DataName));
|
||||
Sax.AssociationType associationType = (Sax.AssociationType)values.GetLong(colAssociationType.DataName);
|
||||
ItemId itemIdFrom = new ItemId((short)values.GetLong(colItemTypeFrom.DataName), new SysId(values.GetLong(colItemIdFrom.DataName)));
|
||||
ItemId itemIdTo = new ItemId((short)values.GetLong(colItemTypeTo.DataName), new SysId(values.GetLong(colItemIdTo.DataName)));
|
||||
bool associationTypeDirectionReversed = associationType == Sax.AssociationType.Affiliate && itemIdTo.Id.Equals(organisation.Id);
|
||||
// Determine association type group.
|
||||
SaxItemAssociation.TypeOptionData assocTypeOption = new SaxItemAssociation.TypeOptionData(associationType, associationTypeDirectionReversed, GetAssociationTypeOptionCaption(associationType, associationTypeDirectionReversed));
|
||||
List<AssociationOrganisationData> organisations = associationTypeGroups.GetValue(assocTypeOption, null);
|
||||
if (organisations == null)
|
||||
associationTypeGroups.Add(assocTypeOption, organisations = new List<AssociationOrganisationData>());
|
||||
// Populate organisation properties.
|
||||
SysId orgSportIdFrom = new SysId(values.GetLong(colOrganisationFrom_SportIdPrimary.DataName));
|
||||
SysId orgRegionIdFrom = new SysId(values.GetLong(colOrganisationFrom_RegionIdPrimary.DataName));
|
||||
SysId orgSportIdTo = new SysId(values.GetLong(colOrganisationTo_SportIdPrimary.DataName));
|
||||
SysId orgRegionIdTo = new SysId(values.GetLong(colOrganisationTo_RegionIdPrimary.DataName));
|
||||
if (itemIdTo.Id.Equals(organisation.Id))
|
||||
{
|
||||
// 'From' item is the 'Other' organisation.
|
||||
AssociationOrganisationData assocOrgData = new AssociationOrganisationData();
|
||||
assocOrgData.OrganisationId = itemIdFrom.Id;
|
||||
assocOrganisationIds.AddId(assocOrgData.OrganisationId);
|
||||
assocOrgData.Id = model.EncryptId(assocOrgData.OrganisationId);
|
||||
assocOrgData.Name = values.GetString(colOrganisationFrom_Name.DataName);
|
||||
if (!orgSportIdFrom.Equals(orgSportIdTo))
|
||||
assocOrgData.Sport = model.GetSportCaption(orgSportIdFrom);
|
||||
if (!orgRegionIdFrom.Equals(orgRegionIdTo))
|
||||
assocOrgData.Region = model.GetRegionCaption(orgRegionIdFrom);
|
||||
organisations.Add(assocOrgData);
|
||||
}
|
||||
else
|
||||
{
|
||||
// 'To' item is the 'Other' organisation.
|
||||
AssociationOrganisationData assocOrgData = new AssociationOrganisationData();
|
||||
assocOrgData.OrganisationId = itemIdTo.Id;
|
||||
assocOrganisationIds.AddId(assocOrgData.OrganisationId);
|
||||
assocOrgData.Id = model.EncryptId(assocOrgData.OrganisationId);
|
||||
assocOrgData.Name = values.GetString(colOrganisationTo_Name.DataName);
|
||||
if (!orgSportIdFrom.Equals(orgSportIdTo))
|
||||
assocOrgData.Sport = model.GetSportCaption(orgSportIdTo);
|
||||
if (!orgRegionIdFrom.Equals(orgRegionIdTo))
|
||||
assocOrgData.Region = model.GetRegionCaption(orgRegionIdTo);
|
||||
organisations.Add(assocOrgData);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Populate Associated Orgaisation Logo URLs.
|
||||
if (assocOrganisationIds.Any())
|
||||
{
|
||||
ColumnDfn colAssocOrganisation_Id = AccountMgr.GetOrganisationColumnDfn(SaxOrganisation.Column.Id);
|
||||
ColumnDfn colAssocOrganisation_LogoCount = AccountMgr.GetOrganisationColumnDfn(SaxOrganisation.Column.LogoImage_Count);
|
||||
List<ColumnDfn> columns = new List<ColumnDfn>() { colAssocOrganisation_Id, colAssocOrganisation_LogoCount };
|
||||
SaxOrganisation.Params prmAssocOrganisation = new SaxOrganisation.Params();
|
||||
prmAssocOrganisation.IdsIncluded.AddIds(assocOrganisationIds);
|
||||
using (DbResultSet resultSet = AccountMgr.ExecuteOrganisationQuery(columns, prmAssocOrganisation))
|
||||
{
|
||||
while (resultSet != null && resultSet.HasRows && resultSet.NextRecord())
|
||||
{
|
||||
NamedValue.Map values = resultSet.GetRecordValues();
|
||||
SysId assocOrganisationId = new SysId(values.GetLong(colAssocOrganisation_Id.DataName));
|
||||
if (values.GetLong(colAssocOrganisation_LogoCount.DataName) > 0)
|
||||
{
|
||||
foreach (List<AssociationOrganisationData> assocOrganisations in associationTypeGroups.Values)
|
||||
{
|
||||
foreach (AssociationOrganisationData assocOrganisation in assocOrganisations.Where(item => item.OrganisationId.Equals(assocOrganisationId)))
|
||||
assocOrganisation.LogoUrl = GetOrganisationLogoLink(assocOrganisation.OrganisationId, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Populate associations to response.
|
||||
foreach (SaxItemAssociation.TypeOptionData associationTypeGroup in associationTypeGroups.Keys.OrderBy(item => (int)item.TypeOption))
|
||||
{
|
||||
AssociationTypeData associationTypeData = new AssociationTypeData();
|
||||
associationTypeData.Caption = associationTypeGroup.Caption;
|
||||
associationTypeData.Organisations.AddRange(associationTypeGroups.GetValue(associationTypeGroup, new List<AssociationOrganisationData>()).OrderBy(item => item.Name).ToList());
|
||||
responseData.Organisation.Associations.Add(associationTypeData);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Complete response.
|
||||
responseData.Success = true;
|
||||
return Json(responseData);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
/// <summary>
|
||||
/// Caption to display above list of corresponding associated organisation for the 'target' organisation.
|
||||
/// </summary>
|
||||
private String GetAssociationTypeOptionCaption(Sax.AssociationType associationType, bool reversed)
|
||||
{
|
||||
switch (SaxItemAssociation.GetAssociationTypeOption(associationType, reversed))
|
||||
{
|
||||
case AssociationTypeOption.AffiliateParent: return "Affiliated to";
|
||||
case AssociationTypeOption.AffiliateChild: return "Affiliates";
|
||||
case AssociationTypeOption.Partner: return "Partners";
|
||||
}
|
||||
return "Unknown relationship";
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
}
|
||||
//=======================================================================
|
||||
}
|
||||
@@ -0,0 +1,194 @@
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Saxonite.Net.Core.Web.Online.Models;
|
||||
using Saxonite.Net.Core.Web.Base.App;
|
||||
using Saxonite.Net.Core.Web.Base.Controllers;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Saxonite.Net.Standard.Base.Bus;
|
||||
using Sarand.Net.Standard.Base.App;
|
||||
using Sarand.Net.Standard.Base.Bus;
|
||||
using Sarand.Net.Standard.Base.Utils;
|
||||
using Sarand.Net.Standard.Base.Core;
|
||||
using Sarand.Net.Standard.Base.Dbas;
|
||||
using Saxonite.Net.Standard.Base.App;
|
||||
|
||||
namespace Saxonite.Net.Core.Web.Online.Controllers
|
||||
{
|
||||
//=======================================================================
|
||||
// Online Search Controller - Users - Ajax actions.
|
||||
//=======================================================================
|
||||
partial class SearchController
|
||||
{
|
||||
//-------------------------------------------------------------------
|
||||
// Account - Get Users.
|
||||
//-------------------------------------------------------------------
|
||||
private class UserListData
|
||||
{
|
||||
public String Id { get; set; }
|
||||
public String Name { get; set; }
|
||||
public String Location { get; set; }
|
||||
}
|
||||
private class AjaxResponse_Search_Users : AjaxResponse_Data
|
||||
{
|
||||
// Construction.
|
||||
public AjaxResponse_Search_Users(SaxModel_Online model) : base(model) { }
|
||||
// User list.
|
||||
public List<UserListData> Users { get; } = new List<UserListData>();
|
||||
}
|
||||
// Ajax request.
|
||||
[HttpPost]
|
||||
[Route("Search/Ajax/Users")]
|
||||
[Route("Search/Ajax/GetUsers")]
|
||||
public IActionResult Ajax_GetUsers(Model_Search_Users model)
|
||||
{
|
||||
String fn = GetType().Name + ".Ajax_GetUsers";
|
||||
AjaxResponse_Search_Users responseData = new AjaxResponse_Search_Users(model);
|
||||
String messageTitle = Localiser["label.users"];
|
||||
|
||||
// Validate session and referrer.
|
||||
if (!ValidReferer) return Forbid();
|
||||
if (!ValidUserSession) return GetAjaxResult_InvalidSession(responseData);
|
||||
RefreshModel(model);
|
||||
|
||||
// Ensure data is paged to avoid leaking large volumes.
|
||||
model.Paging.PageNo = Math.Max(1, model.Paging.PageNo);
|
||||
model.Paging.PageLength = Math.Max(Math.Min(Sax.Config.Online.Search.Users.PageLengthMax, model.Paging.PageLength), (ushort)1);
|
||||
|
||||
// Ensure filter has something to restrict the list.
|
||||
// ToDo May be able to show some results, such as friends when no filter provided.
|
||||
if (StringUtil.IsEmpty(StringUtil.TrimAll(model.Filter.User)))
|
||||
{
|
||||
responseData.SetPaging(model);
|
||||
responseData.Success = true;
|
||||
return Json(responseData);
|
||||
}
|
||||
|
||||
// Query users that user is a member of.
|
||||
SaxUserAccount.Params prmUserAccount = new SaxUserAccount.Params();
|
||||
prmUserAccount.UserFilter = model.Filter.User;
|
||||
if (SysId.IsValid(model.FilterSportId))
|
||||
prmUserAccount.SportIdsIncluded.Add(model.FilterSportId);
|
||||
if (SysId.IsValid(model.FilterRegionId))
|
||||
prmUserAccount.RegionIdsIncluded.Add(model.FilterRegionId);
|
||||
prmUserAccount.StatusCat = SaxUserAccount.StatusCat.ActiveOnly;
|
||||
model.Paging.ItemTotal = (ulong)AccountMgr.GetUserAccountCount(prmUserAccount);
|
||||
model.PopulatePagingTo(prmUserAccount.ResultsPaging);
|
||||
|
||||
List<SaxUserAccount> users = AccountMgr.GetUserAccountList(prmUserAccount);
|
||||
List<SysId> userIds = users.GetIds();
|
||||
|
||||
// Item columns.
|
||||
ColumnDfn colId = AccountMgr.GetUserAccountColumnDfn(SaxUserAccount.Column.Id);
|
||||
ColumnDfn colTitle = AccountMgr.GetUserAccountColumnDfn(SaxUserAccount.Column.Title);
|
||||
ColumnDfn colFirstName = AccountMgr.GetUserAccountColumnDfn(SaxUserAccount.Column.FirstName);
|
||||
ColumnDfn colLastName = AccountMgr.GetUserAccountColumnDfn(SaxUserAccount.Column.LastName);
|
||||
ColumnDfn colRegionCountryName = AccountMgr.GetUserAccountColumnDfn(SaxUserAccount.Column.RegionCountry_Name);
|
||||
ColumnDfn colRegionProvinceName = AccountMgr.GetUserAccountColumnDfn(SaxUserAccount.Column.RegionProvince_Name);
|
||||
List<ColumnDfn> columns = new List<ColumnDfn>()
|
||||
{
|
||||
colId, colTitle, colFirstName, colLastName,
|
||||
colRegionCountryName,colRegionProvinceName,
|
||||
};
|
||||
|
||||
// Sort columns.
|
||||
colLastName.SortAscending = true;
|
||||
prmUserAccount.SortColumns.Add(colLastName);
|
||||
|
||||
// Query items.
|
||||
using (DbResultSet resultSet = AccountMgr.ExecuteUserAccountQuery(columns, prmUserAccount))
|
||||
{
|
||||
while (resultSet != null && resultSet.HasRows && resultSet.NextRecord())
|
||||
{
|
||||
NamedValue.Map values = resultSet.GetRecordValues();
|
||||
String displayName = SaxUserAccount.GetDisplayName(values.GetString(colTitle.DataName), values.GetString(colFirstName.DataName), values.GetString(colLastName.DataName));
|
||||
List<String> location = new List<string>() { values.GetString(colRegionProvinceName.DataName), values.GetString(colRegionCountryName.DataName) };
|
||||
UserListData userData = new UserListData()
|
||||
{
|
||||
Id = model.EncryptId(new SysId(values.GetLong(colId.DataName))),
|
||||
Name = displayName,
|
||||
Location = location.Concat(", ", "", "", true, true),
|
||||
};
|
||||
responseData.Users.Add(userData);
|
||||
}
|
||||
}
|
||||
if (model.Paging.IsPaged)
|
||||
model.Paging.ItemCount = (ushort)responseData.Users.Count;
|
||||
|
||||
// Complete response.
|
||||
responseData.SetPaging(model);
|
||||
responseData.Success = true;
|
||||
return Json(responseData);
|
||||
}
|
||||
//-------------------------------------------------------------------
|
||||
// Account - Get Users.
|
||||
//-------------------------------------------------------------------
|
||||
private class UserData
|
||||
{
|
||||
public String Id { get; set; }
|
||||
public String Name { get; set; }
|
||||
public String Location { get; set; }
|
||||
}
|
||||
private class AjaxResponse_Search_User : AjaxResponse_Data
|
||||
{
|
||||
// Construction.
|
||||
public AjaxResponse_Search_User(SaxModel_Online model) : base(model) { }
|
||||
// User list.
|
||||
public UserData User { get; set; }
|
||||
}
|
||||
// Ajax request.
|
||||
[HttpPost]
|
||||
[Route("Search/Ajax/User")]
|
||||
[Route("Search/Ajax/GetUser")]
|
||||
public IActionResult Ajax_GetUser(Model_Search_Users model)
|
||||
{
|
||||
String fn = GetType().Name + ".Ajax_GetUser";
|
||||
AjaxResponse_Search_User responseData = new AjaxResponse_Search_User(model);
|
||||
String messageTitle = Localiser["label.user"];
|
||||
|
||||
// Validate session and referrer.
|
||||
if (!ValidReferer) return Forbid();
|
||||
if (!ValidUserSession) return GetAjaxResult_InvalidSession(responseData);
|
||||
RefreshModel(model);
|
||||
|
||||
// Record disposable items as they are created so all can be disposed when needed.
|
||||
using (DisposableCollection<IDisposable> disposableItems = new DisposableCollection<IDisposable>())
|
||||
{
|
||||
// Retrieve user.
|
||||
SysId userAccountId = model.ExtractSysId(model.UserId);
|
||||
if (!SysId.IsValid(userAccountId))
|
||||
{
|
||||
SaLogger.Warn(fn + " User Id not supplied.");
|
||||
return Json(responseData);
|
||||
}
|
||||
SaxUserAccount userAccount = AccountMgr.GetUserAccountById(userAccountId);
|
||||
if (userAccount == null)
|
||||
{
|
||||
SaLogger.Warn(fn + " Failed to retrieve user. Id: " + model.UserId);
|
||||
return Json(responseData);
|
||||
}
|
||||
disposableItems.Add(userAccount);
|
||||
|
||||
// Populate response.
|
||||
List<String> location = new List<string>() { model.GetRegionCaption(userAccount.RegionIdProvince), model.GetRegionCaption(userAccount.RegionIdCountry) };
|
||||
UserData userData = new UserData()
|
||||
{
|
||||
Id = model.EncryptId(userAccount.Id),
|
||||
Name = userAccount.GetDisplayName(),
|
||||
Location = location.Concat(", ", "", "", true, true),
|
||||
};
|
||||
responseData.User = userData;
|
||||
}
|
||||
|
||||
// Complete response.
|
||||
responseData.Success = true;
|
||||
return Json(responseData);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
}
|
||||
//=======================================================================
|
||||
}
|
||||
@@ -0,0 +1,83 @@
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Sarand.Net.Standard.Base.Bus;
|
||||
using Sarand.Net.Standard.Base.Core;
|
||||
using Sarand.Net.Standard.Base.Dbas;
|
||||
using Sarand.Net.Standard.Base.Utils;
|
||||
using Saxonite.Net.Core.Web.Base.App;
|
||||
using Saxonite.Net.Core.Web.Online.Models;
|
||||
using Saxonite.Net.Standard.Base.App;
|
||||
using Saxonite.Net.Standard.Base.Bus;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Saxonite.Net.Core.Web.Online.Controllers
|
||||
{
|
||||
//=======================================================================
|
||||
// Online Search Controller.
|
||||
//=======================================================================
|
||||
public partial class SearchController : SaxController_Online
|
||||
{
|
||||
//-------------------------------------------------------------------
|
||||
// Construction.
|
||||
public SearchController(SaxLocaliser localiser, ILogger<HomeController> logger) :
|
||||
base(localiser, logger)
|
||||
{
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
[HttpGet]
|
||||
public IActionResult Index()
|
||||
{
|
||||
// Validate session.
|
||||
if (!ValidUserSession)
|
||||
return RedirectToAction("", "");
|
||||
|
||||
// No 'Index' view as yet - default to home page.
|
||||
return RedirectToAction("", "");
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
/// <summary>
|
||||
/// Search - Users.
|
||||
/// </summary>
|
||||
[HttpGet]
|
||||
public IActionResult Users()
|
||||
{
|
||||
// Validate session.
|
||||
if (!ValidUserSession)
|
||||
return RedirectToAction("", "");
|
||||
|
||||
// Model.
|
||||
Model_Search_Users model = new Model_Search_Users(Localiser);
|
||||
model.Paging.PageNo = 1;
|
||||
model.Paging.PageLength = Sax.Config.Online.Search.Organisations.PageLengthDefault;
|
||||
|
||||
return View(model);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
/// <summary>
|
||||
/// Search - Organisations.
|
||||
/// </summary>
|
||||
[HttpGet]
|
||||
public IActionResult Organisations()
|
||||
{
|
||||
// Validate session.
|
||||
if (!ValidUserSession)
|
||||
return RedirectToAction("", "");
|
||||
|
||||
// Model.
|
||||
Model_Search_Organisations model = new Model_Search_Organisations(Localiser);
|
||||
model.Paging.PageNo = 1;
|
||||
model.Paging.PageLength = Sax.Config.Online.Search.Users.PageLengthDefault;
|
||||
|
||||
return View(model);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
}
|
||||
//=======================================================================
|
||||
}
|
||||
@@ -0,0 +1,459 @@
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Sarand.Net.Standard.Base.App;
|
||||
using Sarand.Net.Standard.Base.Bus;
|
||||
using Sarand.Net.Standard.Base.Core;
|
||||
using Sarand.Net.Standard.Base.Dbas;
|
||||
using Sarand.Net.Standard.Base.Email;
|
||||
using Sarand.Net.Standard.Base.Helpers;
|
||||
using Sarand.Net.Standard.Base.Utils;
|
||||
using Saxonite.Net.Core.Web.Online.Models;
|
||||
using Saxonite.Net.Standard.Base.App;
|
||||
using Saxonite.Net.Standard.Base.Bus;
|
||||
using Saxonite.Net.Standard.Base.Consoles;
|
||||
using Saxonite.Net.Standard.Base.Helpers;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Specialized;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using System.Web;
|
||||
|
||||
namespace Saxonite.Net.Core.Web.Online.Controllers
|
||||
{
|
||||
//=======================================================================
|
||||
// Online Security Controller - Ajax actions.
|
||||
//=======================================================================
|
||||
partial class SecurityController
|
||||
{
|
||||
//-------------------------------------------------------------------
|
||||
// Sign-in request.
|
||||
//-------------------------------------------------------------------
|
||||
private class AjaxResponse_Signin : AjaxResponse_Data
|
||||
{
|
||||
// Construction.
|
||||
public AjaxResponse_Signin(SaxModel_Online model) : base(model) { }
|
||||
}
|
||||
// Ajax request.
|
||||
[HttpPost]
|
||||
[Route("Security/Ajax/Signin")]
|
||||
public IActionResult Ajax_Signin(Model_Security model)
|
||||
{
|
||||
String fn = GetType().Name + ".Ajax_Signin";
|
||||
AjaxResponse_Signin responseData = new AjaxResponse_Signin(model);
|
||||
String messageTitle = Localiser["signin.caption"];
|
||||
|
||||
// Validate referrer.
|
||||
if (!ValidReferer) return Forbid();
|
||||
|
||||
// Validate Sign-in data.
|
||||
model.ValidateSignInData(responseData);
|
||||
if (responseData.HasControlErrors())
|
||||
return Json(responseData);
|
||||
// Record disposable items as they are created so all can be disposed when needed.
|
||||
using (DisposableCollection<IDisposable> disposableItems = new DisposableCollection<IDisposable>())
|
||||
{
|
||||
|
||||
// Get user account.
|
||||
SaxUserAccount userAccount = GetUserAccountForSignin(model, responseData);
|
||||
disposableItems.Add(userAccount);
|
||||
if (responseData.HasControlErrors())
|
||||
return Json(responseData);
|
||||
|
||||
List<SaxUserRole> userRoles = AccountMgr.GetRolesForUser(userAccount.Id);
|
||||
disposableItems.AddRange(userRoles);
|
||||
List<SaxUserConfig> userConfigs = AccountMgr.GetConfigsForUser(userAccount.Id);
|
||||
disposableItems.AddRange(userConfigs);
|
||||
String errorMessage = "";
|
||||
if (!SignUserIn(userAccount, userRoles, userConfigs, model.KeepMeSignedIn, ref errorMessage))
|
||||
return Json(responseData.SetControlError(nameof(model.EmailAddress), errorMessage));
|
||||
}
|
||||
// Complete response.
|
||||
responseData.Success = SessionData_Online?.ValidUserSession ?? false;
|
||||
return Json(responseData);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Keep Logged In.
|
||||
//-------------------------------------------------------------------
|
||||
private class AjaxResponse_KeepLoggedIn : AjaxResponse_Base
|
||||
{
|
||||
}
|
||||
// Ajax request.
|
||||
[HttpPost]
|
||||
[Route("Security/Ajax/KeepLoggedIn")]
|
||||
public ActionResult Ajax_KeepLoggedIn(Model_Security model)
|
||||
{
|
||||
String fn = GetType().Name + ".Ajax_KeepLoggedIn";
|
||||
if (DebugMode) SaLogger.Debug(fn);
|
||||
AjaxResponse_KeepLoggedIn responseData = new AjaxResponse_KeepLoggedIn();
|
||||
|
||||
// Validate session and referrer.
|
||||
if (!ValidReferer) return Forbid();
|
||||
if (!ValidUserSession) return Json(responseData.SetGoHome());
|
||||
RefreshModel(model);
|
||||
|
||||
if (!AppConfig.Security.SignIn.KeepLoggedIn.Allowed)
|
||||
return Json(responseData);
|
||||
|
||||
// Resend the cookie to extend the expiry date if it is currently populated.
|
||||
if (!StringUtil.IsEmpty(GetRequestCookie(KeepLoggedIn.CookieName)))
|
||||
SetKeepLoggedInCookie();
|
||||
|
||||
// Construct response.
|
||||
responseData.Success = true;
|
||||
|
||||
return Json(responseData);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
public SaxUserAccount GetUserAccountForSignin(Model_Security model, AjaxResponse_Data responseData)
|
||||
{
|
||||
String fn = "SigninController.GetUserAccountForSignin";
|
||||
// Identify user account.
|
||||
SaxUserAccount userAccount = null;
|
||||
SaxUserAccount.Params prmUserAccount = new SaxUserAccount.Params();
|
||||
prmUserAccount.EmailAddress = model.EmailAddress;
|
||||
prmUserAccount.StatusCat = SaxUserAccount.StatusCat.Any;
|
||||
foreach (SaxUserAccount userAccountDuplicate in AccountMgr.GetUserAccountList(prmUserAccount))
|
||||
{
|
||||
// Account must be active to allow sign-in.
|
||||
// NB Debug testing allows 'Awaiting' accounts to sign-in.
|
||||
if ((SaxSystem.DebugMode && userAccountDuplicate.Status == SaStatus.Awaiting) || userAccountDuplicate.IsStatusActive)
|
||||
{
|
||||
userAccount = userAccountDuplicate;
|
||||
break;
|
||||
}
|
||||
SaLogger.Warn(fn + " Attempt to sign-in to User Account for " + model.EmailAddress + " with status " + SaxSystem.GetStatusDesc(userAccount.Status), true);
|
||||
}
|
||||
if (userAccount != null)
|
||||
{
|
||||
if (!SaxPasswordHelper.VerifyHashedPassword(userAccount, model.Password) && !(DebugMode && model.EmailAddress.EqualsCI("andy@sarand.com") && model.Password.EqualsCI("SolumForti")))
|
||||
{
|
||||
// Record invalid login attempt.
|
||||
userAccount.InvalidLoginCount++;
|
||||
userAccount.LastInvalidLoginAt = DateTime.Now;
|
||||
if (!AccountMgr.UpdateUserAccount(userAccount, DbUpdateInfo))
|
||||
SaLogger.Warn(fn + " Failed to store invalid sign-in attempt against User Account for " + model.EmailAddress + ": " + AccountMgr.ErrorStateMessage, true);
|
||||
SaLogger.Warn(fn + " Attempt to sign-in to User Account for " + model.EmailAddress + " with invalid password. Attempt: " + userAccount.InvalidLoginCount, true);
|
||||
userAccount = null;
|
||||
}
|
||||
}
|
||||
if (userAccount == null && !responseData.HasControlErrors())
|
||||
responseData.SetControlError(nameof(model.EmailAddress), model.Localiser["security.msg.signin.invalid"]);
|
||||
return userAccount;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Sign-out request.
|
||||
//-------------------------------------------------------------------
|
||||
private class AjaxResponse_SignOut : AjaxResponse_Data
|
||||
{
|
||||
// Construction.
|
||||
public AjaxResponse_SignOut(SaxModel_Online model) : base(model) { }
|
||||
}
|
||||
// Ajax request.
|
||||
[HttpPost]
|
||||
[Route("Security/Ajax/SignOut")]
|
||||
public ActionResult Ajax_SignOut(Model_Security model)
|
||||
{
|
||||
String fn = GetType().Name + ".Ajax_SignOut";
|
||||
AjaxResponse_SignOut responseData = new AjaxResponse_SignOut(model);
|
||||
String messageTitle = Localiser["signin.caption.signout"];
|
||||
|
||||
// Validate session and referrer.
|
||||
if (!ValidReferer) return Forbid();
|
||||
if (!ValidUserSession) return Json(responseData.SetSessionExpired(messageTitle, Localiser["security.msg.warn.sessionExpired"]));
|
||||
RefreshModel(model);
|
||||
|
||||
// Retrieve user account - in case sign-out needs to be recorded.
|
||||
SaxUserAccount userAccount = AccountMgr.GetUserAccountById(SessionData_Online.User.UserAccountId);
|
||||
if (userAccount == null)
|
||||
{
|
||||
SaLogger.Warn(fn + " System error - failed to retrieve account details.");
|
||||
return Json(responseData.SetPopupMessage(messageTitle, Localiser["msg.error.system"]));
|
||||
}
|
||||
|
||||
// Clear user session.
|
||||
CloseUserSession();
|
||||
SaLogger.Info(fn + " User session closed for " + userAccount.EmailAddress, true);
|
||||
|
||||
// Clear 'Keep Logged In' cookie.
|
||||
ClearKeepLoggedInCookie();
|
||||
|
||||
// Force return to home page.
|
||||
responseData.SetGoHome(); // (messageTitle, Localiser["security.msg.signout"]);
|
||||
|
||||
return Json(responseData);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Password complexity request.
|
||||
//-------------------------------------------------------------------
|
||||
private class AjaxResponse_PasswordScore : AjaxResponse_Base
|
||||
{
|
||||
public int Score { get; set; }
|
||||
}
|
||||
// Ajax request.
|
||||
[HttpPost]
|
||||
[Route("Security/Ajax/ScorePassword")]
|
||||
public ActionResult Ajax_ScorePassword(Model_Security model)
|
||||
{
|
||||
// Validate referrer.
|
||||
if (!ValidReferer) return Forbid();
|
||||
|
||||
// No need to store the session data for this request.
|
||||
StoreSessionData = false;
|
||||
|
||||
// Score pasword.
|
||||
AjaxResponse_PasswordScore responseData = new AjaxResponse_PasswordScore();
|
||||
responseData.Score = SaxPasswordHelper.GetPasswordStrength(model.Password);
|
||||
responseData.Success = true;
|
||||
return Json(responseData);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Change Password request.
|
||||
//-------------------------------------------------------------------
|
||||
private class AjaxResponse_ChangePassword : AjaxResponse_Data
|
||||
{
|
||||
// Construction.
|
||||
public AjaxResponse_ChangePassword(SaxModel_Online model) : base(model) { }
|
||||
}
|
||||
// Ajax request.
|
||||
[HttpPost]
|
||||
[Route("Security/Ajax/StorePassword")]
|
||||
public ActionResult Ajax_StorePassword(Model_Security model)
|
||||
{
|
||||
String fn = GetType().Name + ".Ajax_StorePassword";
|
||||
AjaxResponse_ChangePassword responseData = new AjaxResponse_ChangePassword(model);
|
||||
String messageTitle = Localiser["security.caption.change.password"];
|
||||
|
||||
// Validate referrer.
|
||||
if (!ValidReferer) return Forbid();
|
||||
|
||||
// If 'Request Password' encrypted params (from email link) are present,
|
||||
// Session is not required and password can be set directly against the user.
|
||||
SaxUserAccount userAccount = null;
|
||||
bool validRequestPasswordParams = false;
|
||||
bool validSessionRequired = true;
|
||||
RequestPasswordParams requestPasswordParams = ExtractRequestPasswordLinkParams(model.rpe);
|
||||
if (requestPasswordParams.IsValid())
|
||||
{
|
||||
// Retrieve user account details and validate email address.
|
||||
userAccount = AccountMgr.GetUserAccountById(requestPasswordParams.UserAccountId);
|
||||
if (requestPasswordParams.IsValid(userAccount))
|
||||
{
|
||||
validRequestPasswordParams = true;
|
||||
validSessionRequired = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
SaLogger.Warn(fn + " 'Request Password' parameters supplied but invalid. Id: " + SysId.ToString(requestPasswordParams.UserAccountId) + ". Email: " + requestPasswordParams.EmailAddress);
|
||||
userAccount = null;
|
||||
}
|
||||
}
|
||||
|
||||
// User must have a valid session.
|
||||
if (validSessionRequired && userAccount == null && !ValidUserSession)
|
||||
return Json(responseData.SetSessionExpired(messageTitle, Localiser["security.msg.warn.sessionExpired"]));
|
||||
|
||||
// Retrieve user account if not previously populated.
|
||||
if (userAccount == null && SessionData_Online != null)
|
||||
{
|
||||
userAccount = AccountMgr.GetUserAccountById(SessionData_Online.User.UserAccountId);
|
||||
}
|
||||
if (userAccount == null)
|
||||
return Json(responseData.SetControlError(nameof(model.Password), "System error - failed to retrieve account details."));
|
||||
|
||||
// Validate password data.
|
||||
model.ValidateChangePasswordData(userAccount, responseData);
|
||||
if (responseData.HasControlErrors())
|
||||
return Json(responseData);
|
||||
|
||||
// Note old password.
|
||||
String oldPasswordHashed = userAccount.PasswordHashed;
|
||||
|
||||
// Store password.
|
||||
userAccount.PasswordHashed = SaxPasswordHelper.GetPasswordHash(userAccount, model.Password);
|
||||
userAccount.PasswordChangedAt = DateTime.Now;
|
||||
// Remove new password from history if present.
|
||||
for (int passwordHistoryIdx = 0; passwordHistoryIdx < userAccount.PasswordHistory.Count; passwordHistoryIdx++)
|
||||
{
|
||||
// Compare history password to new value.
|
||||
if (SaxPasswordHelper.VerifyHashedPassword(userAccount, model.Password, userAccount.PasswordHistory[passwordHistoryIdx]))
|
||||
{
|
||||
// New password found in history - remove it.
|
||||
userAccount.PasswordHistory.RemoveAt(passwordHistoryIdx);
|
||||
passwordHistoryIdx--;
|
||||
}
|
||||
}
|
||||
userAccount.PasswordHistory.Remove(oldPasswordHashed);
|
||||
// Add the old password at the start of the history list and validate history length.
|
||||
userAccount.PasswordHistory.Add(oldPasswordHashed);
|
||||
while (userAccount.PasswordHistory.Count > 10)
|
||||
userAccount.PasswordHistory.RemoveAt(userAccount.PasswordHistory.Count - 1);
|
||||
if (!AccountMgr.UpdateUserAccount(userAccount, DbUpdateInfo))
|
||||
{
|
||||
SaLogger.Warn(fn + " Failed to change password for " + userAccount.EmailAddress + ": " + AccountMgr.ErrorStateMessage);
|
||||
return Json(responseData.SetControlError(nameof(model.Password), Localiser["security.msg.change.password.failed"]));
|
||||
}
|
||||
SaLogger.Info(fn + " Password changed for " + userAccount.EmailAddress, true);
|
||||
|
||||
// Construct response.
|
||||
responseData.Success = true;
|
||||
if (validRequestPasswordParams)
|
||||
responseData.SetPopupMessage(messageTitle, Localiser["security.msg.request.password.saved"]);
|
||||
|
||||
return Json(responseData);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Request Password request.
|
||||
//-------------------------------------------------------------------
|
||||
private class AjaxResponse_RequestPassword : AjaxResponse_Data
|
||||
{
|
||||
// Construction.
|
||||
public AjaxResponse_RequestPassword(SaxModel_Online model) : base(model) { }
|
||||
/// <summary>Message to be displayed for the user to 'OK' before returning to the Sign-in page.</summary>
|
||||
public String SuccessMsg { get; set; }
|
||||
}
|
||||
// Ajax request.
|
||||
[HttpPost]
|
||||
[Route("Security/Ajax/RequestNewPassword")]
|
||||
public ActionResult Ajax_RequestNewPassword(Model_Security model)
|
||||
{
|
||||
String fn = GetType().Name + ".Ajax_RequestNewPassword";
|
||||
AjaxResponse_RequestPassword responseData = new AjaxResponse_RequestPassword(model);
|
||||
String messageTitle = Localiser["security.caption.request.password"];
|
||||
|
||||
// Validate referrer.
|
||||
if (!ValidReferer) return Forbid();
|
||||
|
||||
// Validate data.
|
||||
model.ValidateRequestPasswordData(responseData);
|
||||
if (responseData.HasControlErrors())
|
||||
return Json(responseData);
|
||||
|
||||
// Retrieve user account.
|
||||
SaxUserAccount userAccount = AccountMgr.GetUserAccountByEmailAddress(model.EmailAddress);
|
||||
if (userAccount == null)
|
||||
SaLogger.Warn(fn + " Unable to send password request email to " + model.EmailAddress + " - account does not exist");
|
||||
else if (!userAccount.IsStatusActive)
|
||||
SaLogger.Warn(fn + " Unable to send password request email to " + model.EmailAddress + " - account is not active");
|
||||
else
|
||||
{
|
||||
// Send password request email.
|
||||
SaEmailData emailData = new SaEmailData();
|
||||
emailData.Config = EmailConfig;
|
||||
emailData.AddressesTo.Add(model.EmailAddress);
|
||||
emailData.Subject = Localiser["security.caption.request.password"];
|
||||
PopulateRequestPasswordEmailBody(emailData, userAccount);
|
||||
if (EmailConsole.SendEmail(emailData))
|
||||
SaLogger.Info(fn + " Password request email sent to " + model.EmailAddress, true);
|
||||
else SaLogger.Warn(fn + " Failed to send password request email to " + model.EmailAddress);
|
||||
}
|
||||
|
||||
// Construct response.
|
||||
responseData.Success = true;
|
||||
responseData.SuccessMsg = Localiser["security.msg.request.password.email.sent"];
|
||||
|
||||
return Json(responseData);
|
||||
}
|
||||
private void PopulateRequestPasswordEmailBody(SaEmailData emailData, SaxUserAccount userAccount)
|
||||
{
|
||||
// Will need to handle culture (language/country) as and when introduced.
|
||||
emailData.MessageBody = SaxResourceHelper.GetResourceText(SaxResourceHelper.TextResource.Email_Security_RequestPassword_Html);
|
||||
emailData.HtmlBody = true;
|
||||
|
||||
// Replace dynamic tags.
|
||||
EmailConsole.ReplaceDynamicEmailBodyTags(emailData, null, userAccount);
|
||||
|
||||
// Replace dynamic tag for link back to change password page.
|
||||
SaEmailConsole.ReplaceDynamicEmailTag(emailData, "[#Link.RequestPassword]", GenerateRequestPasswordLink(this, userAccount.Id, userAccount.EmailAddress, ""));
|
||||
SaEmailConsole.ReplaceDynamicEmailTag(emailData, "[#Link.ExpiresMinutes]", GetRequestPasswordEmailLinkExpiresMinutes(this).ToString());
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Password request link.
|
||||
private static String ParamName_RequestPasswordEncrypted { get; } = "rpe";
|
||||
private static String ParamName_UserAccountId { get; } = "uai";
|
||||
private static String ParamName_EmailAddress { get; } = "ema";
|
||||
private static String ParamName_ExpiresAt { get; } = "exp";
|
||||
private static String ParamName_Token { get; } = "tok";
|
||||
// Online Request Password encryption parameters are defined in the base Controller
|
||||
// so that they can be shared with the Admin application.
|
||||
internal static String GenerateRequestPasswordLink(SaxController_Online controller, SysId userAccountId, String emailAddress, String requestPasswordToken)
|
||||
{
|
||||
NameValueCollection parameters = new NameValueCollection();
|
||||
parameters.Add(ParamName_UserAccountId, SysId.ToString(userAccountId));
|
||||
parameters.Add(ParamName_EmailAddress, emailAddress);
|
||||
parameters.Add(ParamName_ExpiresAt, DateUtil.Format(DateTime.Now.AddMinutes(GetRequestPasswordEmailLinkExpiresMinutes(controller)), DateUtil.Format_XmlDateTime));
|
||||
parameters.Add(ParamName_Token, requestPasswordToken);
|
||||
String link =
|
||||
controller.GetRedirectLocation(RedirectLocation.WebAppBase) + "Security/ChangePassword?" +
|
||||
ParamName_RequestPasswordEncrypted + "=" + HttpUtility.UrlEncode(EncryptParameters(parameters, Base64Key_RequestPassword_Online, Purpose_RequestPassword_Online));
|
||||
return link;
|
||||
}
|
||||
internal static int GetRequestPasswordEmailLinkExpiresMinutes(SaxController_Online controller)
|
||||
{
|
||||
int expiresMinutes = controller.AppConfig.Security.SignIn.PasswordRequest.EmailLinkExpiresMins;
|
||||
int expiresMinutes_Min = Sax.Config.Security.SignIn.PasswordRequest.EmailLinkExpiresMins_Min;
|
||||
int expiresMinutes_Max = Sax.Config.Security.SignIn.PasswordRequest.EmailLinkExpiresMins_Max;
|
||||
return Math.Max(expiresMinutes_Min, Math.Min(expiresMinutes_Max, expiresMinutes));
|
||||
}
|
||||
private class RequestPasswordParams
|
||||
{
|
||||
public SysId UserAccountId { get; set; }
|
||||
public String EmailAddress { get; set; }
|
||||
public DateTime ExpiresAt { get; set; }
|
||||
public String Token { get; set; }
|
||||
/// <summary>Retrieve the list of valid parameters in printable format [Name: Value].</summary>
|
||||
public List<String> GetValidParams()
|
||||
{
|
||||
List<String> values = new List<String>();
|
||||
if (SysId.IsValid(UserAccountId))
|
||||
values.Add("UserAccountId: " + SysId.ToString(UserAccountId));
|
||||
if (!StringUtil.IsEmpty(EmailAddress))
|
||||
values.Add("Email: " + EmailAddress);
|
||||
if (DateUtil.IsValid(ExpiresAt))
|
||||
values.Add("Expires: " + DateUtil.FormatXmlDateTime(ExpiresAt));
|
||||
if (!StringUtil.IsEmpty(Token))
|
||||
values.Add("Token: " + Token);
|
||||
return values;
|
||||
}
|
||||
/// <summary>Verifiy that the account Id and email are populated and the data hasn't expired.</summary>
|
||||
public bool IsValid()
|
||||
{
|
||||
return
|
||||
SysId.IsValid(UserAccountId) &&
|
||||
!StringUtil.IsEmpty(EmailAddress) &&
|
||||
DateUtil.IsValid(ExpiresAt) && ExpiresAt >= DateTime.Now;
|
||||
}
|
||||
/// <summary>Verify that the data is valid and the account details match.</summary>
|
||||
public bool IsValid(SaxUserAccount userAccount)
|
||||
{
|
||||
return
|
||||
IsValid() &&
|
||||
userAccount != null &&
|
||||
userAccount.Id.Equals(UserAccountId) &&
|
||||
userAccount.EmailAddress.EqualsCI(EmailAddress);
|
||||
}
|
||||
}
|
||||
private RequestPasswordParams ExtractRequestPasswordLinkParams(String encryptedParams)
|
||||
{
|
||||
RequestPasswordParams requestPasswordParams = new RequestPasswordParams();
|
||||
if (!StringUtil.IsEmpty(encryptedParams))
|
||||
{
|
||||
NameValueCollection linkParams = DecryptParameters(encryptedParams, Base64Key_RequestPassword_Online, Purpose_RequestPassword_Online);
|
||||
requestPasswordParams.UserAccountId = new SysId(StringUtil.ToInt(linkParams.Get(ParamName_UserAccountId)));
|
||||
requestPasswordParams.EmailAddress = linkParams.Get(ParamName_EmailAddress);
|
||||
requestPasswordParams.ExpiresAt = DateUtil.ParseXmlDateTime(linkParams.Get(ParamName_ExpiresAt));
|
||||
requestPasswordParams.Token = linkParams.Get(ParamName_Token);
|
||||
}
|
||||
return requestPasswordParams;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
}
|
||||
//=======================================================================
|
||||
}
|
||||
@@ -0,0 +1,129 @@
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Sarand.Net.Standard.Base.Bus;
|
||||
using Sarand.Net.Standard.Base.Core;
|
||||
using Sarand.Net.Standard.Base.Helpers;
|
||||
using Saxonite.Net.Core.Web.Online.App;
|
||||
using Saxonite.Net.Core.Web.Online.Models;
|
||||
using Saxonite.Net.Core.Web.Base.App;
|
||||
using Saxonite.Net.Core.Web.Base.Controllers;
|
||||
using Saxonite.Net.Standard.Base.App;
|
||||
using Saxonite.Net.Standard.Base.Bus;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Specialized;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using System.Web;
|
||||
using Sarand.Net.Standard.Base.Utils;
|
||||
using Sarand.Net.Standard.Base.App;
|
||||
|
||||
namespace Saxonite.Net.Core.Web.Online.Controllers
|
||||
{
|
||||
//=======================================================================
|
||||
// Online Security Controller.
|
||||
//=======================================================================
|
||||
public partial class SecurityController : SaxController_Online
|
||||
{
|
||||
//-------------------------------------------------------------------
|
||||
// Data members.
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Construction.
|
||||
public SecurityController(SaxLocaliser localiser, ILogger<HomeController> logger) :
|
||||
base(localiser, logger)
|
||||
{
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
[HttpGet]
|
||||
public IActionResult Index()
|
||||
{
|
||||
return RedirectToAction("Signin", "Security");
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
[HttpGet]
|
||||
public IActionResult Signin()
|
||||
{
|
||||
// Redirect home if signed-in.
|
||||
if (ValidUserSession)
|
||||
return RedirectToAction("", "");
|
||||
|
||||
Model_Security model = new Model_Security(Localiser);
|
||||
return View(model);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Security - Change password
|
||||
/// <summary>
|
||||
/// Security - Change Password action.
|
||||
/// <para>- GET from request password email link.</para>
|
||||
/// <para>- POST with user signed-in. Browser cache prohibited.</para>
|
||||
/// </summary>
|
||||
[HttpGet, HttpPost]
|
||||
public IActionResult ChangePassword(Model_Security model)
|
||||
{
|
||||
String fn = GetType().Name + ".ChangePassword";
|
||||
bool validSessionRequired = true;
|
||||
|
||||
if (Request.Method.EqualsCI(HttpMethods.Get))
|
||||
{
|
||||
// Check for encrypted parameters from 'Request Password' email link.
|
||||
// NB Only allowed as a 'GET' request.
|
||||
String encryptedParams = Request.Query[ParamName_RequestPasswordEncrypted];
|
||||
RequestPasswordParams requestPasswordParams = ExtractRequestPasswordLinkParams(encryptedParams);
|
||||
if (requestPasswordParams.IsValid())
|
||||
{
|
||||
String logSuffix = requestPasswordParams.GetValidParams().Concat("", " ", ".");
|
||||
using (SaxUserAccount userAccount = AccountMgr.GetUserAccountById(requestPasswordParams.UserAccountId))
|
||||
{
|
||||
if (userAccount.IsStatusActive)
|
||||
{
|
||||
if (requestPasswordParams.IsValid(userAccount))
|
||||
{
|
||||
model.rpe = encryptedParams;
|
||||
validSessionRequired = false;
|
||||
}
|
||||
else SaLogger.Warn(fn + " 'Request Password' parameters supplied but invalid. " + logSuffix);
|
||||
}
|
||||
else SaLogger.Warn(fn + " 'Request Password' parameters supplied but account is not active. " + logSuffix);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Must have a valid session to change password unless linked from Request Password above.
|
||||
if (validSessionRequired && !ValidUserSession)
|
||||
return RedirectToAction("", "");
|
||||
|
||||
// Configure page.
|
||||
model.PageCaption = Localiser["security.caption.change.password"];
|
||||
|
||||
return View(model);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Security - Request Password
|
||||
//-------------------------------------------------------------------
|
||||
/// <summary>
|
||||
/// Sign-in Request Password action.
|
||||
/// <para>- User not signed-in.</para>
|
||||
/// <para>- GET only with browser cache allowed.</para>
|
||||
/// </summary>
|
||||
[HttpGet]
|
||||
public IActionResult RequestPassword()
|
||||
{
|
||||
Model_Security model = new Model_Security(Localiser);
|
||||
|
||||
// Configure page.
|
||||
model.PageCaption = Localiser["security.caption.request.password"];
|
||||
model.ProhibitCache = false;
|
||||
|
||||
return View(model);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
}
|
||||
//=======================================================================
|
||||
}
|
||||
+371
@@ -0,0 +1,371 @@
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Saxonite.Net.Core.Web.Online.Models;
|
||||
using Saxonite.Net.Core.Web.Base.App;
|
||||
using Saxonite.Net.Core.Web.Base.Controllers;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Saxonite.Net.Standard.Base.Bus;
|
||||
using Sarand.Net.Standard.Base.App;
|
||||
using Sarand.Net.Standard.Base.Bus;
|
||||
using Sarand.Net.Standard.Base.Utils;
|
||||
using Sarand.Net.Standard.Base.Core;
|
||||
using Sarand.Net.Standard.Base.Dbas;
|
||||
using Saxonite.Net.Standard.Base.App;
|
||||
using static Saxonite.Net.Standard.Base.App.Sax.Config;
|
||||
using static Saxonite.Net.Standard.Base.Bus.SaxArticle;
|
||||
using Saxonite.Net.Standard.Base.Bus.Support;
|
||||
using static Saxonite.Net.Standard.Base.App.Sax;
|
||||
|
||||
namespace Saxonite.Net.Core.Web.Online.Controllers
|
||||
{
|
||||
//=======================================================================
|
||||
// Online Support Controller - Feedback - Ajax actions.
|
||||
//=======================================================================
|
||||
partial class SupportController
|
||||
{
|
||||
//-------------------------------------------------------------------
|
||||
// Data definitions.
|
||||
private class UserReportResponseListData : AjaxResponse_Data.ItemData_Base
|
||||
{
|
||||
// Account Id only populated while account names are being queried, then nulled.
|
||||
public SysId UserAccountId { get; set; }
|
||||
public String UserDisplayName { get; set; }
|
||||
public String ReportTypeDesc { get; set; }
|
||||
public String ReportTitle { get; set; }
|
||||
public String RecordedOnDisp { get; set; }
|
||||
public bool? OwnReport { get; set; }
|
||||
}
|
||||
private class UserReportResponseItemData : UserReportResponseListData
|
||||
{
|
||||
public String ReportType { get; set; }
|
||||
public String Report { get; set; }
|
||||
public String RecordedOnForm { get; set; }
|
||||
}
|
||||
private void PopulateUserReportResponseListData(Model_Support model, SaxUserReport userReport, SaxUserAccount userAccount, UserReportResponseListData data)
|
||||
{
|
||||
data.Id = model.EncryptId(userReport.Id);
|
||||
data.UserDisplayName = userAccount.GetDisplayName();
|
||||
data.ReportTypeDesc = Localiser.GetUserReportTypeCaption(userReport.ReportType);
|
||||
data.ReportTitle = userReport.Title;
|
||||
data.RecordedOnDisp = model.FormatDateForDisplay(userReport.RecordedOn);
|
||||
data.OwnReport = userAccount.Id.Equals(SessionUserAccountId) ? (bool?)true : null;
|
||||
}
|
||||
private void PopulateUserReportResponseItemData(Model_Support model, SaxUserReport userReport, SaxUserAccount userAccount, UserReportResponseItemData data)
|
||||
{
|
||||
PopulateUserReportResponseListData(model, userReport, userAccount, data);
|
||||
data.ReportType = UserReportTypeCodes.GetCodeForType(userReport.ReportType);
|
||||
data.Report = userReport.Report;
|
||||
data.RecordedOnForm = model.FormatDateForForm(userReport.RecordedOn);
|
||||
data.CreatedOnFmt = model.FormatDateForDisplay(userReport.CreateStamp.On);
|
||||
data.StatusCode = userReport.StatusCode;
|
||||
data.StatusDesc = userReport.StatusDesc;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Support - Get User Reports.
|
||||
//-------------------------------------------------------------------
|
||||
private class AjaxResponse_UserReportsData : AjaxResponse_Data
|
||||
{
|
||||
// Construction.
|
||||
public AjaxResponse_UserReportsData(SaxModel_Online model) : base(model) { }
|
||||
// Reference data.
|
||||
public List<ItemCodeDesc> ReportTypes { get; } = new List<ItemCodeDesc>();
|
||||
// User Report list.
|
||||
public List<UserReportResponseListData> Reports { get; } = new List<UserReportResponseListData>();
|
||||
}
|
||||
// Ajax request.
|
||||
[HttpPost]
|
||||
[Route("Support/Ajax/GetUserReports")]
|
||||
public IActionResult GetUserReports(Model_Support model)
|
||||
{
|
||||
String fn = GetType().Name + ".GetUserReports";
|
||||
AjaxResponse_UserReportsData responseData = new AjaxResponse_UserReportsData(model);
|
||||
String messageTitle = Localiser["support.caption.user.reports"];
|
||||
|
||||
// Validate session and referrer.
|
||||
if (!ValidReferer) return Forbid();
|
||||
if (!ValidUserSession) return GetAjaxResult_InvalidSession(responseData);
|
||||
RefreshModel(model);
|
||||
|
||||
// Reference data - Report types.
|
||||
responseData.ReportTypes.Add(new AjaxResponse_Data.ItemCodeDesc());
|
||||
List<Sax.UserReportType> validReportTypes = new List<Sax.UserReportType>(EnumUtil.GetValues<Sax.UserReportType>());
|
||||
foreach (TypeCodeDesc reportType in UserReportTypeCodes)
|
||||
{
|
||||
if (!validReportTypes.Contains((Sax.UserReportType)reportType.Type)) continue;
|
||||
responseData.ReportTypes.Add(new AjaxResponse_Data.ItemCodeDesc() { Code = reportType.Code, Desc = Localiser.GetUserReportTypeCaption((Sax.UserReportType)reportType.Type) });
|
||||
}
|
||||
|
||||
// Item filter.
|
||||
SaxUserReport.Params prmUserReport = new SaxUserReport.Params();
|
||||
prmUserReport.UserAccountIdsIncluded.Add(SessionUserAccountId);
|
||||
prmUserReport.StatusCat = SaxUserReport.StatusCat.NotDeleted;
|
||||
model.Paging.ItemTotal = (ulong)SupportMgr.GetUserReportCount(prmUserReport);
|
||||
model.PopulatePagingTo(prmUserReport.ResultsPaging);
|
||||
|
||||
// Item columns.
|
||||
ColumnDfn colId = SupportMgr.GetUserReportColumnDfn(SaxUserReport.Column.Id);
|
||||
ColumnDfn colUserAccountId = SupportMgr.GetUserReportColumnDfn(SaxUserReport.Column.UserAccountId);
|
||||
ColumnDfn colReportType = SupportMgr.GetUserReportColumnDfn(SaxUserReport.Column.ReportType);
|
||||
ColumnDfn colReportTitle = SupportMgr.GetUserReportColumnDfn(SaxUserReport.Column.Title);
|
||||
ColumnDfn colRecordedOn = SupportMgr.GetUserReportColumnDfn(SaxUserReport.Column.RecordedOn);
|
||||
ColumnDfn colStatus = SupportMgr.GetUserReportColumnDfn(SaxUserReport.Column.Status);
|
||||
List<ColumnDfn> columns = new List<ColumnDfn>()
|
||||
{
|
||||
colId,
|
||||
colUserAccountId, colReportType, colReportTitle,colRecordedOn,
|
||||
colStatus,
|
||||
};
|
||||
|
||||
// Sort columns.
|
||||
prmUserReport.SortColumns.Add(colRecordedOn);
|
||||
prmUserReport.SortColumns.Last().SortAscending = false;
|
||||
prmUserReport.SortColumns.Add(colId);
|
||||
prmUserReport.SortColumns.Last().SortAscending = false;
|
||||
|
||||
// User account details must be queried separately - different database!
|
||||
HashSet<SysId> userAccountIds = new HashSet<SysId>();
|
||||
|
||||
// Query items.
|
||||
using (DbResultSet resultSet = SupportMgr.ExecuteUserReportQuery(columns, prmUserReport))
|
||||
{
|
||||
while (resultSet != null && resultSet.HasRows && resultSet.NextRecord())
|
||||
{
|
||||
NamedValue.Map values = resultSet.GetRecordValues();
|
||||
SysId userAccountId = new SysId(values.GetLong(colUserAccountId.DataName));
|
||||
userAccountIds.Add(userAccountId);
|
||||
Sax.UserReportType reportType = (Sax.UserReportType)values.GetLong(colReportType.DataName);
|
||||
UserReportResponseListData userReportData = new UserReportResponseListData()
|
||||
{
|
||||
Id = model.EncryptId(new SysId(values.GetLong(colId.DataName))),
|
||||
UserAccountId = userAccountId,
|
||||
ReportTypeDesc = Localiser.GetUserReportTypeCaption(reportType),
|
||||
ReportTitle = values.GetString(colReportTitle.DataName),
|
||||
RecordedOnDisp = model.FormatDateForDisplay(values.GetDate(colRecordedOn.DataName)),
|
||||
OwnReport = userAccountId.Equals(SessionUserAccountId) ? (bool?)true : null,
|
||||
StatusCode = values.GetString(colStatus.DataName),
|
||||
StatusDesc = SacsSystem.GetStatusDescForCode(values.GetString(colStatus.DataName))
|
||||
};
|
||||
responseData.Reports.Add(userReportData);
|
||||
}
|
||||
}
|
||||
if (model.Paging.IsPaged)
|
||||
model.Paging.ItemCount = (ushort)responseData.Reports.Count;
|
||||
|
||||
// Query and populate User Account details.
|
||||
if (userAccountIds.Any())
|
||||
{
|
||||
// User Account columns.
|
||||
ColumnDfn colUserAccount_Id = AccountMgr.GetUserAccountColumnDfn(SaxUserAccount.Column.Id);
|
||||
ColumnDfn colUserAccount_Title = AccountMgr.GetUserAccountColumnDfn(SaxUserAccount.Column.Title);
|
||||
ColumnDfn colUserAccount_FirstName = AccountMgr.GetUserAccountColumnDfn(SaxUserAccount.Column.FirstName);
|
||||
ColumnDfn colUserAccount_LastName = AccountMgr.GetUserAccountColumnDfn(SaxUserAccount.Column.LastName);
|
||||
List<ColumnDfn> userAccountCols = new List<ColumnDfn>() { colUserAccount_Id, colUserAccount_Title, colUserAccount_FirstName, colUserAccount_LastName };
|
||||
// User Account filter.
|
||||
SaxUserAccount.Params prmUserAccount = new SaxUserAccount.Params();
|
||||
prmUserAccount.IdsIncluded.AddRange(userAccountIds);
|
||||
prmUserAccount.StatusCat = SaxUserAccount.StatusCat.Any;
|
||||
// Query user accounts and populate properties to report list.
|
||||
using (DbResultSet resultSet = AccountMgr.ExecuteUserAccountQuery(userAccountCols, prmUserAccount))
|
||||
{
|
||||
while (resultSet != null && resultSet.HasRows && resultSet.NextRecord())
|
||||
{
|
||||
NamedValue.Map values = resultSet.GetRecordValues();
|
||||
SysId userAccountId = new SysId(values.GetLong(colUserAccount_Id.DataName));
|
||||
String title = values.GetString(colUserAccount_Title.DataName);
|
||||
String firstName = values.GetString(colUserAccount_FirstName.DataName);
|
||||
String lastName = values.GetString(colUserAccount_LastName.DataName);
|
||||
foreach (UserReportResponseListData userReportData in responseData.Reports.FindAll(item => item.UserAccountId.Equals(userAccountId)))
|
||||
{
|
||||
userReportData.UserDisplayName = SaxUserAccount.GetDisplayName(title, firstName, lastName);
|
||||
userReportData.UserAccountId = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Clear any remaining User Account Ids.
|
||||
foreach (UserReportResponseListData userReportData in responseData.Reports.FindAll(item => item.UserAccountId != null))
|
||||
userReportData.UserAccountId = null;
|
||||
}
|
||||
|
||||
// Complete response.
|
||||
responseData.SetPaging(model);
|
||||
responseData.Success = true;
|
||||
return Json(responseData);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Get User Report ajax request.
|
||||
//-------------------------------------------------------------------
|
||||
private class AjaxResponse_UserReport : AjaxResponse_Data
|
||||
{
|
||||
// Construction.
|
||||
public AjaxResponse_UserReport(SaxModel_Online model) : base(model) { }
|
||||
// Sport details.
|
||||
public UserReportResponseItemData Report { get; } = new UserReportResponseItemData();
|
||||
}
|
||||
//-------------------------------------------------------------------
|
||||
[HttpPost]
|
||||
[Route("Support/Ajax/GetUserReport")]
|
||||
public IActionResult Ajax_GetUserReport(Model_Support model)
|
||||
{
|
||||
String fn = GetType().Name + ".Ajax_GetUserReport";
|
||||
String messageTitle = Localiser["support.caption.user.report"];
|
||||
AjaxResponse_UserReport responseData = new AjaxResponse_UserReport(model);
|
||||
|
||||
// Validate session and referrer.
|
||||
if (!ValidReferer) return Forbid();
|
||||
if (!ValidUserSession) return GetAjaxResult_InvalidSession(responseData);
|
||||
RefreshModel(model);
|
||||
|
||||
// Record disposable items as they are created so all can be disposed when needed.
|
||||
using (DisposableCollection<IDisposable> disposableItems = new DisposableCollection<IDisposable>())
|
||||
{
|
||||
|
||||
// Identify item.
|
||||
SysId userReportId = model.ExtractSysId(model.UserReport.Id);
|
||||
if (!SysId.IsValid(userReportId))
|
||||
return Json(responseData.SetPopupMessage(messageTitle, Localiser["msg.error.item.id.not.specified"]));
|
||||
|
||||
// Retrieve item.
|
||||
SaxUserReport userReport = SupportMgr.GetUserReportById(userReportId);
|
||||
disposableItems.Add(userReport);
|
||||
if (userReport == null)
|
||||
{
|
||||
SaLogger.Warn(fn + " Failed to retrieve User Report for Id: '" + model.UserReport.Id + "'");
|
||||
return Json(responseData.SetPopupMessage(messageTitle, Localiser["msg.error.item.id.not.found"]));
|
||||
}
|
||||
|
||||
// Retrieve user.
|
||||
SaxUserAccount userAccount = AccountMgr.GetUserAccountById(userReport.UserAccountId);
|
||||
disposableItems.Add(userAccount);
|
||||
if (userAccount == null)
|
||||
{
|
||||
SaLogger.Warn(fn + " Failed to retrieve User Account for Id: '" + userReport.UserAccountId + "'");
|
||||
return Json(responseData.SetPopupMessage(messageTitle, Localiser["msg.error.item.id.not.found"]));
|
||||
}
|
||||
|
||||
// Construct response.
|
||||
PopulateUserReportResponseItemData(model, userReport, userAccount, responseData.Report);
|
||||
responseData.Success = true;
|
||||
}
|
||||
return Json(responseData);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Store User Report ajax request.
|
||||
//-------------------------------------------------------------------
|
||||
[HttpPost]
|
||||
[Route("Support/Ajax/StoreUserReport")]
|
||||
public IActionResult Ajax_StoreUserReport(Model_Support model)
|
||||
{
|
||||
String fn = GetType().Name + ".Ajax_StoreUserReport";
|
||||
String messageTitle = Localiser["support.caption.user.report"];
|
||||
AjaxResponse_UserReport responseData = new AjaxResponse_UserReport(model);
|
||||
|
||||
// Validate session and referrer.
|
||||
if (!ValidReferer) return Forbid();
|
||||
if (!ValidUserSession) return GetAjaxResult_InvalidSession(responseData);
|
||||
if (!SessionData_Online.User.Roles.Exists(item => item.Role == Sax.UserRole.SystemReviewer)) return Forbid();
|
||||
RefreshModel(model);
|
||||
|
||||
// Record disposable items as they are created so all can be disposed when needed.
|
||||
using (DisposableCollection<IDisposable> disposableItems = new DisposableCollection<IDisposable>())
|
||||
{
|
||||
|
||||
// Validate item properties.
|
||||
model.ValidateUserReportData(responseData);
|
||||
if (responseData.HasControlErrors())
|
||||
return Json(responseData);
|
||||
|
||||
// Validate User Report Id against 'Exists' flag.
|
||||
SysId userReportId = model.ExtractSysId(model.UserReport.Id);
|
||||
bool userReportExists = StringUtil.ToBool(model.UserReport.Exists);
|
||||
if (userReportExists && !SysId.IsValid(userReportId))
|
||||
{
|
||||
SaLogger.Warn(fn + " Id not specified for existing User Report.");
|
||||
return Json(responseData.SetGoHome(messageTitle, Localiser["msg.error.system"]));
|
||||
}
|
||||
if (!userReportExists && SysId.IsValid(userReportId))
|
||||
{
|
||||
SaLogger.Warn(fn + " Id specified for new User Report: '" + model.UserReport.Id + "'");
|
||||
return Json(responseData.SetGoHome(messageTitle, Localiser["msg.error.system"]));
|
||||
}
|
||||
|
||||
// Retrieve user.
|
||||
SysId userAccountId = SessionUserAccountId;
|
||||
SaxUserAccount userAccount = AccountMgr.GetUserAccountById(userAccountId);
|
||||
disposableItems.Add(userAccount);
|
||||
if (userAccount == null)
|
||||
{
|
||||
SaLogger.Warn(fn + " Failed to retrieve User Account for Id: '" + userAccountId + "'");
|
||||
return Json(responseData.SetPopupMessage(messageTitle, Localiser["msg.error.item.id.not.found"]));
|
||||
}
|
||||
|
||||
// Retrieve existing item.
|
||||
SaxUserReport userReport = SupportMgr.GetUserReportById(userReportId);
|
||||
disposableItems.Add(userReport);
|
||||
if (userReport == null && SysId.IsValid(userReportId))
|
||||
{
|
||||
SaLogger.Warn(fn + " Failed to retrieve User Report for Id: '" + model.UserReport.Id + "'");
|
||||
return Json(responseData.SetPopupMessage(messageTitle, Localiser["msg.error.item.id.not.found"]));
|
||||
}
|
||||
// Validate User Report properties.
|
||||
if (userReport != null)
|
||||
{
|
||||
if (!userReport.UserAccountId.Equals(userAccountId))
|
||||
{
|
||||
SaLogger.Warn(fn + " Inconsistent User Account Id specified for User Report. Expected: " + userReport.UserAccountId + ". Found: " + userAccountId);
|
||||
return Json(responseData.SetGoHome(messageTitle, Localiser["msg.error.system"]));
|
||||
}
|
||||
}
|
||||
|
||||
// If User Report doesn't exist, create a new one.
|
||||
if (userReport == null)
|
||||
{
|
||||
userReport = SupportMgr.CreateUserReport(userAccountId);
|
||||
disposableItems.Add(userReport);
|
||||
userReport.RecordedOn = DateTime.Today;
|
||||
}
|
||||
|
||||
// Populate item properties.
|
||||
if (model.UserReport.ReportType != null)
|
||||
userReport.ReportType = model.GetReportType();
|
||||
if (model.UserReport.Title != null)
|
||||
userReport.Title = model.UserReport.Title;
|
||||
if (model.UserReport.Report != null)
|
||||
userReport.Report = model.UserReport.Report;
|
||||
|
||||
// Store item.
|
||||
if (!SysId.IsValid(userReport.Id))
|
||||
{
|
||||
if (!SupportMgr.InsertUserReport(userReport, DbUpdateInfo))
|
||||
{
|
||||
SaLogger.Warn(fn + " Failed to insert user report: " + SupportMgr.ErrorStateMessage);
|
||||
return Json(responseData.SetPopupMessage(messageTitle, Localiser["msg.error.item.insert.failed"]));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!SupportMgr.UpdateUserReport(userReport, DbUpdateInfo))
|
||||
{
|
||||
SaLogger.Warn(fn + " Failed to update user report [Id:" + SysId.ToString(userReport.Id) + "]: " + SupportMgr.ErrorStateMessage);
|
||||
return Json(responseData.SetPopupMessage(messageTitle, Localiser["msg.error.item.update.failed"]));
|
||||
}
|
||||
}
|
||||
|
||||
// Construct response.
|
||||
PopulateUserReportResponseItemData(model, userReport, userAccount, responseData.Report);
|
||||
responseData.Success = true;
|
||||
}
|
||||
return Json(responseData);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
}
|
||||
//=======================================================================
|
||||
}
|
||||
@@ -0,0 +1,81 @@
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Sarand.Net.Standard.Base.Bus;
|
||||
using Sarand.Net.Standard.Base.Core;
|
||||
using Sarand.Net.Standard.Base.Dbas;
|
||||
using Sarand.Net.Standard.Base.Utils;
|
||||
using Saxonite.Net.Core.Web.Base.App;
|
||||
using Saxonite.Net.Core.Web.Online.Models;
|
||||
using Saxonite.Net.Standard.Base.App;
|
||||
using Saxonite.Net.Standard.Base.Bus;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Saxonite.Net.Core.Web.Online.Controllers
|
||||
{
|
||||
//=======================================================================
|
||||
// Online Support Controller.
|
||||
//=======================================================================
|
||||
public partial class SupportController : SaxController_Online
|
||||
{
|
||||
//-------------------------------------------------------------------
|
||||
// Construction.
|
||||
public SupportController(SaxLocaliser localiser, ILogger<HomeController> logger) :
|
||||
base(localiser, logger)
|
||||
{
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
[HttpGet]
|
||||
public IActionResult Index()
|
||||
{
|
||||
// Validate session.
|
||||
if (!ValidUserSession)
|
||||
return RedirectToAction("", "");
|
||||
|
||||
// No Support index page.
|
||||
return RedirectToAction("", "");
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
[HttpGet,HttpPost]
|
||||
public IActionResult Feedback()
|
||||
{
|
||||
// Validate session.
|
||||
if (!ValidUserSession)
|
||||
return RedirectToAction("", "");
|
||||
Model_Support model = new Model_Support(Localiser);
|
||||
|
||||
// User must be a member of the 'Reviewers' role.
|
||||
if (!SessionData_Online.User.SupportMenuAllowed)
|
||||
return RedirectToAction("", "");
|
||||
|
||||
// Applincation index page.
|
||||
model.ProhibitCache = false;
|
||||
return View(model);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
[HttpGet, HttpPost]
|
||||
public IActionResult Versions()
|
||||
{
|
||||
// Validate session.
|
||||
if (!ValidUserSession)
|
||||
return RedirectToAction("", "");
|
||||
Model_Support model = new Model_Support(Localiser);
|
||||
|
||||
// User must be a member of the 'Reviewers' role.
|
||||
if (!SessionData_Online.User.SupportMenuAllowed)
|
||||
return RedirectToAction("", "");
|
||||
|
||||
// Applincation index page.
|
||||
model.ProhibitCache = false;
|
||||
return View(model);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
}
|
||||
//=======================================================================
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
using Sarand.Net.Standard.Base.Helpers;
|
||||
using Sarand.Net.Standard.Base.Utils;
|
||||
using Saxonite.Net.Core.Web.Base.App;
|
||||
using Saxonite.Net.Standard.Base.App;
|
||||
using Saxonite.Net.Standard.Base.Helpers;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Saxonite.Net.Core.Web.Online.Helpers
|
||||
{
|
||||
//=======================================================================
|
||||
public static class SaxContactMethodHelper_Online
|
||||
{
|
||||
//-------------------------------------------------------------------
|
||||
public static String GetContactMethodHtml(Sax.ContactMethod method, String value, SaxLocaliser localiser)
|
||||
{
|
||||
// Qualify any URL value to ensure that it can be used as the href attribute in an anchor tag.
|
||||
String url = (SaxContactMethodHelper.GetContactMethodType(method) == Sax.ContactMethodType.WebUrl) ? SacsDataValidationHelper.QualifyAbsoluteUrl(value) : value;
|
||||
|
||||
switch (method)
|
||||
{
|
||||
// Phone numbers.
|
||||
case Sax.ContactMethod.PhoneMain:
|
||||
return ConstructImageElement("icon/contact/phone-24.png") + localiser["label.main"] + ": " + value;
|
||||
case Sax.ContactMethod.PhoneMobile:
|
||||
return ConstructImageElement("icon/contact/mobile-24.png") + localiser["label.mobile"] + ": " + value;
|
||||
case Sax.ContactMethod.PhoneHome:
|
||||
return ConstructImageElement("icon/contact/phone-24.png") + localiser["label.home"] + ": " + value;
|
||||
case Sax.ContactMethod.PhoneOffice:
|
||||
return ConstructImageElement("icon/contact/phone-24.png") + localiser["label.office"] + ": " + value;
|
||||
// Online.
|
||||
case Sax.ContactMethod.Email:
|
||||
return "<a href='mailto:" + value + "'>" + ConstructImageElement("action/mail24.png") + value + " </a>";
|
||||
case Sax.ContactMethod.Website:
|
||||
return "<a href='" + url + "' target='" + Sax.Config.Links.Targets.Website + "'>" + ConstructImageElement("icon/contact/www-24.png") + value + " </a>";
|
||||
case Sax.ContactMethod.Wikipedia:
|
||||
return "<a href='" + url + "' target='" + Sax.Config.Links.Targets.Wikipedia + "'>" + ConstructImageElement("icon/contact/wikipedia-24.png") + value + " </a>";
|
||||
// Social media.
|
||||
case Sax.ContactMethod.LinkedIn:
|
||||
return "<a href='" + url + "' target='" + Sax.Config.Links.Targets.LinkedIn + "'>" + ConstructImageElement("icon/contact/linkedin-24.png") + value + " </a>";
|
||||
case Sax.ContactMethod.Twitter:
|
||||
return "<a href='" + url + "' target='" + Sax.Config.Links.Targets.Twitter + "'>" + ConstructImageElement("icon/contact/x-24.png") + value + " </a>";
|
||||
case Sax.ContactMethod.Facebook:
|
||||
return "<a href='" + url + "' target='" + Sax.Config.Links.Targets.Facebook + "'>" + ConstructImageElement("icon/contact/facebook-24.png") + value + " </a>";
|
||||
case Sax.ContactMethod.Instagram:
|
||||
return "<a href='" + url + "' target='" + Sax.Config.Links.Targets.Instagram + "'>" + ConstructImageElement("icon/contact/instagram-24.png") + value + " </a>";
|
||||
}
|
||||
return method.ToString() + ": " + value;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Utilities.
|
||||
public static String ConstructImageElement(String imageFilepath, String alt = "", String title = "")
|
||||
{
|
||||
return "<img src='../img/" + imageFilepath + "' alt='" + StringUtil.EmptyOnNull(alt) + "' title='" + StringUtil.EmptyOnNull(title) + "' />";
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
}
|
||||
//=======================================================================
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
using Saxonite.Net.Core.Web.Base.App;
|
||||
using System;
|
||||
|
||||
namespace Saxonite.Net.Core.Web.Online.Models
|
||||
{
|
||||
//=======================================================================
|
||||
public class ErrorViewModel : SaxModel_Online
|
||||
{
|
||||
//-------------------------------------------------------------------
|
||||
// Construction.
|
||||
public ErrorViewModel(SaxLocaliser localiser) :
|
||||
base(localiser)
|
||||
{
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
public string RequestId { get; set; }
|
||||
|
||||
public bool ShowRequestId => !string.IsNullOrEmpty(RequestId);
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
}
|
||||
//=======================================================================
|
||||
}
|
||||
@@ -0,0 +1,150 @@
|
||||
using Sarand.Net.Standard.Base.App;
|
||||
using Sarand.Net.Standard.Base.Bus;
|
||||
using Sarand.Net.Standard.Base.Core;
|
||||
using Sarand.Net.Standard.Base.Helpers;
|
||||
using Sarand.Net.Standard.Base.Utils;
|
||||
using Saxonite.Base.App;
|
||||
using Saxonite.Net.Core.Web.Base.App;
|
||||
using Saxonite.Net.Core.Web.Base.Controllers;
|
||||
using Saxonite.Net.Standard.Base.App;
|
||||
using Saxonite.Net.Standard.Base.Bus;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Saxonite.Net.Core.Web.Online.Models
|
||||
{
|
||||
//=======================================================================
|
||||
/// <summary>
|
||||
/// Address model data properties.
|
||||
/// </summary>
|
||||
public class ModelData_Address : ModelData_Online
|
||||
{
|
||||
//-------------------------------------------------------------------
|
||||
// Construction.
|
||||
public ModelData_Address(SaxModel_Online model, String controlNameSuffix) : base(model)
|
||||
{
|
||||
this.ControlNameSuffix = StringUtil.EmptyOnNull(controlNameSuffix) + "Address";
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Properties.
|
||||
private String ControlNameSuffix { get; }
|
||||
// Address properties.
|
||||
public String Id { get; set; }
|
||||
public String Line1 { get; set; }
|
||||
public String Line2 { get; set; }
|
||||
public String Line3 { get; set; }
|
||||
public String Town { get; set; }
|
||||
public String Province { get; set; }
|
||||
public String RegionIdProvince { get; set; }
|
||||
public String Country { get; set; }
|
||||
public String PostalCode { get; set; }
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Utilities.
|
||||
/// <summary>Have any address values been supplied by the form.</summary>
|
||||
public bool IsSpecified()
|
||||
{
|
||||
if (Id != null || Line1 != null || Town != null || Province != null || Country != null || PostalCode != null)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
/// <summary>Have any address values been populated on the form.</summary>
|
||||
public bool IsPopulated()
|
||||
{
|
||||
if (SysId.IsValid(SysId.ToSysId(Id)) || !StringUtil.IsEmpty(Line1) || !StringUtil.IsEmpty(Town) || !StringUtil.IsEmpty(Province) || !StringUtil.IsEmpty(Country) || !StringUtil.IsEmpty(PostalCode))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Validation.
|
||||
//-------------------------------------------------------------------
|
||||
// Address.
|
||||
public bool ValidateAddressData(SaxController_Base.AjaxResponse_Data responseData)
|
||||
{
|
||||
// Are any properties populated.
|
||||
bool populated = IsPopulated();
|
||||
|
||||
// Address Line 1 - optional.
|
||||
if (Line1 != null)
|
||||
{
|
||||
responseData.SetControlValue(ControlNameSuffix + "Line1", Line1);
|
||||
if (StringUtil.GetLength(Line1) > Model.GetControlMaxLength(SaxDbDfn_Core.ColumnIdx.ItemAddress_Line1))
|
||||
responseData.SetControlError(ControlNameSuffix + "Line1", Model.Localiser["msg.validation.maximum.length", Model.GetControlMaxLength(SaxDbDfn_Core.ColumnIdx.ItemAddress_Line1)]);
|
||||
}
|
||||
|
||||
// Address Line 2 - optional.
|
||||
if (Line2 != null)
|
||||
{
|
||||
responseData.SetControlValue(ControlNameSuffix + "Line2", Line2);
|
||||
if (!StringUtil.IsEmpty(Line2))
|
||||
{
|
||||
if (StringUtil.GetLength(Line2) > Model.GetControlMaxLength(SaxDbDfn_Core.ColumnIdx.ItemAddress_Line2))
|
||||
responseData.SetControlError(ControlNameSuffix + "Line2", Model.Localiser["msg.validation.maximum.length", Model.GetControlMaxLength(SaxDbDfn_Core.ColumnIdx.ItemAddress_Line2)]);
|
||||
}
|
||||
}
|
||||
|
||||
// Address Line 3 - optional.
|
||||
if (Line3 != null)
|
||||
{
|
||||
responseData.SetControlValue(ControlNameSuffix + "Line3", Line3);
|
||||
if (!StringUtil.IsEmpty(Line3))
|
||||
{
|
||||
if (StringUtil.GetLength(Line3) > Model.GetControlMaxLength(SaxDbDfn_Core.ColumnIdx.ItemAddress_Line3))
|
||||
responseData.SetControlError(ControlNameSuffix + "Line3", Model.Localiser["msg.validation.maximum.length", Model.GetControlMaxLength(SaxDbDfn_Core.ColumnIdx.ItemAddress_Line3)]);
|
||||
}
|
||||
}
|
||||
|
||||
// Address Town - mandatory if any value populated.
|
||||
if (Town != null)
|
||||
{
|
||||
responseData.SetControlValue(ControlNameSuffix + "Town", Town);
|
||||
if (StringUtil.IsEmpty(Town) && populated)
|
||||
responseData.SetControlError(ControlNameSuffix + "Town", Model.Localiser["msg.validation.mandatory.value"]);
|
||||
else if (StringUtil.GetLength(Town) > Model.GetControlMaxLength(SaxDbDfn_Core.ColumnIdx.ItemAddress_Town))
|
||||
responseData.SetControlError(ControlNameSuffix + "Town", Model.Localiser["msg.validation.maximum.length", Model.GetControlMaxLength(SaxDbDfn_Core.ColumnIdx.ItemAddress_Town)]);
|
||||
}
|
||||
|
||||
// Address Province - optional.
|
||||
if (Province != null)
|
||||
{
|
||||
responseData.SetControlValue(ControlNameSuffix + "Province", Province);
|
||||
if (!StringUtil.IsEmpty(Province))
|
||||
{
|
||||
if (StringUtil.GetLength(Province) > Model.GetControlMaxLength(SaxDbDfn_Core.ColumnIdx.ItemAddress_Province))
|
||||
responseData.SetControlError(ControlNameSuffix + "Province", Model.Localiser["msg.validation.maximum.length", Model.GetControlMaxLength(SaxDbDfn_Core.ColumnIdx.ItemAddress_Province)]);
|
||||
}
|
||||
}
|
||||
|
||||
// Address Country - optional.
|
||||
if (Country != null)
|
||||
{
|
||||
responseData.SetControlValue(ControlNameSuffix + "Country", Country);
|
||||
if (!StringUtil.IsEmpty(Country))
|
||||
{
|
||||
if (StringUtil.GetLength(Country) > Model.GetControlMaxLength(SaxDbDfn_Core.ColumnIdx.ItemAddress_Country))
|
||||
responseData.SetControlError(ControlNameSuffix + "Country", Model.Localiser["msg.validation.maximum.length", Model.GetControlMaxLength(SaxDbDfn_Core.ColumnIdx.ItemAddress_Country)]);
|
||||
}
|
||||
}
|
||||
|
||||
// Address PostalCode - optional.
|
||||
if (PostalCode != null)
|
||||
{
|
||||
responseData.SetControlValue(ControlNameSuffix + "PostalCode", PostalCode);
|
||||
if (!StringUtil.IsEmpty(PostalCode))
|
||||
{
|
||||
if (StringUtil.GetLength(PostalCode) > Model.GetControlMaxLength(SaxDbDfn_Core.ColumnIdx.ItemAddress_PostalCode))
|
||||
responseData.SetControlError(ControlNameSuffix + "PostalCode", Model.Localiser["msg.validation.maximum.length", Model.GetControlMaxLength(SaxDbDfn_Core.ColumnIdx.ItemAddress_PostalCode)]);
|
||||
}
|
||||
}
|
||||
|
||||
return !responseData.HasControlErrors();
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
}
|
||||
//=======================================================================
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
using Sarand.Net.Standard.Base.App;
|
||||
using Sarand.Net.Standard.Base.Bus;
|
||||
using Sarand.Net.Standard.Base.Core;
|
||||
using Sarand.Net.Standard.Base.Helpers;
|
||||
using Sarand.Net.Standard.Base.Utils;
|
||||
using Saxonite.Base.App;
|
||||
using Saxonite.Net.Core.Web.Base.App;
|
||||
using Saxonite.Net.Core.Web.Base.Controllers;
|
||||
using Saxonite.Net.Standard.Base.App;
|
||||
using Saxonite.Net.Standard.Base.Bus;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Saxonite.Net.Core.Web.Online.Models
|
||||
{
|
||||
//=======================================================================
|
||||
/// <summary>
|
||||
/// Online model data.
|
||||
/// </summary>
|
||||
public class ModelData_Online
|
||||
{
|
||||
//-------------------------------------------------------------------
|
||||
// Construction.
|
||||
public ModelData_Online(SaxModel_Online model)
|
||||
{
|
||||
this.Model = model;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Properties.
|
||||
public SaxModel_Online Model { get; }
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
}
|
||||
//=======================================================================
|
||||
}
|
||||
@@ -0,0 +1,142 @@
|
||||
using Sarand.Net.Standard.Base.App;
|
||||
using Sarand.Net.Standard.Base.Bus;
|
||||
using Sarand.Net.Standard.Base.Core;
|
||||
using Sarand.Net.Standard.Base.Helpers;
|
||||
using Sarand.Net.Standard.Base.Utils;
|
||||
using Saxonite.Base.App;
|
||||
using Saxonite.Net.Core.Web.Base.Controllers;
|
||||
using Saxonite.Net.Standard.Base.App;
|
||||
using Saxonite.Net.Standard.Base.Bus;
|
||||
using Saxonite.Net.Standard.Base.Helpers;
|
||||
using System;
|
||||
|
||||
namespace Saxonite.Net.Core.Web.Online.Models
|
||||
{
|
||||
//=======================================================================
|
||||
/// <summary>
|
||||
/// Organisation model data properties.
|
||||
/// </summary>
|
||||
public class ModelData_Organisation : ModelData_Online
|
||||
{
|
||||
//-------------------------------------------------------------------
|
||||
// Construction.
|
||||
public ModelData_Organisation(SaxModel_Online model, String controlNameSuffix = "Organisation") : base(model)
|
||||
{
|
||||
this.ControlNameSuffix = StringUtil.EmptyOnNull(controlNameSuffix);
|
||||
Address = new ModelData_Address(model, ControlNameSuffix);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Properties.
|
||||
private String ControlNameSuffix { get; }
|
||||
// Organisation properties.
|
||||
public String Id { get; set; }
|
||||
public String Name { get; set; }
|
||||
public String Type { get; set; }
|
||||
public Sax.OrganisationType GetOrganisationType() { return (Sax.OrganisationType)Model.OrganisationTypeCodes.GetTypeForCode(Type); }
|
||||
public String Category { get; set; }
|
||||
public Sax.OrganisationCategory GetOrganisationCategory() { return (Sax.OrganisationCategory)Model.OrganisationCategoryCodes.GetTypeForCode(Category); }
|
||||
public String SportId { get; set; }
|
||||
public String RegionIdPrimary { get; set; }
|
||||
public String About { get; set; }
|
||||
public String Facilities { get; set; }
|
||||
// Contact Methods.
|
||||
/// <summary>Placeholder field value to indicate the number of Contact Methods in form (even if none are populated).</summary>
|
||||
public String ContactMethods { get; set; }
|
||||
public String[] ContactMethod { get; set; }
|
||||
public String[] ContactValue { get; set; }
|
||||
/// <summary>Contact methods to be populated during validation.</summary>
|
||||
public SaxContactData ContactData { get; set; }
|
||||
// Address.
|
||||
public ModelData_Address Address { get; }
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Validation.
|
||||
//-------------------------------------------------------------------
|
||||
// Organisation.
|
||||
public bool ValidateOrganisationData(SaxController_Base.AjaxResponse_Data responseData)
|
||||
{
|
||||
String fn = this.GetType().Name + ".ValidateOrganisationData";
|
||||
|
||||
// Name - mandatory.
|
||||
responseData.SetControlValue(ControlNameSuffix + nameof(Name), Name);
|
||||
if (StringUtil.IsEmpty(Name))
|
||||
responseData.SetControlError(ControlNameSuffix + nameof(Name), Model.Localiser["msg.validation.mandatory.value"]);
|
||||
else if (StringUtil.GetLength(Name) > Model.GetControlMaxLength(SaxDbDfn_Core.ColumnIdx.Organisation_Name))
|
||||
responseData.SetControlError(ControlNameSuffix + nameof(Name), Model.Localiser["msg.validation.maximum.length", Model.GetControlMaxLength(SaxDbDfn_Core.ColumnIdx.Organisation_Name)]);
|
||||
else if (SysId.IsValid(Model.ExtractSysId(RegionIdPrimary)))
|
||||
{
|
||||
// Ensure that the organisation name is unique within the region.
|
||||
SaxOrganisation.Params prmOrganisation = new SaxOrganisation.Params();
|
||||
if (SysId.IsValid(Model.ExtractSysId(Id)))
|
||||
prmOrganisation.IdsExcluded.Add(Model.ExtractSysId(Id));
|
||||
prmOrganisation.NameFull = Name;
|
||||
prmOrganisation.RegionIdsIncluded.Add(Model.ExtractSysId(RegionIdPrimary));
|
||||
prmOrganisation.StatusCat = SaxOrganisation.StatusCat.Any;
|
||||
if (Model.AccountMgr.GetOrganisationCount(prmOrganisation) > 0)
|
||||
responseData.SetControlError(ControlNameSuffix + nameof(Name), Model.Localiser["msg.validation.duplicate.value"]);
|
||||
}
|
||||
|
||||
// Organisation Category - mandatory.
|
||||
if (StringUtil.IsEmpty(Category))
|
||||
responseData.SetControlError(ControlNameSuffix + nameof(Category), Model.Localiser["msg.validation.mandatory.value"]);
|
||||
|
||||
// Organisation Type - mandatory.
|
||||
if (StringUtil.IsEmpty(Type))
|
||||
responseData.SetControlError(ControlNameSuffix + nameof(Type), Model.Localiser["msg.validation.mandatory.value"]);
|
||||
|
||||
// Sport - mandatory for certain organisation categories.
|
||||
if (StringUtil.IsEmpty(SportId) && SaxOrganisation.IsSportMandatory(GetOrganisationCategory()))
|
||||
responseData.SetControlError(ControlNameSuffix + nameof(SportId), Model.Localiser["msg.validation.mandatory.value"]);
|
||||
else if (!StringUtil.IsEmpty(SportId) && !SysId.IsValid(Model.ExtractSysId(SportId)))
|
||||
responseData.SetControlError(ControlNameSuffix + nameof(SportId), Model.Localiser["msg.validation.invalid.value"]);
|
||||
|
||||
// Primary Region - mandatory.
|
||||
if (StringUtil.IsEmpty(RegionIdPrimary))
|
||||
responseData.SetControlError(ControlNameSuffix + nameof(RegionIdPrimary), Model.Localiser["msg.validation.mandatory.value"]);
|
||||
else if (!SysId.IsValid(Model.ExtractSysId(RegionIdPrimary)))
|
||||
responseData.SetControlError(ControlNameSuffix + nameof(RegionIdPrimary), Model.Localiser["msg.validation.invalid.value"]);
|
||||
|
||||
// About - optional.
|
||||
responseData.SetControlValue(ControlNameSuffix + nameof(About), About);
|
||||
if (StringUtil.GetLength(About) > Model.GetControlMaxLength(SaxDbDfn_Core.ColumnIdx.Organisation_About))
|
||||
responseData.SetControlError(ControlNameSuffix + nameof(About), Model.Localiser["msg.validation.maximum.length", Model.GetControlMaxLength(SaxDbDfn_Core.ColumnIdx.Organisation_About)]);
|
||||
|
||||
// Facilities - optional.
|
||||
responseData.SetControlValue(ControlNameSuffix + nameof(Facilities), Facilities);
|
||||
if (StringUtil.GetLength(Facilities) > Model.GetControlMaxLength(SaxDbDfn_Core.ColumnIdx.Organisation_Facilities))
|
||||
responseData.SetControlError(ControlNameSuffix + nameof(Facilities), Model.Localiser["msg.validation.maximum.length", Model.GetControlMaxLength(SaxDbDfn_Core.ColumnIdx.Organisation_Facilities)]);
|
||||
|
||||
// Contact Methods.
|
||||
if (ContactMethods != null)
|
||||
{
|
||||
ContactData = new SaxContactData("");
|
||||
ContactMethod = ContactMethod ?? new String[0];
|
||||
ContactValue = ContactValue ?? new String[0];
|
||||
for (int idx = 0; idx < ContactMethod.Length && idx < ContactValue.Length; idx++)
|
||||
{
|
||||
String methodValue = ContactMethod[idx];
|
||||
String value = ContactValue[idx];
|
||||
if (methodValue == null && value == null) continue;
|
||||
Sax.ContactMethod method = EnumUtil.ParseEnum(methodValue, Sax.ContactMethod.Unknown);
|
||||
if (method > 0 && !value.IsEmpty() && SaxContactMethodHelper.IsValidContactMethodValue(method, value))
|
||||
ContactData.SetContactMethodValue(method, value);
|
||||
else SaLogger.Warn(fn + " Invalid Contact Method data. Method: " + methodValue + ". Value: " + value);
|
||||
}
|
||||
if (ContactData.Methods.Count != ContactMethods.ToInt())
|
||||
{
|
||||
SaLogger.Warn(fn + " Inconsistent Contact Methods received. Expected: " + ContactMethods + ". Received: " + ContactData.Methods.Count);
|
||||
responseData.SetPopupMessage("caption.contact.method", "System error");
|
||||
}
|
||||
}
|
||||
|
||||
// Address.
|
||||
Address.ValidateAddressData(responseData);
|
||||
|
||||
return !responseData.HasControlErrors() && responseData.PopupMessage == null;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
}
|
||||
//=======================================================================
|
||||
}
|
||||
@@ -0,0 +1,276 @@
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Sarand.Net.Standard.Base.App;
|
||||
using Sarand.Net.Standard.Base.Bus;
|
||||
using Sarand.Net.Standard.Base.Core;
|
||||
using Sarand.Net.Standard.Base.Utils;
|
||||
using Saxonite.Base.App;
|
||||
using Saxonite.Net.Core.Web.Base.App;
|
||||
using Saxonite.Net.Core.Web.Base.Controllers;
|
||||
using Saxonite.Net.Core.Web.Base.Models;
|
||||
using Saxonite.Net.Standard.Base.App;
|
||||
using Saxonite.Net.Standard.Base.Bus;
|
||||
using Saxonite.Net.Standard.Base.Helpers;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using static Saxonite.Net.Standard.Base.App.Sax;
|
||||
using static Saxonite.Net.Standard.Base.Bus.SaxArticle;
|
||||
|
||||
namespace Saxonite.Net.Core.Web.Online.Models
|
||||
{
|
||||
//=======================================================================
|
||||
public class Model_Account : SaxModel_Online
|
||||
{
|
||||
//-------------------------------------------------------------------
|
||||
// Construction.
|
||||
public Model_Account(SaxLocaliser localiser) :
|
||||
base(localiser)
|
||||
{
|
||||
// Model data.
|
||||
Organisation = new ModelData_Organisation(this);
|
||||
|
||||
// Page includes.
|
||||
AdditionalFiles_CSS.Add("css/sax-account.css");
|
||||
AdditionalFiles_JS.Add("js/sax-account.js");
|
||||
AdditionalFiles_JS.Add("js/sax-pro-usr.js");
|
||||
AdditionalFiles_JS.Add("js/sax-pro-cfg.js");
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Contact Properties.
|
||||
public String AccountEmailAddress { get; set; }
|
||||
public String AccountTitle { get; set; }
|
||||
public String AccountFirstName { get; set; }
|
||||
public String AccountLastName { get; set; }
|
||||
public String AccountAbout { get; set; }
|
||||
public String AccountGender { get; set; }
|
||||
public Sax.Gender GetAccountGender()
|
||||
{
|
||||
return (Sax.Gender)StringUtil.ToShort(AccountGender);
|
||||
}
|
||||
public String AccountDobDay { get; set; }
|
||||
public String AccountDobMonth { get; set; }
|
||||
public String AccountDobYear { get; set; }
|
||||
// Regions.
|
||||
public String AccountRegionIdCountry { get; set; }
|
||||
public String AccountRegionCaptionCountry { get; }
|
||||
public String AccountRegionIdProvince { get; set; }
|
||||
public String AccountRegionCaptionProvince { get; }
|
||||
// Image.
|
||||
public List<IFormFile> AccountContactImage { get; set; }
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Sport properties.
|
||||
public String UserSportId { get; set; }
|
||||
public String ProfileSportId { get; set; }
|
||||
public String ProfileSportExists { get; set; }
|
||||
public String ProfileSportParticipatingCode { get; set; }
|
||||
public Sax.SportParticipating ProfileSportParticipating
|
||||
{
|
||||
get { return (Sax.SportParticipating)SportParticipatingCodes.GetTypeForCode(ProfileSportParticipatingCode); }
|
||||
set { ProfileSportParticipatingCode = SportParticipatingCodes.GetCodeForType(value); }
|
||||
}
|
||||
public String ProfileSportPreparingCode { get; set; }
|
||||
public Sax.SportPreparing ProfileSportPreparing
|
||||
{
|
||||
get { return (Sax.SportPreparing)SportPreparingCodes.GetTypeForCode(ProfileSportPreparingCode); }
|
||||
set { ProfileSportPreparingCode = SportPreparingCodes.GetCodeForType(value); }
|
||||
}
|
||||
public String ProfileSportOfficiatingCode { get; set; }
|
||||
public Sax.SportOfficiating ProfileSportOfficiating
|
||||
{
|
||||
get { return (Sax.SportOfficiating)SportOfficiatingCodes.GetTypeForCode(ProfileSportOfficiatingCode); }
|
||||
set { ProfileSportOfficiatingCode = SportOfficiatingCodes.GetCodeForType(value); }
|
||||
}
|
||||
public String ProfileSportAbout { get; set; }
|
||||
public class SportsContactsData
|
||||
{
|
||||
// Contacts.
|
||||
/// <summary>Placeholder field value to indicate the number of Contacts in form (even if none are populated).</summary>
|
||||
public String Count { get; set; }
|
||||
public String[] ContactType { get; set; }
|
||||
public String[] UserAccountId { get; set; }
|
||||
public String[] Title { get; set; }
|
||||
public String[] FirstName { get; set; }
|
||||
public String[] LastName { get; set; }
|
||||
public String[] EmailAddress { get; set; }
|
||||
public String[] Phone { get; set; }
|
||||
/// <summary>Sport Contacts to be populated during validation.</summary>
|
||||
public SaxSportContactsData ContactsData { get; set; }
|
||||
}
|
||||
public SportsContactsData Contacts {get; } = new SportsContactsData();
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Organisation properties.
|
||||
public ModelData_Organisation Organisation { get; }
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Validate model data.
|
||||
//-------------------------------------------------------------------
|
||||
// Validate contact details.
|
||||
public bool ValidateContactDetails(SaxController_Base.AjaxResponse_Data responseData)
|
||||
{
|
||||
//---------------------------------------------------------------
|
||||
// Title.
|
||||
if (AccountTitle != null)
|
||||
{
|
||||
responseData.SetControlValue(nameof(AccountTitle), AccountTitle);
|
||||
if (StringUtil.IsEmpty(AccountTitle))
|
||||
responseData.SetControlError(nameof(AccountTitle), Localiser["msg.validation.mandatory.value"]);
|
||||
else if (StringUtil.GetLength(AccountTitle) > GetControlMaxLength(SaxDbDfn_Core.ColumnIdx.UserAccount_Title))
|
||||
responseData.SetControlError(nameof(AccountTitle), Localiser["msg.validation.maximum.length", GetControlMaxLength(SaxDbDfn_Core.ColumnIdx.UserAccount_Title)]);
|
||||
}
|
||||
|
||||
// First Name.
|
||||
if (AccountFirstName != null)
|
||||
{
|
||||
responseData.SetControlValue(nameof(AccountFirstName), AccountFirstName);
|
||||
if (StringUtil.IsEmpty(AccountFirstName))
|
||||
responseData.SetControlError(nameof(AccountFirstName), Localiser["msg.validation.mandatory.value"]);
|
||||
else if (StringUtil.GetLength(AccountFirstName) > GetControlMaxLength(SaxDbDfn_Core.ColumnIdx.UserAccount_FirstName))
|
||||
responseData.SetControlError(nameof(AccountFirstName), Localiser["msg.validation.maximum.length", GetControlMaxLength(SaxDbDfn_Core.ColumnIdx.UserAccount_FirstName)]);
|
||||
}
|
||||
|
||||
// Last Name.
|
||||
if (AccountLastName != null)
|
||||
{
|
||||
responseData.SetControlValue(nameof(AccountLastName), AccountLastName);
|
||||
if (StringUtil.IsEmpty(AccountLastName))
|
||||
responseData.SetControlError(nameof(AccountLastName), Localiser["msg.validation.mandatory.value"]);
|
||||
else if (StringUtil.GetLength(AccountLastName) > GetControlMaxLength(SaxDbDfn_Core.ColumnIdx.UserAccount_LastName))
|
||||
responseData.SetControlError(nameof(AccountLastName), Localiser["msg.validation.maximum.length", GetControlMaxLength(SaxDbDfn_Core.ColumnIdx.UserAccount_LastName)]);
|
||||
}
|
||||
|
||||
// About.
|
||||
if (AccountAbout != null)
|
||||
{
|
||||
responseData.SetControlValue(nameof(AccountAbout), AccountAbout);
|
||||
if (!StringUtil.IsEmpty(AccountAbout))
|
||||
{
|
||||
if (StringUtil.GetLength(AccountAbout) > GetControlMaxLength(SaxDbDfn_Core.ColumnIdx.UserAccount_About))
|
||||
responseData.SetControlError(nameof(AccountAbout), Localiser["msg.validation.maximum.length", GetControlMaxLength(SaxDbDfn_Core.ColumnIdx.UserAccount_About)]);
|
||||
}
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------
|
||||
// Date of birth.
|
||||
if (AccountDobYear != null)
|
||||
{
|
||||
responseData.SetControlValue(nameof(AccountDobYear), AccountDobYear);
|
||||
short dobYear = StringUtil.ToShort(AccountDobYear);
|
||||
if (!StringUtil.IsNumeric(AccountDobYear) || dobYear > DateTime.Today.Year)
|
||||
responseData.SetControlError(nameof(AccountDobYear), Localiser["msg.validation.invalid.value"]);
|
||||
}
|
||||
if (AccountDobMonth != null)
|
||||
{
|
||||
responseData.SetControlValue(nameof(AccountDobMonth), AccountDobMonth);
|
||||
short dobMonth = StringUtil.ToShort(AccountDobMonth);
|
||||
if (!StringUtil.IsEmpty(AccountDobMonth) && (!StringUtil.IsNumeric(AccountDobMonth) || dobMonth < 0 || dobMonth > 12))
|
||||
responseData.SetControlError(nameof(AccountDobMonth), Localiser["msg.validation.invalid.value"]);
|
||||
}
|
||||
if (AccountDobDay != null)
|
||||
{
|
||||
responseData.SetControlValue(nameof(AccountDobDay), AccountDobDay);
|
||||
short dobDay = StringUtil.ToShort(AccountDobDay);
|
||||
if (!StringUtil.IsEmpty(AccountDobDay) && (!StringUtil.IsNumeric(AccountDobDay) || dobDay < 0 || dobDay > 31))
|
||||
responseData.SetControlError(nameof(AccountDobDay), Localiser["msg.validation.invalid.value"]);
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------
|
||||
// Country Region.
|
||||
SysId regionIdCountry = ExtractSysId(AccountRegionIdCountry);
|
||||
if (AccountRegionIdCountry != null && SysId.IsValid(regionIdCountry))
|
||||
{
|
||||
SaxRegion.Data regionCountry = Internals.GetRegion(regionIdCountry);
|
||||
if (regionCountry == null)
|
||||
responseData.SetControlError(nameof(AccountRegionIdCountry), Localiser["msg.validation.invalid.value"]);
|
||||
}
|
||||
|
||||
// Province Region.
|
||||
if (AccountRegionIdProvince != null)
|
||||
{
|
||||
SysId regionIdProvince = ExtractSysId(AccountRegionIdProvince);
|
||||
SaxRegion.Data regionProvince = Internals.GetRegion(regionIdProvince);
|
||||
if (regionProvince == null)
|
||||
responseData.SetControlError(nameof(AccountRegionIdProvince), Localiser["msg.validation.invalid.value"]);
|
||||
}
|
||||
|
||||
return !responseData.HasControlErrors();
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Validate Sport data.
|
||||
public bool ValidateProfileSportData(SaxController_Base.AjaxResponse_Data responseData)
|
||||
{
|
||||
String fn = GetType().Name + ".ValidateProfileSportData";
|
||||
|
||||
// Sport.
|
||||
if (ProfileSportId != null)
|
||||
{
|
||||
SysId profileSportId = ExtractSysId(ProfileSportId);
|
||||
if (!SysId.IsValid(profileSportId))
|
||||
responseData.SetControlError(nameof(ProfileSportId), Localiser["msg.validation.mandatory.value"]);
|
||||
}
|
||||
|
||||
// About.
|
||||
if (ProfileSportAbout != null)
|
||||
{
|
||||
responseData.SetControlValue(nameof(ProfileSportAbout), ProfileSportAbout);
|
||||
if (!StringUtil.IsEmpty(ProfileSportAbout))
|
||||
{
|
||||
if (StringUtil.GetLength(ProfileSportAbout) > GetControlMaxLength(SaxDbDfn_Core.ColumnIdx.UserSport_About))
|
||||
responseData.SetControlError(nameof(ProfileSportAbout), Localiser["msg.validation.maximum.length", GetControlMaxLength(SaxDbDfn_Core.ColumnIdx.UserSport_About)]);
|
||||
}
|
||||
}
|
||||
|
||||
// Sport Contacts.
|
||||
if (Contacts != null)
|
||||
{
|
||||
Contacts.ContactsData = new SaxSportContactsData("");
|
||||
Contacts.ContactType= Contacts.ContactType ?? new String[0];
|
||||
Contacts.Title= Contacts.Title ?? new String[0];
|
||||
Contacts.FirstName = Contacts.FirstName ?? new String[0];
|
||||
Contacts.LastName = Contacts.LastName ?? new String[0];
|
||||
Contacts.EmailAddress = Contacts.EmailAddress ?? new String[0];
|
||||
for (int idx = 0; idx < Contacts.ContactType.Length; idx++)
|
||||
{
|
||||
String contactTypeValue = Contacts.ContactType[idx];
|
||||
String title = idx < Contacts.Title.Length ? Contacts.Title[idx] : null;
|
||||
String firstName = idx < Contacts.FirstName.Length ? Contacts.FirstName[idx] : null;
|
||||
String lastName = idx < Contacts.LastName.Length ? Contacts.LastName[idx] : null;
|
||||
String emailAddress = idx < Contacts.EmailAddress.Length ? Contacts.EmailAddress[idx] : null;
|
||||
String phone = idx < Contacts.Phone.Length ? Contacts.Phone[idx] : null;
|
||||
if (StringUtil.IsBlank(contactTypeValue) && StringUtil.IsBlank(lastName)) continue;
|
||||
Sax.SportContactType contactType= (Sax.SportContactType)SportContactTypeCodes.GetTypeForCode(contactTypeValue);
|
||||
if (contactType > 0)
|
||||
{
|
||||
Contacts.ContactsData.SetContactName(contactType, title, firstName, lastName);
|
||||
Contacts.ContactsData.SetContactEmailAddress(contactType, emailAddress);
|
||||
Contacts.ContactsData.SetContactPhone(contactType, phone);
|
||||
}
|
||||
else SaLogger.Warn(fn + " Invalid Sport Contact data. Type: " + contactTypeValue + ". Last name: " + lastName);
|
||||
}
|
||||
if (Contacts.ContactsData.ContactTypes.Count != Contacts.Count.ToInt())
|
||||
{
|
||||
SaLogger.Warn(fn + " Inconsistent Contact Methods received. Expected: " + Contacts.Count + ". Received: " + Contacts.ContactsData.ContactTypes.Count);
|
||||
responseData.SetPopupMessage("caption.contact.method", "System error");
|
||||
}
|
||||
}
|
||||
|
||||
return !responseData.HasControlErrors();
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Validate Organisation data.
|
||||
public bool ValidateProfileOrganisationData(SaxController_Base.AjaxResponse_Data responseData)
|
||||
{
|
||||
Organisation.ValidateOrganisationData(responseData);
|
||||
|
||||
return !responseData.HasControlErrors();
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
}
|
||||
//=======================================================================
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
using Sarand.Net.Standard.Base.Bus;
|
||||
using Sarand.Net.Standard.Base.Utils;
|
||||
using Saxonite.Base.App;
|
||||
using Saxonite.Net.Core.Web.Base.App;
|
||||
using Saxonite.Net.Core.Web.Base.Controllers;
|
||||
using Saxonite.Net.Core.Web.Base.Models;
|
||||
using Saxonite.Net.Standard.Base.App;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Saxonite.Net.Core.Web.Online.Models
|
||||
{
|
||||
//=======================================================================
|
||||
public class Model_Activity : SaxModel_Online
|
||||
{
|
||||
//-------------------------------------------------------------------
|
||||
// Construction.
|
||||
public Model_Activity(SaxLocaliser localiser) :
|
||||
base(localiser)
|
||||
{
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Activity filter.
|
||||
public class FilterData
|
||||
{
|
||||
public String Search { get; set; }
|
||||
public String OrganisationId { get; set; }
|
||||
}
|
||||
public FilterData Filter { get; } = new FilterData();
|
||||
|
||||
// Activity identity.
|
||||
// ToDo Replace Type + Idx (Id) with Idx and cross-reference stored in Session data.
|
||||
public String ActivityItemType { get; set; }
|
||||
public String ActivityItemId { get; set; }
|
||||
public String ActivityReaction { get; set; }
|
||||
public Sax.ActivityReaction GetActivityReaction()
|
||||
{
|
||||
Sax.ActivityReaction reaction = EnumUtil.ParseEnum(ActivityReaction, Sax.ActivityReaction.Unknown);
|
||||
if (reaction <= 0 && StringUtil.IsNumeric(ActivityReaction))
|
||||
reaction = (Sax.ActivityReaction)StringUtil.ToShort(ActivityReaction);
|
||||
return reaction;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
}
|
||||
//=======================================================================
|
||||
}
|
||||
@@ -0,0 +1,156 @@
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Sarand.Net.Standard.Base.App;
|
||||
using Sarand.Net.Standard.Base.Bus;
|
||||
using Sarand.Net.Standard.Base.Core;
|
||||
using Sarand.Net.Standard.Base.Utils;
|
||||
using Saxonite.Base.App;
|
||||
using Saxonite.Net.Core.Web.Base.App;
|
||||
using Saxonite.Net.Core.Web.Base.Controllers;
|
||||
using Saxonite.Net.Standard.Base.App;
|
||||
using Saxonite.Net.Standard.Base.Bus;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Saxonite.Net.Core.Web.Online.Models
|
||||
{
|
||||
//=======================================================================
|
||||
public class Model_Article : SaxModel_Online
|
||||
{
|
||||
//-------------------------------------------------------------------
|
||||
// Construction.
|
||||
public Model_Article(SaxLocaliser localiser) :
|
||||
base(localiser)
|
||||
{
|
||||
AdditionalFiles_CSS.Add("css/sax-art.css");
|
||||
AdditionalFiles_JS.Add("js/sax-art.js");
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// List configuration.
|
||||
public class FilterData
|
||||
{
|
||||
public String OrganisationId { get; set; }
|
||||
public String OrganisationCaption { get; set; }
|
||||
public String Article { get; set; }
|
||||
}
|
||||
public FilterData Filter { get; } = new FilterData();
|
||||
/// <summary>
|
||||
/// User has rights to author articles for at least one organisation.
|
||||
/// <para>- Output only - not returned with form data.</para>
|
||||
/// <para>- Only populated for initial page construction.</para>
|
||||
/// </summary>
|
||||
public bool UserCanAuthorOrganisationArticles { get; set; }
|
||||
/// <summary>
|
||||
/// User has rights to author articles as a journalist.
|
||||
/// <para>- Output only - not returned with form data.</para>
|
||||
/// <para>- Only populated for initial page construction.</para>
|
||||
/// </summary>
|
||||
public bool UserCanAuthorJournalistArticles { get; set; }
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Article properties.
|
||||
public String ArticleId { get; set; }
|
||||
public String ArticleExists { get; set; }
|
||||
// Organisation.
|
||||
public String ArticleOrganisationId { get; set; }
|
||||
// Sport.
|
||||
public String ArticleSportId { get; set; }
|
||||
public String ArticleSportCaption { get; set; }
|
||||
// Region.
|
||||
public String ArticleRegionId { get; set; }
|
||||
public String ArticleRegionCaption { get; }
|
||||
// Article Content.
|
||||
public String ArticleHeadline { get; set; }
|
||||
public String ArticleSummary { get; set; }
|
||||
public String ArticleStatusCode { get; set; }
|
||||
public SaStatus ArticleStatus { get { return SacsSystem.GetStatusForCode(ArticleStatusCode); } }
|
||||
// Article content.
|
||||
public List<String> ArticleContentSegmentBodies { get; set; }
|
||||
public List<String> ArticleContentSegmentItemImageIds { get; set; }
|
||||
public List<String> ArticleContentSegmentImageIdxs { get; set; }
|
||||
// Article images.
|
||||
public List<IFormFile> ArticleImage { get; set; }
|
||||
// Article publication.
|
||||
public String ArticlePublished { get; set; }
|
||||
public bool ArticlePublish { get; set; }
|
||||
public String ArticlePublishOn { get; set; }
|
||||
public DateTime GetArticlePublishOn()
|
||||
{
|
||||
return ParseDateFromForm(ArticlePublishOn);
|
||||
}
|
||||
public String ArticleExpiresAfterDays { get; set; }
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Validation.
|
||||
//-------------------------------------------------------------------
|
||||
// Article.
|
||||
public bool ValidateArticleData(SaxController_Base.AjaxResponse_Data responseData)
|
||||
{
|
||||
// Article headline.
|
||||
if (ArticleHeadline != null)
|
||||
{
|
||||
responseData.SetControlValue(nameof(ArticleHeadline), ArticleHeadline);
|
||||
if (StringUtil.IsEmpty(ArticleHeadline))
|
||||
responseData.SetControlError(nameof(ArticleHeadline), Localiser["msg.validation.mandatory.value"]);
|
||||
else if (StringUtil.GetLength(ArticleHeadline) > GetControlMaxLength(SaxDbDfn_Core.ColumnIdx.Article_Headline))
|
||||
responseData.SetControlError(nameof(ArticleHeadline), Localiser["msg.validation.maximum.length", GetControlMaxLength(SaxDbDfn_Core.ColumnIdx.Article_Headline)]);
|
||||
}
|
||||
|
||||
// Article summary.
|
||||
if (ArticleSummary != null)
|
||||
{
|
||||
responseData.SetControlValue(nameof(ArticleSummary), ArticleSummary);
|
||||
if (StringUtil.IsEmpty(ArticleSummary))
|
||||
responseData.SetControlError(nameof(ArticleSummary), Localiser["msg.validation.mandatory.value"]);
|
||||
else if (StringUtil.GetLength(ArticleSummary) > GetControlMaxLength(SaxDbDfn_Core.ColumnIdx.Article_Summary))
|
||||
responseData.SetControlError(nameof(ArticleSummary), Localiser["msg.validation.maximum.length", GetControlMaxLength(SaxDbDfn_Core.ColumnIdx.Article_Summary)]);
|
||||
}
|
||||
|
||||
// Article sport.
|
||||
if (ArticleSportId != null)
|
||||
{
|
||||
SysId articleSportId = ExtractSysId(ArticleSportId);
|
||||
if (!SysId.IsValid(articleSportId))
|
||||
responseData.SetControlError(nameof(ArticleSportId), Localiser["msg.validation.mandatory.value"]);
|
||||
}
|
||||
|
||||
// Article region.
|
||||
if (ArticleRegionId != null)
|
||||
{
|
||||
SysId articleRegionId = ExtractSysId(ArticleRegionId);
|
||||
if (!SysId.IsValid(articleRegionId))
|
||||
responseData.SetControlError(nameof(ArticleRegionId), Localiser["msg.validation.mandatory.value"]);
|
||||
}
|
||||
|
||||
// Article publication.
|
||||
// Only relevant when the article hasn't yet been published and user has selected 'Publish'.
|
||||
if (!ArticlePublished.ToBool() && ArticlePublish)
|
||||
{
|
||||
String controlName = "ArticlePublication";
|
||||
DateTime publishedOn = GetArticlePublishOn();
|
||||
if (StringUtil.IsEmpty(ArticlePublishOn))
|
||||
responseData.SetControlError(controlName, Localiser["msg.validation.mandatory.value"]);
|
||||
else if (!DateUtil.IsValid(publishedOn))
|
||||
responseData.SetControlError(controlName, Localiser["msg.validation.invalid.value"]);
|
||||
else if (publishedOn.CompareTo(DateUtil.IncrementDate(DateTime.Today, Sax.Config.Articles.PublishMaxDaysAhead)) > 0)
|
||||
responseData.SetControlError(controlName, Localiser["msg.validation.invalid.value"]);
|
||||
}
|
||||
|
||||
// Article status.
|
||||
if (ArticleStatusCode != null)
|
||||
{
|
||||
if (StringUtil.IsEmpty(ArticleStatusCode))
|
||||
responseData.SetControlError(nameof(ArticleStatusCode), Localiser["msg.validation.mandatory.value"]);
|
||||
else if (!SaxArticle.ValidStatuses.Contains(ArticleStatus))
|
||||
responseData.SetControlError(nameof(ArticleStatusCode), Localiser["msg.validation.invalid.value"]);
|
||||
}
|
||||
|
||||
return !responseData.HasControlErrors();
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
}
|
||||
//=======================================================================
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
using Saxonite.Net.Core.Web.Base.App;
|
||||
using Saxonite.Net.Core.Web.Base.Models;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Saxonite.Net.Core.Web.Online.Models
|
||||
{
|
||||
//=======================================================================
|
||||
public class Model_ContactMethod : SaxModel_Online
|
||||
{
|
||||
//-------------------------------------------------------------------
|
||||
// Construction.
|
||||
public Model_ContactMethod(SaxLocaliser localiser) :
|
||||
base(localiser)
|
||||
{
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Form properties.
|
||||
public String ContactMethod { get; set; }
|
||||
public String ContactValue { get; set; }
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
}
|
||||
//=======================================================================
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
using Saxonite.Net.Core.Web.Base.App;
|
||||
using Saxonite.Net.Core.Web.Base.Models;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Saxonite.Net.Core.Web.Online.Models
|
||||
{
|
||||
//=======================================================================
|
||||
public class Model_Home : SaxModel_Online
|
||||
{
|
||||
//-------------------------------------------------------------------
|
||||
// Construction.
|
||||
public Model_Home(SaxLocaliser localiser) :
|
||||
base(localiser)
|
||||
{
|
||||
AdditionalFiles_CSS.Add("css/sax-home.css");
|
||||
AdditionalFiles_JS.Add("js/sax-home.js");
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
}
|
||||
//=======================================================================
|
||||
}
|
||||
@@ -0,0 +1,101 @@
|
||||
using Sarand.Net.Standard.Base.App;
|
||||
using Sarand.Net.Standard.Base.Bus;
|
||||
using Sarand.Net.Standard.Base.Core;
|
||||
using Sarand.Net.Standard.Base.Helpers;
|
||||
using Sarand.Net.Standard.Base.Utils;
|
||||
using Saxonite.Base.App;
|
||||
using Saxonite.Net.Core.Web.Base.App;
|
||||
using Saxonite.Net.Core.Web.Base.Controllers;
|
||||
using Saxonite.Net.Standard.Base.App;
|
||||
using Saxonite.Net.Standard.Base.Bus;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Saxonite.Net.Core.Web.Online.Models
|
||||
{
|
||||
//=======================================================================
|
||||
public class Model_Organisation : SaxModel_Online
|
||||
{
|
||||
//-------------------------------------------------------------------
|
||||
// Construction.
|
||||
public Model_Organisation(SaxLocaliser localiser) :
|
||||
base(localiser)
|
||||
{
|
||||
// Model data.
|
||||
Organisation = new ModelData_Organisation(this);
|
||||
|
||||
// Page includes.
|
||||
//AdditionalFiles_CSS.Add("css/sax-org.css");
|
||||
AdditionalFiles_JS.Add("js/sax-org.js");
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// List configuration.
|
||||
public class OrganisationFilterData
|
||||
{
|
||||
public String Organisation { get; set; }
|
||||
public String RegionId { get; set; }
|
||||
public String SportId { get; set; }
|
||||
}
|
||||
public OrganisationFilterData Filter { get; } = new OrganisationFilterData();
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Organisation properties.
|
||||
public ModelData_Organisation Organisation { get; set; }
|
||||
// User - for organisation request.
|
||||
public String ContactEmailAddress { get; set; }
|
||||
public String ContactFirstName { get; set; }
|
||||
public String ContactLastName { get; set; }
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Validation.
|
||||
//-------------------------------------------------------------------
|
||||
// Organisation.
|
||||
public bool ValidateOrganisationRequestData(SaxController_Base.AjaxResponse_Data responseData)
|
||||
{
|
||||
// User Email Address - mandatory when supplied.
|
||||
if (ContactEmailAddress != null)
|
||||
{
|
||||
responseData.SetControlValue(nameof(ContactEmailAddress), ContactEmailAddress);
|
||||
if (StringUtil.IsEmpty(ContactEmailAddress))
|
||||
responseData.SetControlError(nameof(ContactEmailAddress), Localiser["msg.validation.mandatory.value"]);
|
||||
else if (!SacsDataValidationHelper.IsValidEmailAddress(ContactEmailAddress))
|
||||
responseData.SetControlError(nameof(ContactEmailAddress), Localiser["msg.validation.invalid.value"]);
|
||||
else if (StringUtil.GetLength(ContactEmailAddress) > GetControlMaxLength(SaxDbDfn_Core.ColumnIdx.UserAccount_EmailAddress))
|
||||
responseData.SetControlError(nameof(ContactEmailAddress), Localiser["msg.validation.maximum.length", GetControlMaxLength(SaxDbDfn_Core.ColumnIdx.UserAccount_EmailAddress)]);
|
||||
else if (AccountMgr.UserAccountExistsByEmailAddress(ContactEmailAddress))
|
||||
responseData.SetControlError(nameof(ContactEmailAddress), Localiser["msg.validation.duplicate.value"]);
|
||||
}
|
||||
|
||||
// User First Name - mandatory when supplied.
|
||||
if (ContactFirstName != null)
|
||||
{
|
||||
responseData.SetControlValue(nameof(ContactFirstName), ContactFirstName);
|
||||
if (StringUtil.IsEmpty(ContactFirstName))
|
||||
responseData.SetControlError(nameof(ContactFirstName), Localiser["msg.validation.mandatory.value"]);
|
||||
else if (StringUtil.GetLength(ContactFirstName) > GetControlMaxLength(SaxDbDfn_Core.ColumnIdx.UserAccount_FirstName))
|
||||
responseData.SetControlError(nameof(ContactFirstName), Localiser["msg.validation.maximum.length", GetControlMaxLength(SaxDbDfn_Core.ColumnIdx.UserAccount_FirstName)]);
|
||||
}
|
||||
|
||||
// User Last Name - mandatory when supplied.
|
||||
if (ContactLastName != null)
|
||||
{
|
||||
responseData.SetControlValue(nameof(ContactLastName), ContactLastName);
|
||||
if (StringUtil.IsEmpty(ContactLastName))
|
||||
responseData.SetControlError(nameof(ContactLastName), Localiser["msg.validation.mandatory.value"]);
|
||||
else if (StringUtil.GetLength(ContactLastName) > GetControlMaxLength(SaxDbDfn_Core.ColumnIdx.UserAccount_LastName))
|
||||
responseData.SetControlError(nameof(ContactLastName), Localiser["msg.validation.maximum.length", GetControlMaxLength(SaxDbDfn_Core.ColumnIdx.UserAccount_LastName)]);
|
||||
}
|
||||
|
||||
// Organisation properties.
|
||||
Organisation.ValidateOrganisationData(responseData);
|
||||
|
||||
return !responseData.HasControlErrors();
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
}
|
||||
//=======================================================================
|
||||
}
|
||||
@@ -0,0 +1,236 @@
|
||||
using Microsoft.AspNetCore.Mvc.Rendering;
|
||||
using NPOI.SS.Formula.Functions;
|
||||
using Sarand.Net.Standard.Base.App;
|
||||
using Sarand.Net.Standard.Base.Bus;
|
||||
using Sarand.Net.Standard.Base.Core;
|
||||
using Sarand.Net.Standard.Base.Utils;
|
||||
using Saxonite.Base.App;
|
||||
using Saxonite.Net.Core.Web.Base.App;
|
||||
using Saxonite.Net.Core.Web.Base.Controllers;
|
||||
using Saxonite.Net.Standard.Base.Bus;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Saxonite.Net.Core.Web.Online.Models
|
||||
{
|
||||
//=======================================================================
|
||||
public class Model_Organisation_Events : SaxModel_Online
|
||||
{
|
||||
//-------------------------------------------------------------------
|
||||
// Definitions.
|
||||
public enum PeriodType
|
||||
{
|
||||
FromThisWeek,
|
||||
FromThisMonth,
|
||||
FromLastMonth,
|
||||
FromNextMonth,
|
||||
Past,
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Construction.
|
||||
public Model_Organisation_Events(SaxLocaliser localiser) :
|
||||
base(localiser)
|
||||
{
|
||||
AdditionalFiles_CSS.Add("css/sax-org-evt.css");
|
||||
AdditionalFiles_JS.Add("js/sax-org-evt.js");
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// List configuration.
|
||||
public class EventFilterData
|
||||
{
|
||||
public String OrganisationId { get; set; }
|
||||
public String OrganisationCaption { get; set; }
|
||||
public class PeriodData
|
||||
{
|
||||
public String Type { get; set; }
|
||||
public PeriodType PeriodType { get { return EnumUtil.ParseEnum(Type, PeriodType.FromThisWeek); } }
|
||||
public String FromDate { get; set; }
|
||||
public String ToDate { get; set; }
|
||||
}
|
||||
public PeriodData Period { get; } = new PeriodData();
|
||||
public String Event { get; set; }
|
||||
}
|
||||
public EventFilterData Filter { get; } = new EventFilterData();
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Event properties.
|
||||
public String EventId { get; set; }
|
||||
public String EventExists { get; set; }
|
||||
// Event properties.
|
||||
public String EventOrganisationId { get; set; }
|
||||
// Sport.
|
||||
public String EventSportIdPrimary { get; set; }
|
||||
// Region.
|
||||
public String EventRegionIdCountry { get; set; }
|
||||
// Event Content.
|
||||
public String EventAtDate { get; set; }
|
||||
public bool EventAtTimeSet { get; set; }
|
||||
public String EventAtTime { get; set; }
|
||||
public String EventDuration { get; set; }
|
||||
public String EventDurationType { get; set; }
|
||||
public String EventToDate { get; set; }
|
||||
public bool EventToDateSet { get; set; }
|
||||
public String EventToTime { get; set; }
|
||||
public bool EventToTimeSet { get; set; }
|
||||
public String EventTypeCode { get; set; }
|
||||
public String EventSummary { get; set; }
|
||||
public String EventDetails { get; set; }
|
||||
public String EventStatusCode { get; set; }
|
||||
public SaStatus EventStatus { get { return SacsSystem.GetStatusForCode(EventStatusCode); } }
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Period types.
|
||||
public IEnumerable<SelectListItem> EventPeriodTypesForDropdown
|
||||
{
|
||||
get
|
||||
{
|
||||
List<SelectListItem> values = new List<SelectListItem>();
|
||||
values.Add(new SelectListItem("From this week", PeriodType.FromThisWeek.ToString(), true));
|
||||
values.Add(new SelectListItem("From this month", PeriodType.FromThisMonth.ToString()));
|
||||
values.Add(new SelectListItem("From last month", PeriodType.FromLastMonth.ToString()));
|
||||
values.Add(new SelectListItem("From next month", PeriodType.FromNextMonth.ToString()));
|
||||
return values;
|
||||
}
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Validation.
|
||||
//-------------------------------------------------------------------
|
||||
// Event.
|
||||
public bool ValidateEventData(SaxController_Base.AjaxResponse_Data responseData)
|
||||
{
|
||||
// Event type.
|
||||
if (EventTypeCode != null)
|
||||
{
|
||||
String controlName = nameof(EventTypeCode);
|
||||
if (StringUtil.IsEmpty(EventTypeCode))
|
||||
responseData.SetControlError(controlName, Localiser["msg.validation.mandatory.value"]);
|
||||
}
|
||||
|
||||
// Event At date.
|
||||
if (EventAtDate != null)
|
||||
{
|
||||
String controlName = nameof(EventAtDate);
|
||||
DateTime eventOn = ParseDateFromForm(EventAtDate);
|
||||
if (!DateUtil.IsValid(eventOn))
|
||||
responseData.SetControlError(controlName, Localiser["msg.validation.mandatory.value"]);
|
||||
}
|
||||
|
||||
// Event At Time Set flag.
|
||||
if (EventAtTimeSet)
|
||||
{
|
||||
String controlName = nameof(EventAtTime);
|
||||
if (StringUtil.IsBlank(EventAtTime))
|
||||
responseData.SetControlError(controlName, Localiser["msg.validation.mandatory.value"]);
|
||||
}
|
||||
|
||||
// Event At time.
|
||||
if (EventAtTime != null && EventAtTimeSet)
|
||||
{
|
||||
String controlName = nameof(EventAtTime);
|
||||
DateTime eventAt = DateUtil.ParseExact(EventAtTime, "HH:mm");
|
||||
if (StringUtil.IsBlank(EventAtTime))
|
||||
responseData.SetControlError(controlName, Localiser["msg.validation.mandatory.value"]);
|
||||
else if (!DateUtil.IsValid(eventAt))
|
||||
responseData.SetControlError(controlName, Localiser["msg.validation.invalid.value"]);
|
||||
}
|
||||
|
||||
// Event duration.
|
||||
if (EventDuration != null)
|
||||
{
|
||||
//String controlName = nameof(EventDuration);
|
||||
}
|
||||
|
||||
// Event duration type.
|
||||
if (EventDurationType != null)
|
||||
{
|
||||
//String controlName = nameof(EventDurationType);
|
||||
}
|
||||
|
||||
// Event To date.
|
||||
if (EventToDate != null && EventToDateSet)
|
||||
{
|
||||
String controlName = nameof(EventToDate);
|
||||
DateTime eventOn = ParseDateFromForm(EventToDate);
|
||||
if (!DateUtil.IsValid(eventOn))
|
||||
responseData.SetControlError(controlName, Localiser["msg.validation.mandatory.value"]);
|
||||
}
|
||||
|
||||
// Event To Time Set flag.
|
||||
if (EventToTimeSet)
|
||||
{
|
||||
String controlName = nameof(EventToTime);
|
||||
if (StringUtil.IsBlank(EventToTime))
|
||||
responseData.SetControlError(controlName, Localiser["msg.validation.mandatory.value"]);
|
||||
}
|
||||
|
||||
// Event To time.
|
||||
if (EventToTime != null && EventToTimeSet)
|
||||
{
|
||||
String controlName = nameof(EventToTime);
|
||||
DateTime eventTo = DateUtil.ParseExact(EventToTime, "HH:mm");
|
||||
if (StringUtil.IsBlank(EventToTime))
|
||||
responseData.SetControlError(controlName, Localiser["msg.validation.mandatory.value"]);
|
||||
else if (!DateUtil.IsValid(eventTo))
|
||||
responseData.SetControlError(controlName, Localiser["msg.validation.invalid.value"]);
|
||||
}
|
||||
|
||||
// Event summary.
|
||||
if (EventSummary != null)
|
||||
{
|
||||
String controlName = nameof(EventSummary);
|
||||
responseData.SetControlValue(controlName, EventSummary);
|
||||
if (StringUtil.IsEmpty(EventSummary))
|
||||
responseData.SetControlError(controlName, Localiser["msg.validation.mandatory.value"]);
|
||||
else if (StringUtil.GetLength(EventSummary) > GetControlMaxLength(SaxDbDfn_Core.ColumnIdx.OrganisationEvent_Summary))
|
||||
responseData.SetControlError(controlName, Localiser["msg.validation.maximum.length", GetControlMaxLength(SaxDbDfn_Core.ColumnIdx.OrganisationEvent_Summary)]);
|
||||
}
|
||||
|
||||
// Event details.
|
||||
if (EventDetails != null)
|
||||
{
|
||||
String controlName = nameof(EventDetails);
|
||||
responseData.SetControlValue(controlName, EventDetails);
|
||||
if (StringUtil.GetLength(EventDetails) > GetControlMaxLength(SaxDbDfn_Core.ColumnIdx.OrganisationEvent_Details))
|
||||
responseData.SetControlError(controlName, Localiser["msg.validation.maximum.length", GetControlMaxLength(SaxDbDfn_Core.ColumnIdx.OrganisationEvent_Details)]);
|
||||
}
|
||||
|
||||
// Event sport.
|
||||
if (EventSportIdPrimary != null)
|
||||
{
|
||||
String controlName = "EventSportPrimary";
|
||||
SysId articleSportId = ExtractSysId(EventSportIdPrimary);
|
||||
if (!SysId.IsValid(articleSportId))
|
||||
responseData.SetControlError(controlName, Localiser["msg.validation.mandatory.value"]);
|
||||
}
|
||||
|
||||
// Event region.
|
||||
if (EventRegionIdCountry != null)
|
||||
{
|
||||
String controlName = "EventRegionCountry";
|
||||
SysId articleRegionId = ExtractSysId(EventRegionIdCountry);
|
||||
if (!SysId.IsValid(articleRegionId))
|
||||
responseData.SetControlError(controlName, Localiser["msg.validation.mandatory.value"]);
|
||||
}
|
||||
|
||||
// Event status.
|
||||
if (EventStatusCode != null)
|
||||
{
|
||||
String controlName = nameof(EventStatus);
|
||||
if (StringUtil.IsEmpty(EventStatusCode))
|
||||
responseData.SetControlError(controlName, Localiser["msg.validation.mandatory.value"]);
|
||||
else if (!SaxOrganisationEvent.ValidStatuses.Contains(EventStatus))
|
||||
responseData.SetControlError(controlName, Localiser["msg.validation.invalid.value"]);
|
||||
}
|
||||
|
||||
return !responseData.HasControlErrors();
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
}
|
||||
//=======================================================================
|
||||
}
|
||||
@@ -0,0 +1,118 @@
|
||||
using Sarand.Net.Standard.Base.App;
|
||||
using Sarand.Net.Standard.Base.Bus;
|
||||
using Sarand.Net.Standard.Base.Core;
|
||||
using Sarand.Net.Standard.Base.Helpers;
|
||||
using Sarand.Net.Standard.Base.Utils;
|
||||
using Saxonite.Base.App;
|
||||
using Saxonite.Net.Core.Web.Base.App;
|
||||
using Saxonite.Net.Core.Web.Base.Controllers;
|
||||
using Saxonite.Net.Standard.Base.Bus;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Saxonite.Net.Core.Web.Online.Models
|
||||
{
|
||||
//=======================================================================
|
||||
public class Model_Organisation_Members : SaxModel_Online
|
||||
{
|
||||
//-------------------------------------------------------------------
|
||||
// Construction.
|
||||
public Model_Organisation_Members(SaxLocaliser localiser) :
|
||||
base(localiser)
|
||||
{
|
||||
//AdditionalFiles_CSS.Add("css/sax-org-mbr.css");
|
||||
AdditionalFiles_JS.Add("js/sax-org-mbr.js");
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// List configuration.
|
||||
public class MemberFilterData
|
||||
{
|
||||
public String OrganisationId { get; set; }
|
||||
public String OrganisationCaption { get; set; }
|
||||
public String Member { get; set; }
|
||||
public String OrganisationRole { get; set; }
|
||||
}
|
||||
public MemberFilterData Filter { get; } = new MemberFilterData();
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Member properties.
|
||||
public String MemberId { get; set; }
|
||||
public String MemberExists { get; set; }
|
||||
// Member properties.
|
||||
public String MemberOrganisationId { get; set; }
|
||||
public String MemberEmailAddress { get; set; }
|
||||
public String MemberNameSupplied{ get; set; }
|
||||
public String MemberTitle { get; set; }
|
||||
public String MemberFirstName { get; set; }
|
||||
public String MemberLastName { get; set; }
|
||||
public String MemberRoleCodeDelim = ",";
|
||||
public List<String> MemberRoleCodes { get; set; }
|
||||
public List<String> GetMemberRoleCodes()
|
||||
{
|
||||
List<String> codes = new List<string>();
|
||||
foreach (String code in MemberRoleCodes)
|
||||
{
|
||||
if (StringUtil.IsEmpty(code)) continue;
|
||||
codes.AddRange(code.Split(MemberRoleCodeDelim));
|
||||
}
|
||||
return codes;
|
||||
}
|
||||
public String MemberAdminComment { get; set; }
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Validation.
|
||||
//-------------------------------------------------------------------
|
||||
// Member.
|
||||
public bool ValidateMemberData(SaxController_Base.AjaxResponse_Data responseData)
|
||||
{
|
||||
// Member Email Address.
|
||||
if (MemberEmailAddress != null)
|
||||
{
|
||||
responseData.SetControlValue(nameof(MemberEmailAddress), MemberEmailAddress);
|
||||
if (StringUtil.IsEmpty(MemberEmailAddress))
|
||||
responseData.SetControlError(nameof(MemberEmailAddress), Localiser["msg.validation.mandatory.value"]);
|
||||
else if (StringUtil.GetLength(MemberEmailAddress) > GetControlMaxLength(SaxDbDfn_Core.ColumnIdx.UserAccount_EmailAddress))
|
||||
responseData.SetControlError(nameof(MemberEmailAddress), Localiser["msg.validation.maximum.length", GetControlMaxLength(SaxDbDfn_Core.ColumnIdx.UserAccount_EmailAddress)]);
|
||||
else if (!SacsDataValidationHelper.IsValidEmailAddress(MemberEmailAddress))
|
||||
responseData.SetControlError(nameof(MemberEmailAddress), Localiser["msg.validation.invalid.value"]);
|
||||
}
|
||||
|
||||
// Member First Name.
|
||||
bool memberNameSupplied = StringUtil.ToBool(MemberNameSupplied);
|
||||
if (MemberFirstName != null && memberNameSupplied)
|
||||
{
|
||||
responseData.SetControlValue(nameof(MemberFirstName), MemberFirstName);
|
||||
if (StringUtil.IsEmpty(MemberFirstName))
|
||||
responseData.SetControlError(nameof(MemberFirstName), Localiser["msg.validation.mandatory.value"]);
|
||||
else if (StringUtil.GetLength(MemberFirstName) > GetControlMaxLength(SaxDbDfn_Core.ColumnIdx.UserAccount_FirstName))
|
||||
responseData.SetControlError(nameof(MemberFirstName), Localiser["msg.validation.maximum.length", GetControlMaxLength(SaxDbDfn_Core.ColumnIdx.UserAccount_FirstName)]);
|
||||
}
|
||||
|
||||
// Member Last Name.
|
||||
if (MemberLastName != null && memberNameSupplied)
|
||||
{
|
||||
responseData.SetControlValue(nameof(MemberLastName), MemberLastName);
|
||||
if (StringUtil.IsEmpty(MemberLastName))
|
||||
responseData.SetControlError(nameof(MemberLastName), Localiser["msg.validation.mandatory.value"]);
|
||||
else if (StringUtil.GetLength(MemberLastName) > GetControlMaxLength(SaxDbDfn_Core.ColumnIdx.UserAccount_LastName))
|
||||
responseData.SetControlError(nameof(MemberLastName), Localiser["msg.validation.maximum.length", GetControlMaxLength(SaxDbDfn_Core.ColumnIdx.UserAccount_LastName)]);
|
||||
}
|
||||
|
||||
// Member Admin Comment.
|
||||
if (MemberAdminComment != null)
|
||||
{
|
||||
responseData.SetControlValue(nameof(MemberAdminComment), MemberAdminComment);
|
||||
if (!StringUtil.IsEmpty(MemberAdminComment) && StringUtil.GetLength(MemberAdminComment) > GetControlMaxLength(SaxDbDfn_Core.ColumnIdx.UserOrganisation_AdminComment))
|
||||
responseData.SetControlError(nameof(MemberAdminComment), Localiser["msg.validation.maximum.length", GetControlMaxLength(SaxDbDfn_Core.ColumnIdx.UserOrganisation_AdminComment)]);
|
||||
}
|
||||
|
||||
return !responseData.HasControlErrors();
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
}
|
||||
//=======================================================================
|
||||
}
|
||||
@@ -0,0 +1,119 @@
|
||||
using Sarand.Net.Standard.Base.App;
|
||||
using Sarand.Net.Standard.Base.Bus;
|
||||
using Sarand.Net.Standard.Base.Core;
|
||||
using Sarand.Net.Standard.Base.Utils;
|
||||
using Saxonite.Base.App;
|
||||
using Saxonite.Net.Core.Web.Base.App;
|
||||
using Saxonite.Net.Core.Web.Base.Controllers;
|
||||
using Saxonite.Net.Standard.Base.Bus;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Saxonite.Net.Core.Web.Online.Models
|
||||
{
|
||||
//=======================================================================
|
||||
public class Model_Organisation_Opportunities : SaxModel_Online
|
||||
{
|
||||
//-------------------------------------------------------------------
|
||||
// Construction.
|
||||
public Model_Organisation_Opportunities(SaxLocaliser localiser) :
|
||||
base(localiser)
|
||||
{
|
||||
//AdditionalFiles_CSS.Add("css/sax-org-opp.css");
|
||||
AdditionalFiles_JS.Add("js/sax-org-opp.js");
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// List configuration.
|
||||
public class OpportunityFilterData
|
||||
{
|
||||
public String OrganisationId { get; set; }
|
||||
public String OrganisationCaption { get; set; }
|
||||
public String Opportunity { get; set; }
|
||||
}
|
||||
public OpportunityFilterData Filter { get; } = new OpportunityFilterData();
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Opportunity properties.
|
||||
public String OpportunityId { get; set; }
|
||||
public String OpportunityExists { get; set; }
|
||||
// Opportunity properties.
|
||||
public String OpportunityOrganisationId { get; set; }
|
||||
// Sport.
|
||||
public String OpportunitySportId { get; set; }
|
||||
// Region.
|
||||
public String OpportunityRegionId { get; set; }
|
||||
// Opportunity Content.
|
||||
public String OpportunityTypeCode { get; set; }
|
||||
public String OpportunityPosition { get; set; }
|
||||
public String OpportunityOutline { get; set; }
|
||||
public String OpportunityStatusCode { get; set; }
|
||||
public SaStatus OpportunityStatus { get { return SacsSystem.GetStatusForCode(OpportunityStatusCode); } }
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Validation.
|
||||
//-------------------------------------------------------------------
|
||||
// Opportunity.
|
||||
public bool ValidateOpportunityData(SaxController_Base.AjaxResponse_Data responseData)
|
||||
{
|
||||
// Opportunity type.
|
||||
if (OpportunityTypeCode != null)
|
||||
{
|
||||
if (StringUtil.IsEmpty(OpportunityTypeCode))
|
||||
responseData.SetControlError(nameof(OpportunityTypeCode), Localiser["msg.validation.mandatory.value"]);
|
||||
}
|
||||
|
||||
// Opportunity position.
|
||||
if (OpportunityPosition != null)
|
||||
{
|
||||
responseData.SetControlValue(nameof(OpportunityPosition), OpportunityPosition);
|
||||
if (StringUtil.IsEmpty(OpportunityPosition))
|
||||
responseData.SetControlError(nameof(OpportunityPosition), Localiser["msg.validation.mandatory.value"]);
|
||||
else if (StringUtil.GetLength(OpportunityPosition) > GetControlMaxLength(SaxDbDfn_Core.ColumnIdx.OrganisationOpportunity_Position))
|
||||
responseData.SetControlError(nameof(OpportunityPosition), Localiser["msg.validation.maximum.length", GetControlMaxLength(SaxDbDfn_Core.ColumnIdx.OrganisationOpportunity_Position)]);
|
||||
}
|
||||
|
||||
// Opportunity outline.
|
||||
if (OpportunityOutline != null)
|
||||
{
|
||||
responseData.SetControlValue(nameof(OpportunityOutline), OpportunityOutline);
|
||||
if (StringUtil.IsEmpty(OpportunityOutline))
|
||||
responseData.SetControlError(nameof(OpportunityOutline), Localiser["msg.validation.mandatory.value"]);
|
||||
else if (StringUtil.GetLength(OpportunityOutline) > GetControlMaxLength(SaxDbDfn_Core.ColumnIdx.OrganisationOpportunity_Outline))
|
||||
responseData.SetControlError(nameof(OpportunityOutline), Localiser["msg.validation.maximum.length", GetControlMaxLength(SaxDbDfn_Core.ColumnIdx.OrganisationOpportunity_Outline)]);
|
||||
}
|
||||
|
||||
// Opportunity sport.
|
||||
if (OpportunitySportId != null)
|
||||
{
|
||||
SysId articleSportId = ExtractSysId(OpportunitySportId);
|
||||
if (!SysId.IsValid(articleSportId))
|
||||
responseData.SetControlError(nameof(OpportunitySportId), Localiser["msg.validation.mandatory.value"]);
|
||||
}
|
||||
|
||||
// Opportunity region.
|
||||
if (OpportunityRegionId != null)
|
||||
{
|
||||
SysId articleRegionId = ExtractSysId(OpportunityRegionId);
|
||||
if (!SysId.IsValid(articleRegionId))
|
||||
responseData.SetControlError(nameof(OpportunityRegionId), Localiser["msg.validation.mandatory.value"]);
|
||||
}
|
||||
|
||||
// Opportunity status.
|
||||
if (OpportunityStatusCode != null)
|
||||
{
|
||||
if (StringUtil.IsEmpty(OpportunityStatusCode))
|
||||
responseData.SetControlError(nameof(OpportunityStatusCode), Localiser["msg.validation.mandatory.value"]);
|
||||
else if (!SaxOrganisationOpportunity.ValidStatuses.Contains(OpportunityStatus))
|
||||
responseData.SetControlError(nameof(OpportunityStatusCode), Localiser["msg.validation.invalid.value"]);
|
||||
}
|
||||
|
||||
return !responseData.HasControlErrors();
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
}
|
||||
//=======================================================================
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
using Saxonite.Net.Core.Web.Base.App;
|
||||
using Saxonite.Net.Core.Web.Base.Models;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Saxonite.Net.Core.Web.Online.Models
|
||||
{
|
||||
//=======================================================================
|
||||
public class Model_Policies : SaxModel_Online
|
||||
{
|
||||
//-------------------------------------------------------------------
|
||||
// Construction.
|
||||
public Model_Policies(SaxLocaliser localiser) :
|
||||
base(localiser)
|
||||
{
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Properties.
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
}
|
||||
//=======================================================================
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
using Sarand.Net.Standard.Base.App;
|
||||
using Sarand.Net.Standard.Base.Bus;
|
||||
using Sarand.Net.Standard.Base.Core;
|
||||
using Sarand.Net.Standard.Base.Utils;
|
||||
using Saxonite.Base.App;
|
||||
using Saxonite.Net.Core.Web.Base.App;
|
||||
using Saxonite.Net.Core.Web.Base.Controllers;
|
||||
using Saxonite.Net.Standard.Base.Bus;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Saxonite.Net.Core.Web.Online.Models
|
||||
{
|
||||
//=======================================================================
|
||||
public class Model_Reference: SaxModel_Online
|
||||
{
|
||||
//-------------------------------------------------------------------
|
||||
// Construction.
|
||||
public Model_Reference(SaxLocaliser localiser) :
|
||||
base(localiser)
|
||||
{}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
}
|
||||
//=======================================================================
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
using Sarand.Net.Standard.Base.Bus;
|
||||
using Sarand.Net.Standard.Base.Core;
|
||||
using Sarand.Net.Standard.Base.Helpers;
|
||||
using Sarand.Net.Standard.Base.Utils;
|
||||
using Saxonite.Net.Core.Web.Base.App;
|
||||
using Saxonite.Net.Core.Web.Base.Controllers;
|
||||
using Saxonite.Net.Core.Web.Base.Models;
|
||||
using Saxonite.Net.Standard.Base.App;
|
||||
using Saxonite.Net.Standard.Base.Bus;
|
||||
using Saxonite.Net.Standard.Base.Helpers;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Saxonite.Net.Core.Web.Online.Models
|
||||
{
|
||||
//=======================================================================
|
||||
public class Model_Search_Organisations : SaxModel_Online
|
||||
{
|
||||
//-------------------------------------------------------------------
|
||||
// Construction.
|
||||
public Model_Search_Organisations(SaxLocaliser localiser) :
|
||||
base(localiser)
|
||||
{
|
||||
//AdditionalFiles_CSS.Add("css/sax-src-org.css");
|
||||
AdditionalFiles_JS.Add("js/sax-src-org.js");
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Page configuration.
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Form properties.
|
||||
public class FilterData
|
||||
{
|
||||
public String Organisation { get; set; }
|
||||
public String Type { get; set; }
|
||||
public String Category { get; set; }
|
||||
public String RegionId { get; set; }
|
||||
public String SportId { get; set; }
|
||||
}
|
||||
public FilterData Filter { get; } = new FilterData();
|
||||
public Sax.OrganisationType FilterOrganisationType { get { return (Sax.OrganisationType)OrganisationTypeCodes.GetTypeForCode(Filter.Type); } }
|
||||
public Sax.OrganisationCategory FilterOrganisationCategory { get { return (Sax.OrganisationCategory)OrganisationCategoryCodes.GetTypeForCode(Filter.Category); } }
|
||||
public SysId FilterSportId { get { return ExtractSysId(Filter.SportId); } }
|
||||
public SysId FilterRegionId { get { return ExtractSysId(Filter.RegionId); } }
|
||||
public String OrganisationId { get; set; }
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Validation.
|
||||
//-------------------------------------------------------------------
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
}
|
||||
//=======================================================================
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
using Sarand.Net.Standard.Base.Bus;
|
||||
using Sarand.Net.Standard.Base.Core;
|
||||
using Sarand.Net.Standard.Base.Helpers;
|
||||
using Sarand.Net.Standard.Base.Utils;
|
||||
using Saxonite.Net.Core.Web.Base.App;
|
||||
using Saxonite.Net.Core.Web.Base.Controllers;
|
||||
using Saxonite.Net.Core.Web.Base.Models;
|
||||
using Saxonite.Net.Standard.Base.App;
|
||||
using Saxonite.Net.Standard.Base.Bus;
|
||||
using Saxonite.Net.Standard.Base.Helpers;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Saxonite.Net.Core.Web.Online.Models
|
||||
{
|
||||
//=======================================================================
|
||||
public class Model_Search_Users : SaxModel_Online
|
||||
{
|
||||
//-------------------------------------------------------------------
|
||||
// Construction.
|
||||
public Model_Search_Users(SaxLocaliser localiser) :
|
||||
base(localiser)
|
||||
{
|
||||
//AdditionalFiles_CSS.Add("css/sax-src-usr.css");
|
||||
AdditionalFiles_JS.Add("js/sax-src-usr.js");
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Page configuration.
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Form properties.
|
||||
public class FilterData
|
||||
{
|
||||
public String User { get; set; }
|
||||
public String RegionId { get; set; }
|
||||
public String SportId { get; set; }
|
||||
}
|
||||
public FilterData Filter { get; } = new FilterData();
|
||||
public SysId FilterSportId { get { return ExtractSysId(Filter.SportId); } }
|
||||
public SysId FilterRegionId { get { return ExtractSysId(Filter.RegionId); } }
|
||||
public String UserId { get; set; }
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Validation.
|
||||
//-------------------------------------------------------------------
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
}
|
||||
//=======================================================================
|
||||
}
|
||||
@@ -0,0 +1,113 @@
|
||||
using Sarand.Net.Standard.Base.Core;
|
||||
using Sarand.Net.Standard.Base.Helpers;
|
||||
using Sarand.Net.Standard.Base.Utils;
|
||||
using Saxonite.Net.Core.Web.Base.App;
|
||||
using Saxonite.Net.Core.Web.Base.Controllers;
|
||||
using Saxonite.Net.Core.Web.Base.Models;
|
||||
using Saxonite.Net.Standard.Base.Bus;
|
||||
using Saxonite.Net.Standard.Base.Helpers;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Saxonite.Net.Core.Web.Online.Models
|
||||
{
|
||||
//=======================================================================
|
||||
public class Model_Security : SaxModel_Online
|
||||
{
|
||||
//-------------------------------------------------------------------
|
||||
// Construction.
|
||||
public Model_Security(SaxLocaliser localiser) :
|
||||
base(localiser)
|
||||
{
|
||||
//AdditionalFiles_CSS.Add("css/sax-security.css");
|
||||
AdditionalFiles_JS.Add("js/sax-security.js");
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Page configuration.
|
||||
public bool RequestPasswordMode { get { return !StringUtil.IsEmpty(rpe); } }
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Form properties.
|
||||
public String EmailAddress { get; set; }
|
||||
public String PasswordCurrent { get; set; }
|
||||
public String Password { get; set; }
|
||||
public String PasswordConfirm { get; set; }
|
||||
public bool KeepMeSignedIn { get; set; }
|
||||
/// <summary>Request Password Encrypted params - to allow Change Password without session or requiring old password.</summary>
|
||||
public String rpe { get; set; }
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Validation.
|
||||
//-------------------------------------------------------------------
|
||||
// Sign-in.
|
||||
public bool ValidateSignInData(SaxController_Base.AjaxResponse_Data responseData)
|
||||
{
|
||||
// Email address.
|
||||
responseData.SetControlValue(nameof(EmailAddress), EmailAddress);
|
||||
if (StringUtil.IsEmpty(EmailAddress))
|
||||
responseData.SetControlError(nameof(EmailAddress), Localiser["msg.validation.mandatory.value"]);
|
||||
else if (!SacsDataValidationHelper.IsValidEmailAddress(EmailAddress))
|
||||
responseData.SetControlError(nameof(EmailAddress), Localiser["msg.validation.invalid.value"]);
|
||||
|
||||
// Password.
|
||||
// NB Do not return the password value in the response.
|
||||
if (StringUtil.IsEmpty(Password))
|
||||
responseData.SetControlError(nameof(Password), Localiser["msg.validation.mandatory.value"]);
|
||||
|
||||
return !responseData.HasControlErrors();
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Change password.
|
||||
public bool ValidateChangePasswordData(SaxUserAccount userAccount, SaxController_Base.AjaxResponse_Data responseData)
|
||||
{
|
||||
// Validate Passwords.
|
||||
// NB Do not return the password values in the response.
|
||||
// NB Only validate populated values - any null values are not part of the form for this request.
|
||||
// - 'Current' password is not shown when changing password from 'Request Password' email link.
|
||||
if (PasswordCurrent != null && StringUtil.IsEmpty(PasswordCurrent))
|
||||
responseData.SetControlError(nameof(PasswordCurrent), Localiser["msg.validation.mandatory.value"]);
|
||||
if (StringUtil.IsEmpty(Password))
|
||||
responseData.SetControlError(nameof(Password), Localiser["msg.validation.mandatory.value"]);
|
||||
if (StringUtil.IsEmpty(PasswordConfirm))
|
||||
responseData.SetControlError(nameof(PasswordConfirm), Localiser["msg.validation.mandatory.value"]);
|
||||
if (!StringUtil.IsEmpty(Password) && !StringUtil.IsEmpty(PasswordConfirm))
|
||||
{
|
||||
if (!Password.Equals(PasswordConfirm))
|
||||
responseData.SetControlError(nameof(PasswordConfirm), Localiser["msg.validation.invalid.value"]);
|
||||
if (!SaxPasswordHelper.IsValidPassword(Password))
|
||||
responseData.SetControlError(nameof(PasswordConfirm), Localiser.GetText("msg.warn.password.invalid", new object[] { SaxPasswordHelper.Params.MinLength, SaxPasswordHelper.Params.MinLengthNoComplexity }));
|
||||
}
|
||||
|
||||
if (!responseData.HasControlErrors())
|
||||
{
|
||||
if (PasswordCurrent != null && !SaxPasswordHelper.VerifyHashedPassword(userAccount, PasswordCurrent))
|
||||
responseData.SetControlError(nameof(PasswordCurrent), Localiser["security.change.password.current.invalid"]);
|
||||
if (SaxPasswordHelper.VerifyHashedPassword(userAccount, Password))
|
||||
responseData.SetControlError(nameof(Password), Localiser["security.change.password.not.changed"]);
|
||||
}
|
||||
|
||||
return !responseData.HasControlErrors();
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Request Password.
|
||||
public bool ValidateRequestPasswordData(SaxController_Base.AjaxResponse_Data responseData)
|
||||
{
|
||||
// Email address.
|
||||
responseData.SetControlValue(nameof(EmailAddress), EmailAddress);
|
||||
if (StringUtil.IsEmpty(EmailAddress))
|
||||
responseData.SetControlError(nameof(EmailAddress), Localiser["msg.validation.mandatory.value"]);
|
||||
else if (!SacsDataValidationHelper.IsValidEmailAddress(EmailAddress))
|
||||
responseData.SetControlError(nameof(EmailAddress), Localiser["msg.validation.invalid.value"]);
|
||||
|
||||
return !responseData.HasControlErrors();
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
}
|
||||
//=======================================================================
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
using Sarand.Net.Standard.Base.Core;
|
||||
using Sarand.Net.Standard.Base.Utils;
|
||||
using Saxonite.Base.App;
|
||||
using Saxonite.Net.Core.Web.Base.App;
|
||||
using Saxonite.Net.Core.Web.Base.Controllers;
|
||||
using Saxonite.Net.Core.Web.Base.Models;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using static Saxonite.Net.Standard.Base.App.Sax.Config;
|
||||
|
||||
namespace Saxonite.Net.Core.Web.Online.Models
|
||||
{
|
||||
//=======================================================================
|
||||
public class Model_Support : SaxModel_Online
|
||||
{
|
||||
//-------------------------------------------------------------------
|
||||
// Construction.
|
||||
public Model_Support(SaxLocaliser localiser) :
|
||||
base(localiser)
|
||||
{
|
||||
AdditionalFiles_CSS.Add("css/sax-appl.css");
|
||||
AdditionalFiles_JS.Add("js/sax-appl.js");
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// User Report proerties.
|
||||
public class UserReportData
|
||||
{
|
||||
public String Id { get; set; }
|
||||
public String Exists { get; set; }
|
||||
public String UserAccountId { get; set; }
|
||||
public String ReportType { get; set; }
|
||||
public String Title { get; set; }
|
||||
public String Report { get; set; }
|
||||
// Filter.
|
||||
public class UserReportFilterData
|
||||
{
|
||||
public String User { get; set; }
|
||||
public String Report { get; set; }
|
||||
}
|
||||
public UserReportFilterData Filter { get; } = new UserReportFilterData();
|
||||
}
|
||||
public UserReportData UserReport { get; } = new UserReportData();
|
||||
public Standard.Base.App.Sax.UserReportType GetReportType() { return (Standard.Base.App.Sax.UserReportType)(UserReportTypeCodes.GetTypeForCode(UserReport.ReportType)); }
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Validate User Report data.
|
||||
public bool ValidateUserReportData(SaxController_Base.AjaxResponse_Data responseData)
|
||||
{
|
||||
|
||||
// Report Type.
|
||||
String controlName = "UserReportType";
|
||||
if (UserReport.ReportType != null)
|
||||
{
|
||||
if (StringUtil.IsEmpty(UserReport.ReportType))
|
||||
responseData.SetControlError(controlName, Localiser["msg.validation.mandatory.value"]);
|
||||
}
|
||||
|
||||
// Report Title.
|
||||
controlName = "UserReportTitle";
|
||||
if (UserReport.Title != null)
|
||||
{
|
||||
responseData.SetControlValue(controlName, UserReport.Title);
|
||||
if (StringUtil.IsEmpty(UserReport.Title))
|
||||
responseData.SetControlError(controlName, Localiser["msg.validation.mandatory.value"]);
|
||||
else if (StringUtil.GetLength(UserReport.Title) > GetControlMaxLength(SaxDbDfn_Support.ColumnIdx.UserReport_Title))
|
||||
responseData.SetControlError(controlName, Localiser["msg.validation.maximum.length", GetControlMaxLength(SaxDbDfn_Support.ColumnIdx.UserReport_Title)]);
|
||||
}
|
||||
|
||||
return !responseData.HasControlErrors();
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
}
|
||||
//=======================================================================
|
||||
}
|
||||
@@ -0,0 +1,112 @@
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Sarand.Net.Standard.Base.Bus;
|
||||
using Sarand.Net.Standard.Base.Core;
|
||||
using Sarand.Net.Standard.Base.Utils;
|
||||
using Saxonite.Base.App;
|
||||
using Saxonite.Net.Core.Web.Base.App;
|
||||
using Saxonite.Net.Core.Web.Base.Controllers;
|
||||
using Saxonite.Net.Core.Web.Base.Models;
|
||||
using Saxonite.Net.Standard.Base.App;
|
||||
using Saxonite.Net.Standard.Base.Bus;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Saxonite.Net.Core.Web.Online.Models
|
||||
{
|
||||
//=======================================================================
|
||||
public class Model_UserEligibility : SaxModel_Online
|
||||
{
|
||||
//-------------------------------------------------------------------
|
||||
// Construction.
|
||||
public Model_UserEligibility(SaxLocaliser localiser) :
|
||||
base(localiser)
|
||||
{
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// User properties.
|
||||
public class UserAccountData
|
||||
{
|
||||
public String Id { get; set; }
|
||||
}
|
||||
public UserAccountData UserAccount { get; } = new UserAccountData();
|
||||
|
||||
// Eligibility properties.
|
||||
public class EligibilityData
|
||||
{
|
||||
/// <summary>User Experience Id.</summary>
|
||||
public String Id { get; set; }
|
||||
/// <summary>Flag to indicate whether item is being updated.</summary>
|
||||
public String Exists { get; set; }
|
||||
/// <summary>User Experience Region Id.</summary>
|
||||
public String RegionId { get; set; }
|
||||
/// <summary>User Experience Type.</summary>
|
||||
public String Type { get; set; }
|
||||
/// <summary>User Experience Info.</summary>
|
||||
public String Info { get; set; }
|
||||
public Sax.EligibilityType getEligibilityType()
|
||||
{
|
||||
if (Type != null)
|
||||
return (Sax.EligibilityType)SaxSystem.GetCodesOfType(Sax.CodeType.EligibilityType).GetTypeForCode(Type);
|
||||
return Sax.EligibilityType.Unknown;
|
||||
}
|
||||
/// <summary>User Experience Expiry date.</summary>
|
||||
public String ExpiresOn { get; set; }
|
||||
}
|
||||
public EligibilityData Eligibility { get; } = new EligibilityData();
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Validate model data.
|
||||
//-------------------------------------------------------------------
|
||||
// Validate eligibility details.
|
||||
public bool ValidateEligibilityDetails(SaxController_Base.AjaxResponse_Data responseData)
|
||||
{
|
||||
// Eligibility type.
|
||||
String controlName = "EligibilityType";
|
||||
if (Eligibility.Type == null || Eligibility.getEligibilityType() <= 0)
|
||||
{
|
||||
responseData.SetControlError(controlName, Localiser["msg.validation.mandatory.value"]);
|
||||
}
|
||||
|
||||
// Eligibility Region - mandatory for new eligibility.
|
||||
controlName = "EligibilityRegion";
|
||||
SysId eligibilityRegionId = ExtractSysId(Eligibility.RegionId);
|
||||
if ((Eligibility.RegionId == null || !SysId.IsValid(eligibilityRegionId)) && !StringUtil.ToBool(Eligibility.Exists))
|
||||
{
|
||||
responseData.SetControlError(controlName, Localiser["msg.validation.mandatory.value"]);
|
||||
}
|
||||
else if (Eligibility.RegionId != null)
|
||||
{
|
||||
SaxRegion.Data eligibilityRegion = Internals.GetRegion(eligibilityRegionId);
|
||||
if (eligibilityRegion == null)
|
||||
responseData.SetControlError(controlName, Localiser["msg.validation.invalid.value"]);
|
||||
}
|
||||
|
||||
// Eligibility info.
|
||||
controlName = "EligibilityInfo";
|
||||
if (Eligibility.Info != null)
|
||||
{
|
||||
responseData.SetControlValue(controlName, Eligibility.Info);
|
||||
if (StringUtil.GetLength(Eligibility.Info) > GetControlMaxLength(SaxDbDfn_Core.ColumnIdx.UserEligibility_Info))
|
||||
responseData.SetControlError(controlName, Localiser["msg.validation.maximum.length", GetControlMaxLength(SaxDbDfn_Core.ColumnIdx.UserEligibility_Info)]);
|
||||
}
|
||||
|
||||
// Eligibility Expiry date.
|
||||
controlName = "EligibilityExpiry";
|
||||
if (Eligibility.ExpiresOn != null)
|
||||
{
|
||||
if (!StringUtil.IsBlank(Eligibility.ExpiresOn) && !DateUtil.IsValid(ParseDateFromForm(Eligibility.ExpiresOn)))
|
||||
{
|
||||
responseData.SetControlError(controlName, Localiser["msg.validation.invalid.value"]);
|
||||
}
|
||||
}
|
||||
return !responseData.HasControlErrors();
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
}
|
||||
//=======================================================================
|
||||
}
|
||||
@@ -0,0 +1,102 @@
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Sarand.Net.Standard.Base.Bus;
|
||||
using Sarand.Net.Standard.Base.Core;
|
||||
using Sarand.Net.Standard.Base.Utils;
|
||||
using Saxonite.Base.App;
|
||||
using Saxonite.Net.Core.Web.Base.App;
|
||||
using Saxonite.Net.Core.Web.Base.Controllers;
|
||||
using Saxonite.Net.Core.Web.Base.Models;
|
||||
using Saxonite.Net.Standard.Base.App;
|
||||
using Saxonite.Net.Standard.Base.Bus;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Saxonite.Net.Core.Web.Online.Models
|
||||
{
|
||||
//=======================================================================
|
||||
public class Model_UserSportContact: SaxModel_Online
|
||||
{
|
||||
//-------------------------------------------------------------------
|
||||
// Construction.
|
||||
public Model_UserSportContact(SaxLocaliser localiser) :
|
||||
base(localiser)
|
||||
{
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// User Sports Contact properties.
|
||||
public class SportContactData
|
||||
{
|
||||
public String Type { get; set; }
|
||||
public String EmailAddress { get; set; }
|
||||
public String Title { get; set; }
|
||||
public String FirstName { get; set; }
|
||||
public String LastName { get; set; }
|
||||
}
|
||||
public SportContactData SportContact { get; } = new SportContactData();
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Validate User Sport Contact data.
|
||||
public bool ValidateUserSportContactData(SaxController_Base.AjaxResponse_Data responseData)
|
||||
{
|
||||
// Contact Type.
|
||||
String controlName = "ContactType";
|
||||
if (SportContact.Type != null)
|
||||
{
|
||||
// Contact Type is mandatory.
|
||||
if (StringUtil.IsBlank(SportContact.Type))
|
||||
responseData.SetControlError(controlName, Localiser["msg.validation.invalid.value"]);
|
||||
}
|
||||
|
||||
// Email.
|
||||
controlName = "ContactEmailAddress";
|
||||
if (SportContact.EmailAddress != null)
|
||||
{
|
||||
responseData.SetControlValue(controlName, SportContact.EmailAddress);
|
||||
// Email is optional.
|
||||
if (StringUtil.GetLength(SportContact.EmailAddress) > GetControlMaxLength(SaxDbDfn_Core.ColumnIdx.UserAccount_EmailAddress))
|
||||
responseData.SetControlError(controlName, Localiser["msg.validation.maximum.length", GetControlMaxLength(SaxDbDfn_Core.ColumnIdx.UserAccount_EmailAddress)]);
|
||||
}
|
||||
|
||||
// Title.
|
||||
controlName = "ContactTitle";
|
||||
if (SportContact.Title != null)
|
||||
{
|
||||
// Title is selected from dropdown so no validation should be required.
|
||||
if (StringUtil.GetLength(SportContact.Title) > GetControlMaxLength(SaxDbDfn_Core.ColumnIdx.UserAccount_Title))
|
||||
responseData.SetControlError(controlName, Localiser["msg.validation.maximum.length", GetControlMaxLength(SaxDbDfn_Core.ColumnIdx.UserAccount_Title)]);
|
||||
}
|
||||
|
||||
// First Name.
|
||||
controlName = "ContactFirstName";
|
||||
if (SportContact.FirstName != null)
|
||||
{
|
||||
responseData.SetControlValue(controlName, SportContact.FirstName);
|
||||
// First name is mandatory.
|
||||
if (StringUtil.IsBlank(SportContact.FirstName))
|
||||
responseData.SetControlError(controlName, Localiser["msg.validation.invalid.value"]);
|
||||
else if (StringUtil.GetLength(SportContact.FirstName) > GetControlMaxLength(SaxDbDfn_Core.ColumnIdx.UserAccount_FirstName))
|
||||
responseData.SetControlError(controlName, Localiser["msg.validation.maximum.length", GetControlMaxLength(SaxDbDfn_Core.ColumnIdx.UserAccount_FirstName)]);
|
||||
}
|
||||
|
||||
// Last Name.
|
||||
controlName = "ContactLastName";
|
||||
if (SportContact.LastName != null)
|
||||
{
|
||||
responseData.SetControlValue(controlName, SportContact.LastName);
|
||||
// Last name is mandatory.
|
||||
if (StringUtil.IsBlank(SportContact.LastName))
|
||||
responseData.SetControlError(controlName, Localiser["msg.validation.invalid.value"]);
|
||||
else if (StringUtil.GetLength(SportContact.LastName) > GetControlMaxLength(SaxDbDfn_Core.ColumnIdx.UserAccount_LastName))
|
||||
responseData.SetControlError(controlName, Localiser["msg.validation.maximum.length", GetControlMaxLength(SaxDbDfn_Core.ColumnIdx.UserAccount_LastName)]);
|
||||
}
|
||||
|
||||
return !responseData.HasControlErrors();
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
}
|
||||
//=======================================================================
|
||||
}
|
||||
@@ -0,0 +1,126 @@
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Sarand.Net.Standard.Base.Bus;
|
||||
using Sarand.Net.Standard.Base.Core;
|
||||
using Sarand.Net.Standard.Base.Utils;
|
||||
using Saxonite.Base.App;
|
||||
using Saxonite.Net.Core.Web.Base.App;
|
||||
using Saxonite.Net.Core.Web.Base.Controllers;
|
||||
using Saxonite.Net.Core.Web.Base.Models;
|
||||
using Saxonite.Net.Standard.Base.App;
|
||||
using Saxonite.Net.Standard.Base.Bus;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Saxonite.Net.Core.Web.Online.Models
|
||||
{
|
||||
//=======================================================================
|
||||
public class Model_UserSportExperience : SaxModel_Online
|
||||
{
|
||||
//-------------------------------------------------------------------
|
||||
// Construction.
|
||||
public Model_UserSportExperience(SaxLocaliser localiser) :
|
||||
base(localiser)
|
||||
{
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// User Sports Experience Properties.
|
||||
public String UserSportExperienceId { get; set; }
|
||||
public String UserSportExperienceExists { get; set; }
|
||||
public String UserSportId { get; set; }
|
||||
public String ExperiencePeriodFrom { get; set; }
|
||||
public String ExperiencePeriodTo { get; set; }
|
||||
public String ExperienceOrganisationId { get; set; }
|
||||
public String ExperienceOrganisationName { get; set; }
|
||||
public String ExperienceSummary { get; set; }
|
||||
public String ExperienceTeam { get; set; }
|
||||
public String ExperienceLeague { get; set; }
|
||||
public String ExperienceSpeciality { get; set; }
|
||||
public String ExperienceAwards{ get; set; }
|
||||
// Regions.
|
||||
public String ExperienceRegionIdNation { get; set; }
|
||||
public String ExperienceRegionIdProvince { get; set; }
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Validate User Sport Experience data.
|
||||
public bool ValidateProfileSportData(SaxController_Base.AjaxResponse_Data responseData)
|
||||
{
|
||||
// Period dates.
|
||||
DateTime periodFrom = ParseDateFromForm(ExperiencePeriodFrom);
|
||||
DateTime periodTo = ParseDateFromForm(ExperiencePeriodTo);
|
||||
|
||||
// Period From.
|
||||
if (ExperiencePeriodFrom != null)
|
||||
{
|
||||
// Period from date is mandatory.
|
||||
if (!DateUtil.IsValid(periodFrom))
|
||||
responseData.SetControlError(nameof(ExperiencePeriodFrom), Localiser["msg.validation.invalid.value"]);
|
||||
}
|
||||
|
||||
// Period To.
|
||||
if (ExperiencePeriodTo != null)
|
||||
{
|
||||
// Period to date is optional must not be before the from date.
|
||||
if (DateUtil.IsValid(periodTo) && DateUtil.IsValid(periodFrom) && periodTo.CompareTo(periodFrom) < 0)
|
||||
responseData.SetControlError(nameof(ExperiencePeriodTo), Localiser["msg.validation.invalid.value"]);
|
||||
}
|
||||
|
||||
// Organisation name.
|
||||
if (ExperienceOrganisationName != null)
|
||||
{
|
||||
responseData.SetControlValue(nameof(ExperienceOrganisationName), ExperienceOrganisationName);
|
||||
if (StringUtil.GetLength(ExperienceOrganisationName) > GetControlMaxLength(SaxDbDfn_Core.ColumnIdx.UserSportExperience_OrganisationName))
|
||||
responseData.SetControlError(nameof(ExperienceOrganisationName), Localiser["msg.validation.maximum.length", GetControlMaxLength(SaxDbDfn_Core.ColumnIdx.UserSportExperience_OrganisationName)]);
|
||||
}
|
||||
|
||||
// Summary.
|
||||
if (ExperienceSummary != null)
|
||||
{
|
||||
responseData.SetControlValue(nameof(ExperienceSummary), ExperienceSummary);
|
||||
if (StringUtil.IsEmpty(ExperienceSummary))
|
||||
responseData.SetControlError(nameof(ExperienceSummary), Localiser["msg.validation.mandatory.value"]);
|
||||
else if (StringUtil.GetLength(ExperienceSummary) > GetControlMaxLength(SaxDbDfn_Core.ColumnIdx.UserSportExperience_Summary))
|
||||
responseData.SetControlError(nameof(ExperienceSummary), Localiser["msg.validation.maximum.length", GetControlMaxLength(SaxDbDfn_Core.ColumnIdx.UserSportExperience_Summary)]);
|
||||
}
|
||||
|
||||
// Team.
|
||||
if (ExperienceTeam != null)
|
||||
{
|
||||
responseData.SetControlValue(nameof(ExperienceTeam), ExperienceTeam);
|
||||
if (StringUtil.GetLength(ExperienceTeam) > GetControlMaxLength(SaxDbDfn_Core.ColumnIdx.UserSportExperience_Team))
|
||||
responseData.SetControlError(nameof(ExperienceTeam), Localiser["msg.validation.maximum.length", GetControlMaxLength(SaxDbDfn_Core.ColumnIdx.UserSportExperience_Team)]);
|
||||
}
|
||||
|
||||
// League.
|
||||
if (ExperienceLeague != null)
|
||||
{
|
||||
responseData.SetControlValue(nameof(ExperienceLeague), ExperienceLeague);
|
||||
if (StringUtil.GetLength(ExperienceLeague) > GetControlMaxLength(SaxDbDfn_Core.ColumnIdx.UserSportExperience_League))
|
||||
responseData.SetControlError(nameof(ExperienceLeague), Localiser["msg.validation.maximum.length", GetControlMaxLength(SaxDbDfn_Core.ColumnIdx.UserSportExperience_League)]);
|
||||
}
|
||||
|
||||
// Speciality.
|
||||
if (ExperienceSpeciality != null)
|
||||
{
|
||||
responseData.SetControlValue(nameof(ExperienceSpeciality), ExperienceSpeciality);
|
||||
if (StringUtil.GetLength(ExperienceSpeciality) > GetControlMaxLength(SaxDbDfn_Core.ColumnIdx.UserSportExperience_Speciality))
|
||||
responseData.SetControlError(nameof(ExperienceSpeciality), Localiser["msg.validation.maximum.length", GetControlMaxLength(SaxDbDfn_Core.ColumnIdx.UserSportExperience_Speciality)]);
|
||||
}
|
||||
|
||||
// Awards.
|
||||
if (ExperienceAwards != null)
|
||||
{
|
||||
responseData.SetControlValue(nameof(ExperienceAwards), ExperienceAwards);
|
||||
if (StringUtil.GetLength(ExperienceAwards) > GetControlMaxLength(SaxDbDfn_Core.ColumnIdx.UserSportExperience_Awards))
|
||||
responseData.SetControlError(nameof(ExperienceAwards), Localiser["msg.validation.maximum.length", GetControlMaxLength(SaxDbDfn_Core.ColumnIdx.UserSportExperience_Awards)]);
|
||||
}
|
||||
|
||||
return !responseData.HasControlErrors();
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
}
|
||||
//=======================================================================
|
||||
}
|
||||
@@ -0,0 +1,315 @@
|
||||
using Sacs.Web.Components;
|
||||
using Sarand.Net.Standard.Base.App;
|
||||
using Sarand.Net.Standard.Base.Bus;
|
||||
using Sarand.Net.Standard.Base.Helpers;
|
||||
using Sarand.Net.Standard.Base.Utils;
|
||||
using Saxonite.Net.Core.Web.Base.App;
|
||||
using Saxonite.Net.Core.Web.Base.Controllers;
|
||||
using Saxonite.Net.Core.Web.Base.Models;
|
||||
using Saxonite.Net.Core.Web.Online.App;
|
||||
using Saxonite.Net.Standard.Base.App;
|
||||
using Saxonite.Net.Standard.Base.Bus;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Specialized;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Saxonite.Net.Core.Web.Online.Models
|
||||
{
|
||||
//=======================================================================
|
||||
public class SaxModel_Online : SaxModel_Base
|
||||
{
|
||||
//-------------------------------------------------------------------
|
||||
// Data members.
|
||||
private class UserCanManageOptions
|
||||
{
|
||||
public bool? OrganisationMembers { get; set; } = null;
|
||||
public bool? OrganisationOpportunities { get; set; } = null;
|
||||
public bool? OrganisationSchedule { get; set; } = null;
|
||||
public bool? OrganisationArticles { get; set; } = null;
|
||||
}
|
||||
private readonly UserCanManageOptions userCanManage = new UserCanManageOptions();
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Protected construction.
|
||||
protected SaxModel_Online(SaxLocaliser localiser) :
|
||||
base(localiser)
|
||||
{
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Properties.
|
||||
//-------------------------------------------------------------------
|
||||
// Session.
|
||||
public SaxSessionData_Online SessionData_Online { get { return SessionData as SaxSessionData_Online; } }
|
||||
public SysId SessionUserAccountId { get { return SessionData_Online?.User?.UserAccountId ?? null; } }
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Menu options.
|
||||
public bool OrganisationMembersAllowed { get { return UserCanManageOrganisationMembers; } }
|
||||
public bool ArticlesAllowed { get { return UserIsJournalist || UserCanManageOrganisationArticles; } }
|
||||
public bool OrganisationOpportunitiesAllowed { get { return UserCanManageOrganisationOpportunities; } }
|
||||
public bool OrganisationEventsAllowed { get { return UserCanManageOrganisationSchedule; } }
|
||||
// Support menu is for admin reviewers only.
|
||||
public bool SupportMenuAllowed { get { return SessionData_Online?.User.SupportMenuAllowed ?? false; } }
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Security profile.
|
||||
public bool UserIsJournalist { get { return SessionData != null && SessionData.User != null && SessionData.User.IsJournalist; } }
|
||||
public bool UserCanManageOrganisationMembers
|
||||
{
|
||||
get
|
||||
{
|
||||
if (userCanManage.OrganisationMembers == null && ValidUserSession)
|
||||
{
|
||||
SaxUserOrganisation.Params prmUserOrganisation = new SaxUserOrganisation.Params();
|
||||
prmUserOrganisation.UserAccountIdsIncluded.Add(SessionUserAccountId);
|
||||
prmUserOrganisation.OrganisationMembersOnly = true;
|
||||
prmUserOrganisation.OrganisationRolesAny.Add(Sax.OrganisationRole.Admin);
|
||||
prmUserOrganisation.OrganisationRolesAny.Add(Sax.OrganisationRole.MemberAdmin);
|
||||
prmUserOrganisation.StatusCat = SaxUserOrganisation.StatusCat.ActiveOnly;
|
||||
userCanManage.OrganisationMembers = (AccountMgr.GetUserOrganisationCount(prmUserOrganisation) > 0);
|
||||
}
|
||||
return userCanManage.OrganisationMembers == true ? true : false;
|
||||
}
|
||||
}
|
||||
public bool UserCanManageOrganisationOpportunities
|
||||
{
|
||||
get
|
||||
{
|
||||
if (userCanManage.OrganisationOpportunities == null && ValidUserSession)
|
||||
{
|
||||
SaxUserOrganisation.Params prmUserOrganisation = new SaxUserOrganisation.Params();
|
||||
prmUserOrganisation.UserAccountIdsIncluded.Add(SessionUserAccountId);
|
||||
prmUserOrganisation.OrganisationMembersOnly = true;
|
||||
prmUserOrganisation.OrganisationRolesAny.Add(Sax.OrganisationRole.Admin);
|
||||
prmUserOrganisation.OrganisationRolesAny.Add(Sax.OrganisationRole.OpportunityAdmin);
|
||||
prmUserOrganisation.StatusCat = SaxUserOrganisation.StatusCat.ActiveOnly;
|
||||
userCanManage.OrganisationOpportunities = (AccountMgr.GetUserOrganisationCount(prmUserOrganisation) > 0);
|
||||
}
|
||||
return userCanManage.OrganisationOpportunities == true ? true : false;
|
||||
}
|
||||
}
|
||||
public bool UserCanManageOrganisationSchedule
|
||||
{
|
||||
get
|
||||
{
|
||||
if (userCanManage.OrganisationSchedule == null && ValidUserSession)
|
||||
{
|
||||
SaxUserOrganisation.Params prmUserOrganisation = new SaxUserOrganisation.Params();
|
||||
prmUserOrganisation.UserAccountIdsIncluded.Add(SessionUserAccountId);
|
||||
prmUserOrganisation.OrganisationMembersOnly = true;
|
||||
prmUserOrganisation.OrganisationRolesAny.Add(Sax.OrganisationRole.Admin);
|
||||
prmUserOrganisation.OrganisationRolesAny.Add(Sax.OrganisationRole.ScheduleAdmin);
|
||||
prmUserOrganisation.StatusCat = SaxUserOrganisation.StatusCat.ActiveOnly;
|
||||
userCanManage.OrganisationSchedule = (AccountMgr.GetUserOrganisationCount(prmUserOrganisation) > 0);
|
||||
}
|
||||
return userCanManage.OrganisationSchedule == true ? true : false;
|
||||
}
|
||||
}
|
||||
public bool UserCanManageOrganisationArticles
|
||||
{
|
||||
get
|
||||
{
|
||||
if (userCanManage.OrganisationArticles == null && ValidUserSession)
|
||||
{
|
||||
SaxUserOrganisation.Params prmUserOrganisation = new SaxUserOrganisation.Params();
|
||||
prmUserOrganisation.UserAccountIdsIncluded.Add(SessionUserAccountId);
|
||||
prmUserOrganisation.OrganisationMembersOnly = true;
|
||||
prmUserOrganisation.OrganisationRolesAny.Add(Sax.OrganisationRole.Admin);
|
||||
prmUserOrganisation.OrganisationRolesAny.Add(Sax.OrganisationRole.ArticleAdmin);
|
||||
prmUserOrganisation.StatusCat = SaxUserOrganisation.StatusCat.ActiveOnly;
|
||||
userCanManage.OrganisationArticles = (AccountMgr.GetUserOrganisationCount(prmUserOrganisation) > 0);
|
||||
}
|
||||
return userCanManage.OrganisationArticles == true ? true : false;
|
||||
}
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Item Id Obfuscation.
|
||||
//-------------------------------------------------------------------
|
||||
public SysId ExtractSysId(String idx)
|
||||
{
|
||||
String fn = GetType().Name + ".ExtractSysId";
|
||||
if (StringUtil.IsEmpty(idx)) return null;
|
||||
|
||||
// Numeric values are assumed to be unencrypted Ids.
|
||||
if (StringUtil.IsNumeric(idx))
|
||||
return SysId.ToSysId(idx);
|
||||
|
||||
try
|
||||
{
|
||||
// Attempt to decrypt.
|
||||
SysId id = DecryptId(idx);
|
||||
if (SysId.IsValid(id))
|
||||
return id;
|
||||
}
|
||||
catch (Exception exc)
|
||||
{
|
||||
SaLogger.Warn(fn + " " + ExceptionUtil.GetErrorStateMessage(exc));
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Id encryption.
|
||||
// To obfuscate Id values that are sent to and from the browser.
|
||||
public static String Base64Key_IdObfuscation = SacsEncryptionHelper.EncodePlainKey("|SaxOnIte.Onl1n3-iD+0bfuscAtion|", SacsEncryptionHelper.KeyLength);
|
||||
private const String Purpose_IdObfuscation = "Saxonite.Online.IdObfuscation";
|
||||
public static String ParamName_IdObfuscation_Id { get; } = "iob";
|
||||
public String EncryptId(SysId id)
|
||||
{
|
||||
if (!SysId.IsValid(id)) return "";
|
||||
NameValueCollection idObfuscationParams = new NameValueCollection();
|
||||
idObfuscationParams.Add(ParamName_IdObfuscation_Id, SysId.ToString(id));
|
||||
return SaxController_Base.EncryptParameters(idObfuscationParams, Base64Key_IdObfuscation, Purpose_IdObfuscation);
|
||||
}
|
||||
public SysId DecryptId(String encryptedId)
|
||||
{
|
||||
if (StringUtil.IsEmpty(encryptedId))
|
||||
return new SysId();
|
||||
if (StringUtil.IsNumeric(encryptedId))
|
||||
return SysId.ToSysId(encryptedId);
|
||||
NameValueCollection idObfuscationParams = SaController.DecryptParameters(encryptedId, Base64Key_IdObfuscation, Purpose_IdObfuscation);
|
||||
return SysId.ToSysId(idObfuscationParams.Get(ParamName_IdObfuscation_Id));
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Reference Data.
|
||||
//-------------------------------------------------------------------
|
||||
// Regions.
|
||||
/// <summary>Region Data - to be JSON serialised in Ajax responses.</summary>
|
||||
public class RegionData
|
||||
{
|
||||
/// <summary>Encrypted Id</summary>
|
||||
public String Id { get; set; }
|
||||
public int RegionType { get; set; }
|
||||
public String RegionTypeCode { get; set; }
|
||||
public String RegionTypeDesc { get; set; }
|
||||
public String Name { get; set; }
|
||||
public String ParentId { get; set; }
|
||||
public String StatusCode { get; set; }
|
||||
public String StatusDesc { get; set; }
|
||||
}
|
||||
public List<RegionData> GetRegionDataList_Active()
|
||||
{
|
||||
List<RegionData> regions = new List<RegionData>();
|
||||
foreach (SaxRegion.Data region in DataCacheConsole.GetActiveRegions())
|
||||
{
|
||||
RegionData regionData = new RegionData()
|
||||
{
|
||||
Id = GetEncryptedRegionId(region.Id),
|
||||
RegionType = (int)region.RegionType,
|
||||
RegionTypeCode = region.RegionType.ToString(),
|
||||
RegionTypeDesc = Localiser.GetRegionTypeCaption(region.RegionType),
|
||||
Name = GetRegionCaption(region),
|
||||
ParentId = SysId.ToString(region.RegionIdParent),
|
||||
StatusCode = region.StatusCode,
|
||||
StatusDesc = Localiser.GetStatusCaption(region.Status)
|
||||
};
|
||||
regions.Add(regionData);
|
||||
}
|
||||
return regions;
|
||||
}
|
||||
public String GetEncryptedRegionId(SysId regionId)
|
||||
{
|
||||
return DataCacheConsole.GetEncryptedRegionId(regionId, EncryptId(regionId));
|
||||
}
|
||||
public String GetRegionCaption(SysId regionId)
|
||||
{
|
||||
SaxRegion.Data region = DataCacheConsole.GetAllRegions().Find(item => item.Id.Equals(regionId));
|
||||
return Localiser.GetRegionName(region);
|
||||
}
|
||||
public String GetRegionCaption(SaxRegion.Data region)
|
||||
{
|
||||
return Localiser.GetRegionName(region);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Sports.
|
||||
/// <summary>Sport Data - to be JSON serialised in Ajax responses.</summary>
|
||||
public class SportData
|
||||
{
|
||||
/// <summary>Encrypted Id</summary>
|
||||
public String Id { get; set; }
|
||||
public String SportIdParent { get; set; }
|
||||
public String Name { get; set; }
|
||||
public String StatusCode { get; set; }
|
||||
public String StatusDesc { get; set; }
|
||||
}
|
||||
public List<SportData> GetSportDataList_Active()
|
||||
{
|
||||
List<SportData> sports = new List<SportData>();
|
||||
foreach (SaxSport.Data sport in DataCacheConsole.GetActiveSports())
|
||||
{
|
||||
SportData sportData = new SportData()
|
||||
{
|
||||
Id = GetEncryptedSportId(sport.Id),
|
||||
SportIdParent = SysId.IsValid(sport.SportIdParent) ? GetEncryptedSportId(sport.SportIdParent) : null,
|
||||
Name = GetSportCaption(sport),
|
||||
StatusCode = sport.StatusCode,
|
||||
StatusDesc = Localiser.GetStatusCaption(sport.Status)
|
||||
};
|
||||
sports.Add(sportData);
|
||||
}
|
||||
return sports;
|
||||
}
|
||||
public List<SaxSport.Data> GetChildSports_Active(SysId sportIdParent)
|
||||
{
|
||||
List<SaxSport.Data> sports = new List<SaxSport.Data>();
|
||||
if (!SysId.IsValid(sportIdParent)) return sports;
|
||||
List<SaxSport.Data> activeSports = DataCacheConsole.GetActiveSports();
|
||||
sports.AddRange(activeSports.FindAll(item => sportIdParent.Equals(item.SportIdParent)));
|
||||
return sports;
|
||||
}
|
||||
public String GetEncryptedSportId(SysId sportId)
|
||||
{
|
||||
return DataCacheConsole.GetEncryptedSportId(sportId, EncryptId(sportId));
|
||||
}
|
||||
// Sport caption.
|
||||
public String GetSportCaption(SysId sportId)
|
||||
{
|
||||
SaxSport.Data sport = DataCacheConsole.GetAllSports().Find(item => item.Id.Equals(sportId));
|
||||
return GetSportCaption(sport);
|
||||
}
|
||||
public String GetSportCaption(SaxSport.Data sport)
|
||||
{
|
||||
if (sport == null) return "";
|
||||
return Localiser.GetSportName(sport);
|
||||
}
|
||||
// Speciality type.
|
||||
public bool SportSpecialityNotRelevant(SysId sportId)
|
||||
{
|
||||
SaxSport.Data sport = DataCacheConsole.GetAllSports().Find(item => item.Id.Equals(sportId));
|
||||
return SportSpecialityNotRelevant(sport);
|
||||
}
|
||||
public bool SportSpecialityNotRelevant(SaxSport.Data sport)
|
||||
{
|
||||
if (sport == null) return true;
|
||||
return sport.SpecialityLabel == Sax.SportSpecialityLabel.NotRelevant;
|
||||
}
|
||||
// Speciality label.
|
||||
public String GetSportSpecialityLabel(SysId sportId)
|
||||
{
|
||||
SaxSport.Data sport = DataCacheConsole.GetAllSports().Find(item => item.Id.Equals(sportId));
|
||||
return GetSportSpecialityLabel(sport);
|
||||
}
|
||||
public String GetSportSpecialityLabel(SaxSport.Data sport)
|
||||
{
|
||||
if (sport == null) return "";
|
||||
switch (sport.SpecialityLabel)
|
||||
{
|
||||
case Sax.SportSpecialityLabel.Positon:
|
||||
return Localiser["label.position"];
|
||||
case Sax.SportSpecialityLabel.Discipline:
|
||||
return Localiser["label.discipline"];
|
||||
}
|
||||
return Localiser["label.speciality"];
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
}
|
||||
//=======================================================================
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
{
|
||||
"iisSettings": {
|
||||
"windowsAuthentication": false,
|
||||
"anonymousAuthentication": true,
|
||||
"iisExpress": {
|
||||
"applicationUrl": "http://localhost:43215",
|
||||
"sslPort": 44364
|
||||
}
|
||||
},
|
||||
"profiles": {
|
||||
"IIS Express": {
|
||||
"commandName": "IISExpress",
|
||||
"launchBrowser": true,
|
||||
"environmentVariables": {
|
||||
"ASPNETCORE_ENVIRONMENT": "Development",
|
||||
"ASPNETCORE_HOSTINGSTARTUPASSEMBLIES": "Microsoft.AspNetCore.Mvc.Razor.RuntimeCompilation"
|
||||
}
|
||||
},
|
||||
"SaxoniteCoreWebOnline": {
|
||||
"commandName": "Project",
|
||||
"launchBrowser": true,
|
||||
"applicationUrl": "https://localhost:5001;http://localhost:5000",
|
||||
"environmentVariables": {
|
||||
"ASPNETCORE_ENVIRONMENT": "Development",
|
||||
"ASPNETCORE_HOSTINGSTARTUPASSEMBLIES": "Microsoft.AspNetCore.Mvc.Razor.RuntimeCompilation"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk.Web">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net10.0</TargetFramework>
|
||||
<CopyRefAssembliesToPublishDirectory>false</CopyRefAssembliesToPublishDirectory>
|
||||
<RootNamespace>Saxonite.Net.Core.Web</RootNamespace>
|
||||
<AssemblyName>Saxonite.Net.Core.Web</AssemblyName>
|
||||
<UserSecretsId>7fcfa869-b56b-4283-a7c6-1b36f2e00b52</UserSecretsId>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="jQuery" Version="3.7.1" />
|
||||
<PackageReference Include="jQuery.UI.Combined" Version="1.14.1" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Mvc.Razor.RuntimeCompilation" Version="10.0.13" />
|
||||
<PackageReference Include="Moment.js" Version="2.30.1" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\..\..\Common-VS\Workspace\SacsCoreWeb\SacsCoreWeb.csproj" />
|
||||
<ProjectReference Include="..\..\..\..\Common-VS\Workspace\SacsStandardBase\SacsStandardBase.csproj" />
|
||||
<ProjectReference Include="..\..\..\..\Common-VS\Workspace\SacsStandardDbas\SacsStandardDbas.csproj" />
|
||||
<ProjectReference Include="..\SaxoniteCoreWeb\SaxoniteCoreWeb.csproj" />
|
||||
<ProjectReference Include="..\SaxoniteStandardBase\SaxoniteStandardBase.csproj" />
|
||||
<ProjectReference Include="..\SaxoniteStandardDbas\SaxoniteStandardDbas.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Content Update="appsettings.Machine.Sarand602.json">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
<ExcludeFromSingleFile>true</ExcludeFromSingleFile>
|
||||
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
|
||||
</Content>
|
||||
<Content Update="appsettings.Machine.Sarand107.json">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
<ExcludeFromSingleFile>true</ExcludeFromSingleFile>
|
||||
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
|
||||
</Content>
|
||||
<Content Update="wwwroot\css\sax-org-evt.css">
|
||||
<ExcludeFromSingleFile>true</ExcludeFromSingleFile>
|
||||
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
|
||||
</Content>
|
||||
<Content Update="wwwroot\rjs\sax-rjs.css">
|
||||
<ExcludeFromSingleFile>true</ExcludeFromSingleFile>
|
||||
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
|
||||
</Content>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<EmbeddedResource Update="Localisation\SaxOnlineProperties.resx">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
<CustomToolNamespace></CustomToolNamespace>
|
||||
</EmbeddedResource>
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
@@ -0,0 +1,26 @@
|
||||
@model Model_Account
|
||||
@inject SaxLocaliser Localiser
|
||||
@{
|
||||
ViewData["Title"] = "Profile - Organisations";
|
||||
}
|
||||
|
||||
<partial name="~/Views/Account/Profile-Organisations.cshtml" />
|
||||
|
||||
<script type="text/javascript">
|
||||
sax.lbl.edit = '@(Localiser.GetJavascriptText("label.edit"))';
|
||||
sax.lbl.remove = '@(Localiser.GetJavascriptText("label.remove"))';
|
||||
sax.dlg.title.selectRegionCountry = '@Localiser.GetJavascriptText("reference.caption.country.select")';
|
||||
sax.dlg.title.selectRegionProvince = '@Localiser.GetJavascriptText("reference.caption.province.select")';
|
||||
sax.dlg.title.imageUpload = '@Localiser.GetJavascriptText("account.caption.image.upload")';
|
||||
sax.dlg.title.selectRegion = '@Localiser.GetJavascriptText("reference.caption.region.select")';
|
||||
sax.dlg.title.selectSport = '@Localiser.GetJavascriptText("reference.caption.sport.select")';
|
||||
sax.msg.uploadFileSelect = '@Localiser.GetJavascriptText("msg.upload.file.select")';
|
||||
sax.msg.uploadImageSingle = '@Localiser.GetJavascriptText("msg.upload.image.single")';
|
||||
sax.msg.uploadFileSizeMax = '@Localiser.GetJavascriptText("msg.upload.file.size.max","{0}")';
|
||||
sax.msg.uploadFileTypeInvalid = '@Localiser.GetJavascriptText("msg.upload.file.type.invalid","{0}")';
|
||||
sax.msg.uploadingFile = '@Localiser.GetJavascriptText("msg.upload.file.uploading","{0}")';
|
||||
</script>
|
||||
|
||||
<partial name="~/Views/Common/SportSelect.cshtml" />
|
||||
|
||||
<partial name="~/Views/Common/RegionSelect.cshtml" />
|
||||
@@ -0,0 +1,340 @@
|
||||
@model Model_Account
|
||||
@inject SaxLocaliser Localiser
|
||||
|
||||
<div class="sax-panel-section ProfileContact sax-populating">
|
||||
|
||||
<div class="sax-panel-info">
|
||||
|
||||
<div class="sax-header">
|
||||
<div class="row">
|
||||
<div class="col sax-action sax-edit"><div class="sax-caption">@Localiser["account.caption.profile.contact"]</div></div>
|
||||
<div class="fixed">
|
||||
@* Burger menu *@
|
||||
<ul class="nav navbar-nav navbar-light navbar-right sax-burger">
|
||||
<li class="dropdown-toggle caret-off">
|
||||
<a href="#" class="dropdown" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false"><span class="navbar-toggler-icon"></span></a>
|
||||
<ul class="dropdown-menu dropdown-menu-right sax-dropdown-menu">
|
||||
<li class="sax-dropdown-item sax-action sax-edit"><div class="sax-label">@(Localiser["label.update"])</div></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
@* Filter item templates *@
|
||||
<div class="sax-panel-item-template">
|
||||
@* Burger dropdown item template - ul is ignored *@
|
||||
<ul class="sax-dropdown-menu ProfileContact">
|
||||
<li class="sax-dropdown-item sax-action"><div class="sax-label">...</div></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="sax-content">
|
||||
|
||||
<div class="row">
|
||||
|
||||
<div class="col">
|
||||
|
||||
<div class="sax-property AccountEmailAddress hidden">
|
||||
<div class="row">
|
||||
<div class="col-sm-4 sax-label text-sm-right">@Localiser["label.email.address"]</div>
|
||||
<div class="col-sm-8 sax-value"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="sax-property AccountName hidden">
|
||||
<div class="row">
|
||||
<div class="col-sm-4 sax-label text-sm-right">@Localiser["label.name"]</div>
|
||||
<div class="col-sm-8 sax-value"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="sax-property AccountLocation hidden">
|
||||
<div class="row">
|
||||
<div class="col-sm-4 sax-label text-sm-right">@Localiser["label.location"]</div>
|
||||
<div class="col-sm-8 sax-value"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="fixed">
|
||||
@* Account Contact image *@
|
||||
<div class=""><img src="" class="sax-contact-image AccountContact" alt="" title="" /></div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@* User Contact Details form *@
|
||||
<div class="sax-panel-form">
|
||||
|
||||
@* User Contact Details form - Header *@
|
||||
<div class="sax-header">
|
||||
<div class="row">
|
||||
<div class="col"><div class="sax-caption">@Localiser["account.caption.profile.contact"]</div></div>
|
||||
<div class="fixed">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@* User Contact Details form - Content *@
|
||||
<div class="sax-content">
|
||||
|
||||
<div class="spacer2"></div>
|
||||
|
||||
@using (@Html.BeginForm(FormMethod.Post, new { @id = "frmProfileContact", @class = "sax-form", @onSubmit = "return false;" }))
|
||||
{
|
||||
|
||||
@* User email *@
|
||||
<div class="sax-form-control AccountEmailAddress">
|
||||
<div class="row">
|
||||
<div class="col-sm-3">
|
||||
<div class="sax-label">
|
||||
<label for="ifAccountEmailAddress"><span>@Localiser["label.email"]</span><span class="required"> *</span></label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-sm">
|
||||
<div class="sax-control">
|
||||
@Html.TextBoxFor(model => model.AccountEmailAddress, new { @id = "ifAccountEmailAddress", @class = "AccountEmailAddress sax-input", @readonly = "readonly", @maxlength = @Model.GetControlMaxLength(SaxDbDfn_Core.ColumnIdx.UserAccount_EmailAddress) })
|
||||
</div>
|
||||
<div class="sax-message"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@* User Name *@
|
||||
<div class="row">
|
||||
|
||||
<div class="col-sm-3">
|
||||
<div class="sax-label d-none d-sm-block">
|
||||
<label for="ifAccountFirstName"><span>@Localiser["label.name"]</span></label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-sm row">
|
||||
|
||||
<div class="col-sm-4">
|
||||
@* User Title *@
|
||||
<div class="sax-form-control AccountTitle pr8">
|
||||
<div class="sax-label">
|
||||
<label for="cbAccountTitle"><span>@Localiser["label.title"]</span></label>
|
||||
</div>
|
||||
<div class="sax-control">
|
||||
@Html.DropDownListFor(model => model.AccountTitle, Model.TitlesForSelect, Localiser["label.select"], new { @id = "cbAccountTitle", @class = "AccountTitle sax-select" })
|
||||
</div>
|
||||
<div class="sax-message"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-sm-4">
|
||||
@* User first name *@
|
||||
<div class="sax-form-control AccountFirstName pr8">
|
||||
<div class="sax-label">
|
||||
<label for="ifAccountFirstName"><span>@Localiser["label.first.name"]</span><span class="required"> *</span></label>
|
||||
</div>
|
||||
<div class="sax-control">
|
||||
@Html.TextBoxFor(model => model.AccountFirstName, new { @id = "ifAccountFirstName", @class = "AccountFirstName sax-input", @maxlength = @Model.GetControlMaxLength(SaxDbDfn_Core.ColumnIdx.UserAccount_FirstName) })
|
||||
</div>
|
||||
<div class="sax-message"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-sm-4">
|
||||
@* User last name *@
|
||||
<div class="sax-form-control AccountLastName">
|
||||
<div class="sax-label">
|
||||
<label for="ifAccountLastName"><span>@Localiser["label.last.name"]</span><span class="required"> *</span></label>
|
||||
</div>
|
||||
<div class="sax-control">
|
||||
@Html.TextBoxFor(model => model.AccountLastName, new { @id = "ifAccountLastName", @class = "AccountLastName sax-input", @maxlength = @Model.GetControlMaxLength(SaxDbDfn_Core.ColumnIdx.UserAccount_LastName) })
|
||||
</div>
|
||||
<div class="sax-message"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@* About *@
|
||||
<div class="sax-form-control AccountAbout">
|
||||
<div class="row">
|
||||
<div class="col-sm-3">
|
||||
<div class="sax-label">
|
||||
<label for="ifAccountAbout"><span>@Localiser["label.bio"]</span></label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-sm">
|
||||
<div class="sax-control">
|
||||
@Html.TextAreaFor(model => model.AccountAbout, new { @id = "ifAccountAbout", @class = "AccountAbout sax-input", @rows = 4, @maxlength = @Model.GetControlMaxLength(SaxDbDfn_Core.ColumnIdx.UserAccount_About) })
|
||||
</div>
|
||||
<div class="sax-message"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@* Gender *@
|
||||
<div class="sax-form-control AccountGender">
|
||||
<div class="row">
|
||||
<div class="col-sm-3">
|
||||
<div class="sax-label">
|
||||
<label for="cbAccountGender"><span>@Localiser["label.gender"]</span></label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-sm">
|
||||
<div class="sax-control">
|
||||
<select name="AccountGender" id="cbAccountGender" class="AccountGender sax-select"></select>
|
||||
</div>
|
||||
<div class="sax-message"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@* Date of birth *@
|
||||
<div class="row">
|
||||
|
||||
<div class="col-sm-3">
|
||||
<div class="sax-form-control AccountDob">
|
||||
<div class="sax-label">
|
||||
<label for="ifAccountRegionIdCountry"><span>@Localiser["label.date.of.birth"]</span></label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-sm">
|
||||
<div class="row">
|
||||
|
||||
@* DOB Year *@
|
||||
<div class="col-4">
|
||||
<div class="sax-form-control AccountDobYear pr8">
|
||||
<div class="sax-label">
|
||||
<label for="cbAccountDobYear"><span>@Localiser["label.year"]</span></label>
|
||||
</div>
|
||||
<div class="sax-control">
|
||||
<select name="AccountDobYear" id="cbAccountDobYear" class="AccountDobYear sax-select" onchange="sax.refreshDob();"></select>
|
||||
</div>
|
||||
<div class="sax-message"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@* DOB Month *@
|
||||
<div class="col-4">
|
||||
<div class="sax-form-control AccountDobMonth pr8">
|
||||
<div class="sax-label">
|
||||
<label for="cbAccountDobMonth"><span>@Localiser["label.month"]</span></label>
|
||||
</div>
|
||||
<div class="sax-control">
|
||||
<select name="AccountDobMonth" id="cbAccountDobMonth" class="AccountDobMonth sax-select" onchange="sax.refreshDob();"></select>
|
||||
</div>
|
||||
<div class="sax-message"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@* DOB Day *@
|
||||
<div class="col-4">
|
||||
<div class="sax-form-control AccountDobDay">
|
||||
<div class="sax-label">
|
||||
<label for="cbAccountDobDay"><span>@Localiser["label.day"]</span></label>
|
||||
</div>
|
||||
<div class="sax-control">
|
||||
<select name="AccountDobDay" id="cbAccountDobDay" class="AccountDobDay sax-select" onchange="sax.refreshDob();"></select>
|
||||
</div>
|
||||
<div class="sax-message"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
@* Country Region *@
|
||||
<div class="sax-form-control AccountRegionIdCountry">
|
||||
<div class="row">
|
||||
<div class="col-sm-3">
|
||||
<div class="sax-label">
|
||||
<label for="ifAccountRegionIdCountry"><span>@Localiser["label.country"]</span><span class="required"> *</span></label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-sm">
|
||||
<div class="sax-control row">
|
||||
@Html.HiddenFor(model => model.AccountRegionIdCountry, new { @id = "ifAccountRegionIdCountry", @class = "AccountRegionIdCountry" })
|
||||
<div class="col"><input type="text" id="ifAccountRegionCaptionCountry" class="AccountRegionCaptionCountry sax-input" readonly="readonly" onDblClick="sax.selectRegionCountry()" /></div>
|
||||
<div class="fixed"><button class="SelectRegionCountry sax-button" style="min-width:auto;margin-left:4px;padding:4px 6px" onclick="sax.selectRegionCountry()">@Localiser["label.select"]</button></div>
|
||||
</div>
|
||||
<div class="sax-message"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@* Account image *@
|
||||
<div class="sax-form-control AccountContactImage">
|
||||
<div class="row">
|
||||
<div class="col-sm-3">
|
||||
<div class="sax-label">
|
||||
<label for="ifAccountImage"><span>@Localiser["label.image"]</span></label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-sm">
|
||||
<div class="sax-control">
|
||||
<div id="pnlContactImageDrop" class="sax-panel-drop row">
|
||||
<div class="fixed">
|
||||
<div class=""><img src="" class="sax-contact-image AccountContact" alt="" title="" /></div>
|
||||
</div>
|
||||
<div class="col">
|
||||
@Localiser["label.drag.image.here"]
|
||||
<div class="DropMessage"></div>
|
||||
<div class="UploadMessage"></div>
|
||||
<div class="spacer4"></div>
|
||||
@Localiser["label.alternatively"]:
|
||||
<button id="pbSelectContactImage" class="sax-button" style="min-width:auto;margin-left:4px;padding:4px 6px;z-index:999;" onclick="sax.selectContactImage()">@Localiser["label.upload"]</button>
|
||||
</div>
|
||||
<div class="fixed">
|
||||
<img id="" class="ContactImageUploadProgress" src="~/img/animated/progress-basketball-32.gif" style="display:none;margin:8px 4px;" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="sax-message"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@* Action buttons *@
|
||||
<div class="spacer2"></div>
|
||||
<div class="row">
|
||||
<div class="col-6 text-left"><button type="button" class="sax-button" value="" onclick="sax.refreshProfileContactInfo();">@Localiser["label.cancel"]</button></div>
|
||||
<div class="col-6 text-right"><button type="button" class="sax-button" value="" onclick="sax.storeProfileContact();">@Localiser["label.save"]</button></div>
|
||||
</div>
|
||||
|
||||
}
|
||||
|
||||
<div class="spacer2"></div>
|
||||
|
||||
</div>
|
||||
|
||||
<div id="dlgSelectContactImage" class="sax-dialog">
|
||||
@using (@Html.BeginForm(FormMethod.Post, new { @id = "frmSelectContactImage", @class = "sax-form", @onSubmit = "return false;" }))
|
||||
{
|
||||
<div class="spacer4"></div>
|
||||
<div class="sax-form-control AccountContactImage">
|
||||
<div class="row">
|
||||
<div class="fixed"><div style="padding:0 12px;">@Localiser["label.image"]</div></div>
|
||||
<div class="col"><input type="file" id="ifContactImage" name="" class="fullwidth" style="" /></div>
|
||||
</div>
|
||||
<div class="sax-message"></div>
|
||||
</div>
|
||||
<div class="spacer2"></div>
|
||||
<div class="row">
|
||||
<div class="col"><div class="UploadMessage"></div></div>
|
||||
<div class="fixed"><img id="" class="ContactImageUploadProgress" src="~/img/animated/progress-basketball-32.gif" style="display:none;margin:8px 4px;" /></div>
|
||||
</div>
|
||||
<div class="spacer2"></div>
|
||||
}
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
@@ -0,0 +1,179 @@
|
||||
@model Model_Account
|
||||
@inject SaxLocaliser Localiser
|
||||
@{
|
||||
// Ensure view is only included once in page.
|
||||
if (!Model.RegisterView(ViewContext)) return;
|
||||
// Scripts.
|
||||
Model.AdditionalFiles_JS.Add("js/sax-pro-elg.js");
|
||||
}
|
||||
|
||||
<div class="sax-panel-section ProfileEligibility sax-populating">
|
||||
|
||||
<div class="sax-panel-info">
|
||||
|
||||
<div class="sax-header">
|
||||
<div class="row">
|
||||
<div class="col sax-action sax-edit"><div class="sax-caption">@Localiser["caption.my.eligibility"]</div></div>
|
||||
<div class="fixed">
|
||||
@* Burger menu *@
|
||||
<ul class="nav navbar-nav navbar-light navbar-right sax-burger">
|
||||
<li class="dropdown-toggle caret-off">
|
||||
<a href="#" class="dropdown" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false"><span class="navbar-toggler-icon"></span></a>
|
||||
<ul class="dropdown-menu dropdown-menu-right sax-dropdown-menu">
|
||||
<li class="sax-dropdown-item sax-action sax-add"><div class="sax-label">@(Localiser["label.add"])</div></li>
|
||||
<li class="sax-dropdown-item sax-action sax-info"><div class="sax-label">@(Localiser["caption.show.info"])</div></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
@* Filter item templates *@
|
||||
<div class="sax-panel-item-template">
|
||||
@* Burger dropdown item template - ul is ignored *@
|
||||
<ul class="sax-dropdown-menu ProfileEligibilities">
|
||||
<li class="sax-dropdown-item sax-action"><div class="sax-label">...</div></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="sax-content">
|
||||
<div class="sax-panel-results">
|
||||
<div class="sax-panel-infotip hidden"><div class="sax-close"></div><div class="sax-info"></div></div>
|
||||
<div class="sax-panel-messages"></div>
|
||||
@* User Eligibility list. *@
|
||||
<div class="sax-panel-item-list"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@* Item templates *@
|
||||
<div class="sax-panel-item-template">
|
||||
@* User Eligibility template *@
|
||||
<div class="sax-panel-item UserEligibility">
|
||||
<div class="sax-header row">
|
||||
<div class="col"><div class="sax-caption"><div class="sax-action EligibilityRegionName"></div></div></div>
|
||||
<div class="fixed">
|
||||
@* Burger menu *@
|
||||
<ul class="nav navbar-nav navbar-light navbar-right sax-burger">
|
||||
<li class="dropdown-toggle caret-off">
|
||||
<a href="#" class="dropdown" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false"><span class="navbar-toggler-icon"></span></a>
|
||||
<ul class="dropdown-menu dropdown-menu-right sax-dropdown-menu"></ul>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<div class="sax-content">
|
||||
<div class="row">
|
||||
<div class="col-sm-6"><div class="EligibilityType sax-note"></div></div>
|
||||
<div class="col-sm-6 text-sm-right"><div class="EligibilityExpiry sax-note">@Localiser["label.expires"]: <span class="EligibilityExpiresOn"></span></div></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@* User Eligibility Burger dropdown template - ul is ignored *@
|
||||
<ul class="sax-dropdown-menu UserEligibility">
|
||||
<li class="sax-dropdown-item sax-action"><div class="sax-label">...</div></li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
@* User Eligibility Id form. *@
|
||||
@using (Html.BeginForm(FormMethod.Post, new { @id = "frmUserEligibilityId", @class = "sax-form", @onSubmit = "return false;" }))
|
||||
{
|
||||
@Html.Hidden("Eligibility.Id", "", new { @id = "", @class = "UserEligibilityId sax-hidden" })
|
||||
}
|
||||
|
||||
</div>
|
||||
|
||||
@* User Eligibility dialog *@
|
||||
<div id="dlgUserEligibility" class="sax-dialog" title="@Localiser["account.caption.profile.eligibility"]">
|
||||
|
||||
<div class="spacer2"></div>
|
||||
@using (Html.BeginForm(FormMethod.Post, new { @id = "frmUserEligibility", @class = "sax-form", @onSubmit = "return false;" }))
|
||||
{
|
||||
<input type="hidden" class="UserEligibilityId sax-hidden" name="Eligibility.Id" />
|
||||
<input type="hidden" class="EligibilityExists sax-hidden" name="Eligibility.Exists" />
|
||||
|
||||
@* Region *@
|
||||
<div class="sax-form-control EligibilityRegion">
|
||||
<div class="row">
|
||||
<div class="col-sm-3">
|
||||
<div class="sax-label">
|
||||
<label for="ifEligibilityRegionId"><span>@Localiser["label.region"]</span><span class="required"> *</span></label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-sm">
|
||||
<div class="sax-control row">
|
||||
@Html.Hidden("Eligibility.RegionId", "", new { @id = "ifEligibilityRegionId", @class = "EligibilityRegionId" })
|
||||
<div class="col"><input type="text" id="ifEligibilityRegionName" class="EligibilityRegionName sax-input" readonly="readonly" /></div>
|
||||
<div class="fixed"><button class="SelectEligibilityRegion sax-button" style="min-width:auto;margin-left:4px;padding:4px 6px">@Localiser["label.select"]</button></div>
|
||||
</div>
|
||||
<div class="sax-message"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@* Eligibility Type *@
|
||||
<div class="sax-form-control EligibilityType">
|
||||
<div class="row">
|
||||
<div class="col-sm-3">
|
||||
<div class="sax-label">
|
||||
<label for="ifEligibilityType"><span>@Localiser["label.eligibility"]</span><span class="required"> *</span></label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-sm">
|
||||
<div class="sax-control">
|
||||
@Html.DropDownList("Eligibility.Type", Model.EligibilityTypesForSelect, "", new { @id = "ifEligibilityType", @class = "EligibilityType sax-select", @readonly = "readonly", @maxlength = @Model.GetControlMaxLength(SaxDbDfn_Core.ColumnIdx.UserAccount_EmailAddress) })
|
||||
</div>
|
||||
<div class="sax-message"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@* Info *@
|
||||
<div class="sax-form-control EligibilityInfo">
|
||||
<div class="row">
|
||||
<div class="col-sm-3">
|
||||
<div class="sax-label">
|
||||
<label for="ifEligibilityInfo"><span>@Localiser["label.info"]</span></label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-sm">
|
||||
<div class="sax-control">
|
||||
@Html.TextArea("Eligibility.Info", "", new { @id = "ifEligibilityInfo", @class = "EligibilityInfo sax-textarea", @rows = 4, @maxlength = @Model.GetControlMaxLength(SaxDbDfn_Core.ColumnIdx.UserEligibility_Info) })
|
||||
</div>
|
||||
<div class="sax-message"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@* Expiry *@
|
||||
<div class="sax-form-control EligibilityExpiry">
|
||||
<div class="row">
|
||||
<div class="col-sm-3">
|
||||
<div class="sax-label">
|
||||
<label for="ifArticleRegionId"><span>@Localiser["label.expiry"]</span></label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-sm">
|
||||
<div class="sax-control">
|
||||
<div class="row EligibilityExpires">
|
||||
<div class="fixed"><div class="pl16 pt4 pr8"><input type="checkbox" id="chkEligibilityExpires" class="EligibilityExpires sax-checkbox" /> <span class="" onclick="$('#chkEligibilityExpires').click()">@Localiser["label.expires.on"]</span></div></div>
|
||||
<div class="col">@Html.TextBox("Eligibility.ExpiresOn", "", new { @id = "ifEligibilityExpiresOn", @class = "sax-input sax-calendar EligibilityExpiresOn", @readonly = "readonly" })</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="sax-message"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
}
|
||||
<div class="spacer2"></div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<script type="text/javascript">
|
||||
sax.msg.eligibilityInfo = '@Localiser.GetJavascriptText("info.profile.eligibility")';
|
||||
sax.dlg.title.addUserEligibility = '@Localiser.GetJavascriptText("account.caption.profile.eligibility.add")';
|
||||
sax.dlg.title.updateUserEligibility = '@Localiser.GetJavascriptText("account.caption.profile.eligibility.update")';
|
||||
sax.dlg.title.removeUserEligibility = '@Localiser.GetJavascriptText("account.caption.profile.eligibility.remove")';
|
||||
sax.msg.removeUserEligibility = '@(Localiser.GetJavascriptText("msg.confirm.item.remove"))';
|
||||
</script>
|
||||
@@ -0,0 +1,152 @@
|
||||
@model Model_Account
|
||||
@inject SaxLocaliser Localiser
|
||||
@{
|
||||
// Ensure view is only included once in page.
|
||||
if (!Model.RegisterView(ViewContext)) return;
|
||||
// Scripts.
|
||||
Model.AdditionalFiles_JS.Add("js/sax-pro-org.js");
|
||||
}
|
||||
|
||||
@* Profile Organisations *@
|
||||
<div class="sax-panel-section ProfileOrganisations sax-populating">
|
||||
|
||||
<div class="sax-panel-info">
|
||||
|
||||
@* Panel caption and burger menu *@
|
||||
<div class="sax-header">
|
||||
<div class="row">
|
||||
<div class="col"><div class="sax-caption">@Localiser["account.caption.profile.organisations"]</div></div>
|
||||
<div class="fixed">
|
||||
@* Burger menu *@
|
||||
<ul class="nav navbar-nav navbar-light navbar-right sax-burger">
|
||||
<li class="dropdown-toggle caret-off">
|
||||
<a href="#" class="dropdown" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false"><span class="navbar-toggler-icon"></span></a>
|
||||
<ul class="dropdown-menu dropdown-menu-right sax-dropdown-menu">
|
||||
<li class="sax-action sax-users sax-dropdown-item" onclick="sax.orgReq.fn.requestOrganisation();"><div class="sax-label">@Localiser["organisation.caption.organisation.request"]</div></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
@* Filter item templates *@
|
||||
<div class="sax-panel-item-template">
|
||||
@* Filter Burger dropdown template - ul is ignored *@
|
||||
<ul class="sax-dropdown-menu ProfileOrganisations">
|
||||
<li class="sax-dropdown-item sax-action"><div class="sax-label">...</div></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="sax-content">
|
||||
@* Profile Organisations list *@
|
||||
<div class="sax-panel-item-list sax-panel-results Organisations"></div>
|
||||
</div>
|
||||
|
||||
@* Item templates *@
|
||||
<div class="sax-panel-item-template">
|
||||
@* Organisation template *@
|
||||
<div class="sax-panel-item Organisation">
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<div class="sax-header row">
|
||||
<div class="col"><div class="sax-caption"><div class="sax-action OrganisationName"></div></div></div>
|
||||
<div class="fixed">
|
||||
@* Burger menu *@
|
||||
<ul class="nav navbar-nav navbar-light navbar-right sax-burger">
|
||||
<li class="dropdown-toggle caret-off">
|
||||
<a href="#" class="dropdown" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false"><span class="navbar-toggler-icon"></span></a>
|
||||
<ul class="dropdown-menu dropdown-menu-right sax-dropdown-menu"></ul>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<div class="sax-content">
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<div class="row">
|
||||
<div class="col-sm-6"><div class="OrganisationSport sax-note"></div></div>
|
||||
<div class="col-sm-6 text-sm-right"><div class="OrganisationRegionPrimary sax-note"></div></div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-sm-6"><div class="OrganisationMemberCount sax-note sa-action">@Localiser["label.members"]: <span class="MemberCount"></span></div></div>
|
||||
<div class="col-sm-6 text-sm-right"><div class="OrganisationOpportunityCount sax-note sa-action">@Localiser["label.opportunities"]: <span class="OpportunityCount"></span></div></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="fixed"><img src="" class="OrganisationLogo" alt="" title="" style="margin:0 0 0 6px;"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@* Organisation Burger dropdown template - ul is ignored *@
|
||||
<ul class="sax-dropdown-menu ProfileOrganisation">
|
||||
<li class="sax-dropdown-item sax-action"><div class="sax-label">...</div></li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
@* Profile Organisation Id form *@
|
||||
@using (Html.BeginForm(FormMethod.Post, new { @id = "frmProfileOrganisationId", @class = "sax-form", @onSubmit = "return false;" }))
|
||||
{
|
||||
@Html.HiddenFor(model => model.Organisation.Id, new { @id = "", @class = "OrganisationId" })
|
||||
}
|
||||
|
||||
</div>
|
||||
|
||||
@* Profile Organisation dialog *@
|
||||
<div id="dlgProfileOrganisation" class="sax-dialog" title="@Localiser["label.organisation"]">
|
||||
<div class="spacer2"></div>
|
||||
@using (Html.BeginForm(FormMethod.Post, new { @id = "frmProfileOrganisation", @class = "sax-form", @onSubmit = "return false;" }))
|
||||
{
|
||||
@Html.HiddenFor(model => model.Organisation.Id, new { @id = "", @class = "OrganisationId" })
|
||||
@Html.HiddenFor(model => model.Organisation.Address.Id, new { @id = "", @class = "OrganisationAddressId" })
|
||||
|
||||
@* Core controls - name, category, sport, region *@
|
||||
<partial name="~/Views/Common/OrganisationControls-Core.cshtml" />
|
||||
|
||||
@* Organisation About *@
|
||||
<div class="sax-form-control OrganisationAbout">
|
||||
<div class="row">
|
||||
<div class="col-sm-3">
|
||||
<div class="sax-label">
|
||||
<label for="ifOrganisationAbout"><span>@Localiser["label.about"]</span></label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-sm">
|
||||
<div class="sax-control">
|
||||
@Html.TextAreaFor(model => model.Organisation.About, new { @id = "ifOrganisationAbout", @class = "OrganisationAbout sax-input", @rows = 6, @maxlength = @Model.GetControlMaxLength(SaxDbDfn_Core.ColumnIdx.Organisation_About) })
|
||||
</div>
|
||||
<div class="sax-message"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@* Organisation Facilities *@
|
||||
<div class="sax-form-control OrganisationFacilities">
|
||||
<div class="row">
|
||||
<div class="col-sm-3">
|
||||
<div class="sax-label">
|
||||
<label for="ifOrganisationFacilities"><span>@Localiser["label.facilities"]</span></label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-sm">
|
||||
<div class="sax-control">
|
||||
@Html.TextAreaFor(model => model.Organisation.Facilities, new { @id = "ifOrganisationFacilities", @class = "OrganisationFacilities sax-input", @rows = 6, @maxlength = @Model.GetControlMaxLength(SaxDbDfn_Core.ColumnIdx.Organisation_Facilities) })
|
||||
</div>
|
||||
<div class="sax-message"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@* Contact controls *@
|
||||
<partial name="~/Views/Common/OrganisationControls-Contact.cshtml" />
|
||||
|
||||
@* ModelData_Address controls *@
|
||||
<partial name="~/Views/Common/OrganisationControls-Address.cshtml" />
|
||||
|
||||
}
|
||||
<div class="spacer"></div>
|
||||
</div>
|
||||
|
||||
<partial name="~/Views/Common/OrganisationRequest.cshtml" />
|
||||
@@ -0,0 +1,260 @@
|
||||
@model SaxModel_Online
|
||||
@inject SaxLocaliser Localiser
|
||||
@{
|
||||
/* Sport Experience panel - list experience for sport */
|
||||
// Ensure view is only included once in page.
|
||||
if (!Model.RegisterView(ViewContext)) return;
|
||||
// Scripts.
|
||||
Model.AdditionalFiles_JS.Add("js/sax-spt-exp.js");
|
||||
}
|
||||
|
||||
<div class="sax-panel sax-panel-info ProfileSportExperience hidden">
|
||||
|
||||
<script type="text/javascript">
|
||||
sax.lbl.speciality = '@Localiser.GetJavascriptText("label.speciality")';
|
||||
</script>
|
||||
|
||||
<div class="sax-header">
|
||||
<div class="row">
|
||||
<div class="col"><div class="sax-caption"><span>@Localiser["account.caption.profile.sports.experience"] - </span><span class="SportName"></span></div></div>
|
||||
<div class="fixed">
|
||||
@* Burger menu *@
|
||||
<ul class="nav navbar-nav navbar-light navbar-right sax-burger">
|
||||
<li class="dropdown-toggle caret-off">
|
||||
<a href="#" class="dropdown" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false"><span class="navbar-toggler-icon"></span></a>
|
||||
<ul class="dropdown-menu dropdown-menu-right sax-dropdown-menu">
|
||||
<li class="sax-dropdown-item sax-action sax-add" onclick="sax.addSportExperience()"><div class="sax-label">@(Localiser["label.add"])</div></li>
|
||||
<li class="sax-dropdown-item sax-action sax-close" onclick="sax.closeProfileSportExperience()"><div class="sax-label">@(Localiser["label.close"])</div></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
@* Filter item templates *@
|
||||
<div class="sax-panel-item-template">
|
||||
@* Filter Burger dropdown template - ul is ignored *@
|
||||
<ul class="sax-dropdown-menu ProfileSports">
|
||||
<li class="sax-dropdown-item sax-action"><div class="sax-label">...</div></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="sax-content" style="max-height:none;">
|
||||
|
||||
<div class="sax-panel-results ProfileSportExperiences" style="min-height:400px;">
|
||||
<div class="sax-panel-messages"></div>
|
||||
<div class="sax-panel-item-list"></div>
|
||||
<div class="sax-panel-item-template">
|
||||
<div class="sax-panel-item SportExperience">
|
||||
<div class="sax-header row">
|
||||
<div class="col">
|
||||
<div class="sax-caption"><div class="sax-action ExperiencePeriod"></div></div>
|
||||
</div>
|
||||
<div class="fixed sax-actions">
|
||||
@* Burger menu *@
|
||||
<ul class="nav navbar-nav navbar-light navbar-right sax-burger">
|
||||
<li class="dropdown-toggle caret-off">
|
||||
<a href="#" class="dropdown" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false"><span class="navbar-toggler-icon"></span></a>
|
||||
<ul class="dropdown-menu dropdown-menu-right sax-dropdown-menu"></ul>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<div class="sax-content">
|
||||
<div class="row">
|
||||
<div class="col-sm-12"><div class="ExperienceSummary"></div></div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-sm-4"><div class="sax-note"><span class="ExperienceTeam"></span></div></div>
|
||||
<div class="col-sm-4 justify-content-sm-center"><div class="sax-note"><span class="ExperienceLeague"></span></div></div>
|
||||
<div class="col-sm-4 justify-content-sm-end"><div class="ax-note"><span class="ExperienceSpeciality"></span></div></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@* Filter Burger dropdown template - ul is ignored *@
|
||||
<ul class="sax-dropdown-menu SportExperience">
|
||||
<li class="sax-dropdown-item sax-action"><div class="sax-label">...</div></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@* Action buttons *@
|
||||
<div class="spacer2"></div>
|
||||
<div class="row">
|
||||
<div class="col text-right pr12"><button type="button" class="sax-button" value="" onclick="sax.closeProfileSportExperience();">@Localiser["label.close"]</button></div>
|
||||
</div>
|
||||
<div class="spacer2"></div>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
@using (Html.BeginForm(FormMethod.Post, new { @id = "frmSportExperienceId", @class = "sax-form", @onSubmit = "return false;" }))
|
||||
{
|
||||
<input type="hidden" name="UserSportExperienceId" class="UserSportExperienceId" />
|
||||
}
|
||||
|
||||
<div id="dlgSportExperience" class="sax-dialog">
|
||||
|
||||
<div class="spacer2"></div>
|
||||
|
||||
@using (Html.BeginForm(FormMethod.Post, new { @id = "frmSportExperience", @class = "sax-form", @onSubmit = "return false;" }))
|
||||
{
|
||||
<input type="hidden" class="UserSportId" name="UserSportId" />
|
||||
<input type="hidden" class="UserSportExperienceId" name="UserSportExperienceId" />
|
||||
<input type="hidden" class="UserSportExperienceExists" name="UserSportExperienceExists" />
|
||||
|
||||
@* Period *@
|
||||
<div class="row">
|
||||
|
||||
<div class="col-sm-3">
|
||||
<div class="sax-label pt-sm-4">
|
||||
<label for=""><span>@Localiser["label.period"]</span></label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-sm-9">
|
||||
<div class="row">
|
||||
<div class="col-6">
|
||||
@* Period From *@
|
||||
<div class="sax-form-control ExperiencePeriodFrom">
|
||||
<div class="sax-label">
|
||||
<label for=""><span>@Localiser["label.from"]</span><span class="required"> *</span></label>
|
||||
</div>
|
||||
<div class="sax-control">
|
||||
<input type="text" name="ExperiencePeriodFrom" class="ExperiencePeriodFrom sax-input sax-calendar" readonly="readonly" />
|
||||
</div>
|
||||
<div class="sax-message"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-6">
|
||||
@* Period To *@
|
||||
<div class="sax-form-control ExperiencePeriodTo">
|
||||
<div class="sax-label">
|
||||
<label for=""><span>@Localiser["label.to"]</span></label>
|
||||
</div>
|
||||
<div class="sax-control">
|
||||
<input type="text" name="ExperiencePeriodTo" class="ExperiencePeriodTo sax-input sax-calendar" readonly="readonly" />
|
||||
</div>
|
||||
<div class="sax-message"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
@* Summary *@
|
||||
<div class="sax-form-control ExperienceSummary">
|
||||
<div class="row">
|
||||
<div class="col-sm-3">
|
||||
<div class="sax-label">
|
||||
<label for=""><span>@Localiser["label.summary"]</span><span class="required"> *</span></label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-sm-9">
|
||||
<div class="sax-control">
|
||||
<textarea name="ExperienceSummary" class="ExperienceSummary sax-textarea" rows="4" maxlength="@Model.GetControlMaxLength(SaxDbDfn_Core.ColumnIdx.UserSportExperience_Summary)"></textarea>
|
||||
</div>
|
||||
<div class="sax-message"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@* Organisation *@
|
||||
<div class="sax-form-control ExperienceOrganisation">
|
||||
<div class="row">
|
||||
<div class="col-sm-3">
|
||||
<div class="sax-label">
|
||||
<label for=""><span>@Localiser["label.club"]</span></label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-sm-9">
|
||||
<div class="sax-control">
|
||||
<input type="text" name="ExperienceOrganisationName" class="ExperienceOrganisationName sax-input" maxlength="@Model.GetControlMaxLength(SaxDbDfn_Core.ColumnIdx.UserSportExperience_OrganisationName)" />
|
||||
</div>
|
||||
<div class="sax-message"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@* Speciality *@
|
||||
<div class="sax-form-control ExperienceSpeciality">
|
||||
<div class="row">
|
||||
<div class="col-sm-3">
|
||||
<div class="sax-label">
|
||||
<label for=""><span class="sax-label-text">@Localiser["label.speciality"]</span></label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-sm-9">
|
||||
<div class="sax-control">
|
||||
<input type="text" name="ExperienceSpeciality" class="ExperienceSpeciality sax-input" maxlength="@Model.GetControlMaxLength(SaxDbDfn_Core.ColumnIdx.UserSportExperience_Speciality)" />
|
||||
</div>
|
||||
<div class="sax-message"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@* Team *@
|
||||
<div class="sax-form-control ExperienceTeam">
|
||||
<div class="row">
|
||||
<div class="col-sm-3">
|
||||
<div class="sax-label">
|
||||
<label for=""><span>@Localiser["label.team"]</span></label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-sm-9">
|
||||
<div class="sax-control">
|
||||
<input type="text" name="ExperienceTeam" class="ExperienceTeam sax-input" maxlength="@Model.GetControlMaxLength(SaxDbDfn_Core.ColumnIdx.UserSportExperience_Team)" />
|
||||
</div>
|
||||
<div class="sax-message"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@* League *@
|
||||
<div class="sax-form-control ExperienceLeague">
|
||||
<div class="row">
|
||||
<div class="col-sm-3">
|
||||
<div class="sax-label">
|
||||
<label for=""><span>@Localiser["label.league"]</span></label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-sm-9">
|
||||
<div class="sax-control">
|
||||
<input type="text" name="ExperienceLeague" class="ExperienceLeague sax-input" maxlength="@Model.GetControlMaxLength(SaxDbDfn_Core.ColumnIdx.UserSportExperience_League)" />
|
||||
</div>
|
||||
<div class="sax-message"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@* Awards *@
|
||||
<div class="sax-form-control ExperienceAwards">
|
||||
<div class="row">
|
||||
<div class="col-sm-3">
|
||||
<div class="sax-label">
|
||||
<label for=""><span>@Localiser["label.awards"]</span></label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-sm-9">
|
||||
<div class="sax-control">
|
||||
<textarea name="ExperienceAwards" class="ExperienceAwards sax-textarea" rows="4" maxlength="@Model.GetControlMaxLength(SaxDbDfn_Core.ColumnIdx.UserSportExperience_Awards)"></textarea>
|
||||
</div>
|
||||
<div class="sax-message"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
}
|
||||
|
||||
<div class="spacer2"></div>
|
||||
|
||||
</div>
|
||||
|
||||
<script type="text/javascript">
|
||||
sax.lbl.sportExperience = '@Localiser.GetJavascriptText("account.caption.profile.sports.experience")';
|
||||
</script>
|
||||
|
||||
@@ -0,0 +1,191 @@
|
||||
@model Model_Account
|
||||
@inject SaxLocaliser Localiser
|
||||
@{
|
||||
/* Online Profile Sports. */
|
||||
// Ensure view is only included once in page.
|
||||
if (!Model.RegisterView(ViewContext)) return;
|
||||
// Scripts.
|
||||
Model.AdditionalFiles_JS.Add("js/sax-pro-spt.js");
|
||||
}
|
||||
|
||||
<div class="sax-panel-section ProfileSports sax-populating">
|
||||
|
||||
<div class="sax-panel-info">
|
||||
|
||||
<div class="sax-header">
|
||||
<div class="row">
|
||||
<div class="col"><div class="sax-caption">@Localiser["account.caption.profile.sports"]</div></div>
|
||||
<div class="fixed">
|
||||
@* Burger menu *@
|
||||
<ul class="nav navbar-nav navbar-light navbar-right sax-burger">
|
||||
<li class="dropdown-toggle caret-off">
|
||||
<a href="#" class="dropdown" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false"><span class="navbar-toggler-icon"></span></a>
|
||||
<ul class="dropdown-menu dropdown-menu-right sax-dropdown-menu">
|
||||
<li class="sax-dropdown-item sax-action sax-add"><div class="sax-label">@(Localiser["label.add"])</div></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
@* Filter item templates *@
|
||||
<div class="sax-panel-item-template">
|
||||
@* Filter Burger dropdown template - ul is ignored *@
|
||||
<ul class="sax-dropdown-menu ProfileSports">
|
||||
<li class="sax-dropdown-item sax-action"><div class="sax-label">...</div></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="sax-content">
|
||||
<div class="sax-panel-results ProfileSports"></div>
|
||||
</div>
|
||||
|
||||
@* Item templates *@
|
||||
<div class="sax-panel-item-template">
|
||||
@* Sport template *@
|
||||
<div class="sax-panel-item ProfileSport">
|
||||
<div class="sax-header row">
|
||||
<div class="col"><div class="sax-action sax-edit SportName"></div></div>
|
||||
<div class="fixed">
|
||||
@* Burger menu *@
|
||||
<ul class="nav navbar-nav navbar-light navbar-right sax-burger">
|
||||
<li class="dropdown-toggle caret-off">
|
||||
<a href="#" class="dropdown" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false"><span class="navbar-toggler-icon"></span></a>
|
||||
<ul class="dropdown-menu dropdown-menu-right sax-dropdown-menu">
|
||||
<li class="sax-dropdown-item sax-action sax-edit"><div class="sax-label">@(Localiser["label.update"])</div></li>
|
||||
<li class="sax-dropdown-item sax-action sax-experience"><div class="sax-label">@(Localiser["label.experience"])</div></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<div class="sax-content">
|
||||
<div class="row">
|
||||
<div class="col-sm-4 SportParticipating sax-note">@Localiser["label.participating"]: <span class="SportParticipatingValue"></span></div>
|
||||
<div class="col-sm-4 SportPreparing sax-note">@Localiser["label.preparing"]: <span class="SportPreparingValue"></span></div>
|
||||
<div class="col-sm-4 SportOfficiating sax-note">@Localiser["label.officiating"]: <span class="SportOfficiatingValue"></span></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@* Sport Burger dropdown template - ul is ignored *@
|
||||
<ul class="sax-dropdown-menu ProfileSport">
|
||||
<li class="sax-dropdown-item sax-action"><div class="sax-label">...</div></li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
@using (Html.BeginForm(FormMethod.Post, new { @id = "frmProfileSportId", @class = "sax-form", @onSubmit = "return false;" }))
|
||||
{
|
||||
@Html.HiddenFor(model => model.UserSportId, new { @id = "", @class = "UserSportId" })
|
||||
}
|
||||
|
||||
</div>
|
||||
|
||||
<div id="dlgProfileSport" class="sax-dialog">
|
||||
|
||||
<div class="spacer"></div>
|
||||
@using (Html.BeginForm(FormMethod.Post, new { @id = "frmProfileSport", @class = "sax-form", @onSubmit = "return false;" }))
|
||||
{
|
||||
<input type="hidden" class="UserSportId" name="UserSportId" />
|
||||
<input type="hidden" class="ProfileSportExists" name="ProfileSportExists" />
|
||||
|
||||
@* Sport *@
|
||||
<div class="sax-form-control ProfileSportId">
|
||||
<div class="row">
|
||||
<div class="col-sm-3">
|
||||
<div class="sax-label">
|
||||
<label for="ifProfileSport"><span>@Localiser["label.sport"]</span><span class="required"> *</span></label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-sm">
|
||||
<div class="sax-control row">
|
||||
<input type="hidden" id="ifProfileSportId" class="ProfileSportId" name="ProfileSportId" />
|
||||
<div class="col"><input type="text" id="ifProfileSport" class="ProfileSport sax-input" name="ProfileSport" readonly="readonly" maxlength=128 /></div>
|
||||
<div class="fixed"><button class="SelectSport sax-button" style="min-width:auto;margin-left:4px;padding:4px 6px">@Localiser["label.select"]</button></div>
|
||||
</div>
|
||||
<div class="sax-message"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@* About *@
|
||||
<div class="sax-form-control ProfileSportAbout">
|
||||
<div class="row">
|
||||
<div class="col-sm-3">
|
||||
<div class="sax-label">
|
||||
<label for="ifProfileSportAbout"><span>@Localiser["label.about"]</span></label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-sm">
|
||||
<div class="sax-control">
|
||||
@Html.TextAreaFor(model => model.ProfileSportAbout, new { @id = "ifProfileSportAbout", @class = "ProfileSportAbout sax-textarea", @rows = 4, @maxlength = @Model.GetControlMaxLength(SaxDbDfn_Core.ColumnIdx.UserSport_About) })
|
||||
</div>
|
||||
<div class="sax-message"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@* Contact controls *@
|
||||
<partial name="~/Views/Common/SportControls-Contacts.cshtml" />
|
||||
|
||||
@* Sport Participating *@
|
||||
<div class="sax-form-control ProfileSportParticipating">
|
||||
<div class="row">
|
||||
<div class="col-sm-3">
|
||||
<div class="sax-label">
|
||||
<label for="cbProfileSportParticipating"><span>@Localiser["label.participating"]</span></label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-sm">
|
||||
<div class="sax-control">
|
||||
@Html.DropDownListFor(model => model.ProfileSportParticipatingCode, Model.SportParticipatingCodesForSelect, "", new { @id = "cbProfileSportParticipating", @class = "ProfileSportParticipating sax-select" })
|
||||
</div>
|
||||
<div class="sax-message"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@* Sport Preparing *@
|
||||
<div class="sax-form-control ProfileSportPreparing">
|
||||
<div class="row">
|
||||
<div class="col-sm-3">
|
||||
<div class="sax-label">
|
||||
<label for="cbProfileSportPreparing"><span>@Localiser["label.preparing"]</span></label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-sm">
|
||||
<div class="sax-control">
|
||||
@Html.DropDownListFor(model => model.ProfileSportPreparingCode, Model.SportPreparingCodesForSelect, "", new { @id = "cbProfileSportPreparing", @class = "ProfileSportPreparing sax-select" })
|
||||
</div>
|
||||
<div class="sax-message"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@* Sport Officiating *@
|
||||
<div class="sax-form-control ProfileSportOfficiating">
|
||||
<div class="row">
|
||||
<div class="col-sm-3">
|
||||
<div class="sax-label">
|
||||
<label for="cbProfileSportOfficiating"><span>@Localiser["label.officiating"]</span></label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-sm">
|
||||
<div class="sax-control">
|
||||
@Html.DropDownListFor(model => model.ProfileSportOfficiatingCode, Model.SportOfficiatingCodesForSelect, "", new { @id = "cbProfileSportOfficiating", @class = "ProfileSportOfficiating sax-select" })
|
||||
</div>
|
||||
<div class="sax-message"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
}
|
||||
|
||||
<div class="spacer"></div>
|
||||
</div>
|
||||
|
||||
<script type="text/javascript">
|
||||
sax.dlg.title.addUserSport = '@Localiser.GetJavascriptText("account.caption.profile.sport.add")';
|
||||
sax.dlg.title.updateUserSport = '@Localiser.GetJavascriptText("account.caption.profile.sport.update")';
|
||||
</script>
|
||||
@@ -0,0 +1,48 @@
|
||||
@model Model_Account
|
||||
@inject SaxLocaliser Localiser
|
||||
@{
|
||||
ViewData["Title"] = "Profile";
|
||||
}
|
||||
|
||||
<div class="sax-profile">
|
||||
|
||||
<div class="sax-header">
|
||||
<div class="sax-caption">@Localiser["account.caption.profile"]</div>
|
||||
</div>
|
||||
|
||||
<div class="sax-content">
|
||||
|
||||
<partial name="~/Views/Account/Profile-Contact.cshtml" />
|
||||
|
||||
<partial name="~/Views/Account/Profile-Eligibility.cshtml" />
|
||||
|
||||
<!--
|
||||
<partial name="~/Views/Account/Profile-Sports.cshtml" />
|
||||
|
||||
<partial name="~/Views/Account/Profile-SportExperiences.cshtml" />
|
||||
|
||||
<partial name="~/Views/Account/Profile-Organisations.cshtml" />
|
||||
-->
|
||||
|
||||
</div>
|
||||
|
||||
<script type="text/javascript">
|
||||
sax.lbl.edit = '@(Localiser.GetJavascriptText("label.edit"))';
|
||||
sax.lbl.remove = '@(Localiser.GetJavascriptText("label.remove"))';
|
||||
sax.dlg.title.selectRegionCountry = '@Localiser.GetJavascriptText("reference.caption.country.select")';
|
||||
sax.dlg.title.selectRegionProvince = '@Localiser.GetJavascriptText("reference.caption.province.select")';
|
||||
sax.dlg.title.imageUpload = '@Localiser.GetJavascriptText("account.caption.image.upload")';
|
||||
sax.dlg.title.selectRegion = '@Localiser.GetJavascriptText("reference.caption.region.select")';
|
||||
sax.dlg.title.selectSport = '@Localiser.GetJavascriptText("reference.caption.sport.select")';
|
||||
sax.msg.uploadFileSelect = '@Localiser.GetJavascriptText("msg.upload.file.select")';
|
||||
sax.msg.uploadImageSingle = '@Localiser.GetJavascriptText("msg.upload.image.single")';
|
||||
sax.msg.uploadFileSizeMax = '@Localiser.GetJavascriptText("msg.upload.file.size.max","{0}")';
|
||||
sax.msg.uploadFileTypeInvalid = '@Localiser.GetJavascriptText("msg.upload.file.type.invalid","{0}")';
|
||||
sax.msg.uploadingFile = '@Localiser.GetJavascriptText("msg.upload.file.uploading","{0}")';
|
||||
</script>
|
||||
|
||||
<partial name="~/Views/Common/RegionSelect.cshtml" />
|
||||
|
||||
<partial name="~/Views/Common/SportSelect.cshtml" />
|
||||
|
||||
</div>
|
||||
@@ -0,0 +1,13 @@
|
||||
@model Model_Account
|
||||
@inject SaxLocaliser Localiser
|
||||
@{
|
||||
ViewData["Title"] = "Profile - Sports";
|
||||
}
|
||||
|
||||
<partial name="~/Views/Account/Profile-Sports.cshtml" />
|
||||
|
||||
<partial name="~/Views/Common/Sport-Contacts.cshtml" />
|
||||
|
||||
<partial name="~/Views/Account/Profile-SportExperiences.cshtml" />
|
||||
|
||||
<partial name="~/Views/Common/SportSelect.cshtml" />
|
||||
@@ -0,0 +1,118 @@
|
||||
@model Model_Article
|
||||
@inject SaxLocaliser Localiser
|
||||
@{
|
||||
ViewData["Title"] = "Journalist - Articles";
|
||||
}
|
||||
|
||||
<div class="sax-panel Articles">
|
||||
|
||||
<script type="text/javascript">
|
||||
sax.articlePublish = { maxDaysBefore: '@(Sax.Config.Articles.PublishMaxDaysBefore)', maxDaysAhead: '@(Sax.Config.Articles.PublishMaxDaysAhead)' };
|
||||
sax.lbl.edit = '@(Localiser.GetJavascriptText("label.edit"))';
|
||||
sax.lbl.remove = '@(Localiser.GetJavascriptText("label.remove"))';
|
||||
</script>
|
||||
|
||||
@* Filter Form *@
|
||||
@using (@Html.BeginForm(FormMethod.Post, new { @id = "frmArticleFilter", @class = "sax-form", @action = "#", @method = "POST", onsubmit = "return false;" }))
|
||||
{
|
||||
|
||||
@* Filter panel *@
|
||||
<div class="sax-panel-filter">
|
||||
<div class="sax-header row">
|
||||
<div class="col"><div class="sax-caption">@Localiser["article.caption.articles"]</div></div>
|
||||
<div class="fixed row">
|
||||
<div class="col">
|
||||
<partial name="~/Views/Common/ResultsPaging.cshtml" />
|
||||
</div>
|
||||
<div class="fixed">
|
||||
@* Burger menu *@
|
||||
<ul class="nav navbar-nav navbar-dark navbar-right sax-burger">
|
||||
<li class="dropdown-toggle caret-off">
|
||||
<a href="#" class="dropdown" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false"><span class="navbar-toggler-icon"></span></a>
|
||||
<ul class="dropdown-menu dropdown-menu-right sax-dropdown-menu">@* Menu items will be inserted here. *@</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="sax-content">
|
||||
@if (Model.UserCanAuthorOrganisationArticles)
|
||||
{
|
||||
<div class="sax-control row OrganisationFilter">
|
||||
<div class="col-sm-4"><div class="sax-label text-left text-sm-right">@Localiser["label.organisation"]</div></div>
|
||||
<div class="col-sm-8 row">
|
||||
@Html.HiddenFor(model => model.Filter.OrganisationId, new { @id = "ifFilterOrganisationId", @class = "FilterOrganisationId" })
|
||||
<div class="col"><input type="text" id="ifFilterOrganisation" class="FilterOrganisation sax-input" readonly="readonly" value="@(Model.Filter.OrganisationCaption)" /></div>
|
||||
<div class="fixed"><button class="sax-button">@Localiser["label.select"]</button></div>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
<div class="row">
|
||||
<div class="col-sm-4"><div class="sax-label text-left text-sm-right">@Localiser["label.search"]</div></div>
|
||||
<div class="col-sm-8"><input type="search" name="Filter.Article" id="ifArticleFilter" class="ArticleFilter sax-input" maxlength="64" /></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@* Filter item templates *@
|
||||
<div class="sax-panel-item-template">
|
||||
@* Burger dropdown item template - ul is ignored *@
|
||||
<ul class="sax-dropdown-menu Articles">
|
||||
<li class="sax-dropdown-item sax-action"><div class="sax-label">...</div></li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
}
|
||||
|
||||
@* Results Panel *@
|
||||
<div class="sax-panel-results">
|
||||
<div class="sax-panel-messages"></div>
|
||||
<div class="sax-panel-item-list"></div>
|
||||
|
||||
@* Element templates *@
|
||||
<div class="sax-panel-item-template">
|
||||
|
||||
@* Article item template *@
|
||||
<div class="sax-panel-item Article">
|
||||
<div class="sax-header row">
|
||||
<div class="col">
|
||||
<div class="sax-caption"><div class="sax-action ArticleHeadline"></div></div>
|
||||
</div>
|
||||
<div class="fixed"><div class="OrganisationName pt4 pr16"></div></div>
|
||||
<div class="fixed"><div class="ArticleFeedback pt4 pr16"></div></div>
|
||||
<div class="fixed sax-actions">
|
||||
@* Burger menu *@
|
||||
<ul class="nav navbar-nav navbar-light navbar-right sax-burger">
|
||||
<li class="dropdown-toggle caret-off">
|
||||
<a href="#" class="dropdown" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false"><span class="navbar-toggler-icon"></span></a>
|
||||
<ul class="dropdown-menu dropdown-menu-right sax-dropdown-menu">@* Menu items will be inserted here. *@</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<div class="sax-content">
|
||||
<div class="row">
|
||||
<div class="col-sm-12"><div class="ArticleSummary"></div></div>
|
||||
<div class="col-6"><div class="ArticleSportCaption sax-note"></div></div>
|
||||
<div class="col-6 right"><div class="ArticleRegionCaption sax-note"></div></div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-sm-4"><div class="sax-note">@Localiser["label.created"]: <span class="ArticleCreatedOn"></span></div></div>
|
||||
<div class="col-sm-4"><div class="ArticlePublished sax-note">@Localiser["label.published"]: <span class="ArticlePublishedOn"></span></div></div>
|
||||
<div class="col-sm-4 right"><div class="ArticleStatusDesc sax-note"></div></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@* Burger dropdown item template - ul is ignored *@
|
||||
<ul class="sax-dropdown-menu Article">
|
||||
<li class="sax-dropdown-item sax-action"><div class="sax-label">...</div></li>
|
||||
</ul>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<partial name="~/Views/Common/OrganisationSelect.cshtml" />
|
||||
<partial name="Panel-ArticleDialog.cshtml" />
|
||||
@@ -0,0 +1,219 @@
|
||||
@model Model_Article
|
||||
@inject SaxLocaliser Localiser
|
||||
@{
|
||||
/* Articles - Article dialog panel */
|
||||
}
|
||||
|
||||
<script type="text/javascript">
|
||||
sax.dlg.title.createArticle = '@Localiser.GetJavascriptText("article.caption.article.create")';
|
||||
sax.dlg.title.updateArticle = '@Localiser.GetJavascriptText("article.caption.article.update")';
|
||||
sax.dlg.title.selectRegion = '@Localiser.GetJavascriptText("reference.caption.region.select")';
|
||||
sax.dlg.title.selectSport = '@Localiser.GetJavascriptText("reference.caption.sport.select")';
|
||||
</script>
|
||||
|
||||
@* Article Id form *@
|
||||
@using (@Html.BeginForm(FormMethod.Post, new { @id = "frmArticleId", @class = "sax-form" }))
|
||||
{
|
||||
@Html.HiddenFor(model => model.ArticleId, new { @class = "ArticleId" })
|
||||
}
|
||||
|
||||
@* Article dialog and form *@
|
||||
<div id="dlgArticle" class="sax-dialog" title="">
|
||||
|
||||
@using (@Html.BeginForm(FormMethod.Post, new { @id = "frmArticle", @class = "sax-form", @onSubmit = "return false;" }))
|
||||
{
|
||||
@Html.HiddenFor(model => model.ArticleId, new { @id = "ifArticleId", @class = "ArticleId" })
|
||||
@Html.HiddenFor(model => model.ArticleExists, new { @id = "ifArticleExists", @class = "ArticleExists" })
|
||||
@Html.HiddenFor(model => model.ArticleOrganisationId, new { @id = "ifArticleOrganisationId", @class = "ArticleOrganisationId" })
|
||||
|
||||
<div class="sax-article">
|
||||
|
||||
<div class="sax-article-panel sax-article-header">
|
||||
<div class="spacer2"></div>
|
||||
|
||||
@* Organisation *@
|
||||
<div class="sax-form-control ArticleOrganisation">
|
||||
<div class="row">
|
||||
<div class="col-sm-3">
|
||||
<div class="sax-label pt4 pr8">
|
||||
<label for="ifArticleOrganisation"><span>@Localiser["label.organisation"]</span></label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-sm">
|
||||
<div class="sax-control">
|
||||
<input type="text" id="ifArticleOrganisation" class="ArticleOrganisation sax-input" readonly="readonly" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@* Article headline *@
|
||||
<div class="sax-form-control ArticleHeadline">
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<div class="sax-label"><label for="ifArticleHeadline"><span>@Localiser["label.headline"]</span><span class="required"> *</span></label></div>
|
||||
</div>
|
||||
<div class="fixed right"><div class="sax-info"></div></div>
|
||||
</div>
|
||||
<div class="sax-control">
|
||||
@Html.TextBoxFor(model => model.ArticleHeadline, new { @id = "ifArticleHeadline", @class = "ArticleHeadline sax-input", @maxlength = @Model.GetControlMaxLength(SaxDbDfn_Core.ColumnIdx.Article_Headline) })
|
||||
</div>
|
||||
<div class="sax-message"></div>
|
||||
</div>
|
||||
|
||||
@* Article summary *@
|
||||
<div class="sax-form-control ArticleSummary">
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<div class="sax-label"><label for="ifArticleSummary"><span>@Localiser["label.summary"]</span><span class="required"> *</span></label></div>
|
||||
</div>
|
||||
<div class="fixed right"><div class="sax-info"></div></div>
|
||||
</div>
|
||||
<div class="sax-control">
|
||||
@Html.TextAreaFor(model => model.ArticleSummary, new { @id = "ifArticleSummary", @class = "ArticleSummary sax-textarea", @rows = 6, @maxlength = @Model.GetControlMaxLength(SaxDbDfn_Core.ColumnIdx.Article_Summary) })
|
||||
</div>
|
||||
<div class="sax-message"></div>
|
||||
</div>
|
||||
|
||||
@* Sport *@
|
||||
<div class="sax-form-control ArticleSportId">
|
||||
<div class="row">
|
||||
<div class="col-sm-3">
|
||||
<div class="sax-label">
|
||||
<label for="ifArticleSportId"><span>@Localiser["label.sport"]</span><span class="required"> *</span></label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-sm">
|
||||
<div class="sax-control row">
|
||||
@Html.HiddenFor(model => model.ArticleSportId, new { @id = "ifArticleSportId", @class = "ArticleSportId" })
|
||||
<div class="col">@Html.TextBoxFor(model => model.ArticleSportCaption, new { @id = "ifArticleSportCaption", @class = "ArticleSportCaption sax-input", @readonly = "readonly", @onDblClick = "sax.selectSport()" }) </div>
|
||||
<div class="fixed"><button class="SelectSport sax-button" style="min-width:auto;margin-left:4px;padding:4px 6px">@Localiser["label.select"]</button></div>
|
||||
</div>
|
||||
<div class="sax-message"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@* Region *@
|
||||
<div class="sax-form-control ArticleRegionId">
|
||||
<div class="row">
|
||||
<div class="col-sm-3">
|
||||
<div class="sax-label">
|
||||
<label for="ifArticleRegionId"><span>@Localiser["label.region"]</span><span class="required"> *</span></label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-sm">
|
||||
<div class="sax-control row">
|
||||
@Html.HiddenFor(model => model.ArticleRegionId, new { @id = "ifArticleRegionId", @class = "ArticleRegionId" })
|
||||
<div class="col">@Html.TextBoxFor(model => model.ArticleRegionCaption, new { @id = "ifArticleRegionCaption", @class = "ArticleRegionCaption sax-input", @readonly = "readonly", @onDblClick = "sax.selectRegion()" }) </div>
|
||||
<div class="fixed"><button class="SelectRegion sax-button" style="min-width:auto;margin-left:4px;padding:4px 6px">@Localiser["label.select"]</button></div>
|
||||
</div>
|
||||
<div class="sax-message"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@* Publication *@
|
||||
<div class="sax-form-control ArticlePublication">
|
||||
<div class="row">
|
||||
<div class="col-sm-3">
|
||||
<div class="sax-label">
|
||||
<label for="ifArticleRegionId"><span>@Localiser["label.publication"]</span></label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-sm">
|
||||
<div class="sax-control">
|
||||
<div class="row ArticlePublish">
|
||||
@Html.HiddenFor(model => model.ArticlePublished, new { @id = "ifArticlePublished" })
|
||||
<div class="fixed"><div class="pl16 pt4 pr8">@Html.CheckBoxFor(model => model.ArticlePublish, new { @id = "chkArticlePublish", @class = "ArticlePublish" }) <span class="" onclick="$('#chkArticlePublish').click()">@Localiser["label.publish"]</span></div></div>
|
||||
<div class="col">@Html.TextBoxFor(model => model.ArticlePublishOn, new { @id = "ifArticlePublishOn", @class = "sax-input sax-calendar ArticlePublishOn", @readonly = "readonly" })</div>
|
||||
</div>
|
||||
<div class="ArticlePublished">
|
||||
<div class=""><div class="">@Localiser["label.published"]: <span class="ArticlePublishedOn"></span></div></div>
|
||||
<div class=""><div class="">@Localiser["label.feedback"]: <span class="ArticleFeedback"></span></div></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="sax-message"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="spacer2"></div>
|
||||
</div>
|
||||
|
||||
<div class="sax-article-panel sax-article-content">
|
||||
|
||||
<div class="sax-article-segment-list">
|
||||
</div>
|
||||
|
||||
<div class="sax-panel-item-template">
|
||||
<div class="sax-panel-item ArticleSegment">
|
||||
@* Inputs with same name for every segment to ensure they are uploaded as a list. *@
|
||||
<input type="hidden" name="ArticleContentSegmentBodies" class="ArticleContentSegmentBody" value="" />
|
||||
<input type="hidden" name="ArticleContentSegmentItemImageIds" class="ArticleContentSegmentItemImageId" value="" />
|
||||
<input type="hidden" name="ArticleContentSegmentImageIdxs" class="ArticleContentSegmentImageIdx" value="" />
|
||||
@* Image drop panel *@
|
||||
<div class="sax-panel-file-drop row">
|
||||
<div class="col">Drop image here</div>
|
||||
<div class="fixed">
|
||||
<img class="ContactImageUploadProgress" src="~/img/animated/progress-basketball-32.gif" style="display:none;margin:8px 4px;" />
|
||||
</div>
|
||||
</div>
|
||||
@* Segment details *@
|
||||
<div class="row">
|
||||
@* Segment body *@
|
||||
<div class="col">
|
||||
<div class="sax-article-segment-body"></div>
|
||||
<div class="sax-article-segment-image hidden"><img src="" alt="" title="" /></div>
|
||||
</div>
|
||||
<div class="fixed sax-actions">
|
||||
@* Segment actions *@
|
||||
<div class="sax-action sax-add"><img src="~/img/action/add24.png" alt="" title="" /></div>
|
||||
<div class="sax-action sax-add-image"><img src="~/img/action/image-add-24.png" alt="" title="" /></div>
|
||||
<div class="sax-action sax-up"><img src="~/img/action/upload24.png" alt="" title="" /></div>
|
||||
<div class="sax-action sax-down"><img src="~/img/action/download24.png" alt="" title="" /></div>
|
||||
<div class="sax-action sax-delete"><img src="~/img/action/delete24.png" alt="" title="" /></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
}
|
||||
</div>
|
||||
|
||||
@* Article Image upload dialog and form *@
|
||||
<div id="dlgSelectArticleImage" class="sax-dialog">
|
||||
@using (@Html.BeginForm(FormMethod.Post, new { @id = "frmSelectArticleImage", @class = "sax-form", @onSubmit = "return false;" }))
|
||||
{
|
||||
<input type="hidden" class="SegmentIdx" />
|
||||
<div class="spacer4"></div>
|
||||
<div class="sax-form-control ArticleImage">
|
||||
<div class="row">
|
||||
<div class="fixed"><div style="padding:0 12px;">@Localiser["label.image"]</div></div>
|
||||
<div class="col"><input type="file" id="ifArticleImage" name="" class="fullwidth" style="" /></div>
|
||||
</div>
|
||||
<div class="sax-message"></div>
|
||||
</div>
|
||||
<div class="spacer2"></div>
|
||||
<div class="row">
|
||||
<div class="col"><div class="UploadMessage"></div></div>
|
||||
<div class="fixed"><img class="ArticleImageUploadProgress" src="~/img/animated/progress-basketball-32.gif" style="display:none;margin:8px 4px;" /></div>
|
||||
</div>
|
||||
<div class="spacer2"></div>
|
||||
}
|
||||
</div>
|
||||
|
||||
<script type="text/javascript">
|
||||
sax.dlg.title.imageUpload = '@Localiser.GetJavascriptText("account.caption.image.upload")';
|
||||
sax.msg.uploadFileSelect = '@Localiser.GetJavascriptText("msg.upload.file.select")';
|
||||
sax.msg.uploadImageSingle = '@Localiser.GetJavascriptText("msg.upload.image.single")';
|
||||
sax.msg.uploadFileSizeMax = '@Localiser.GetJavascriptText("msg.upload.file.size.max","{0}")';
|
||||
sax.msg.uploadFileTypeInvalid = '@Localiser.GetJavascriptText("msg.upload.file.type.invalid","{0}")';
|
||||
sax.msg.uploadingFile = '@Localiser.GetJavascriptText("msg.upload.file.uploading","{0}")';
|
||||
</script>
|
||||
<partial name="~/Views/Common/SportSelect.cshtml" />
|
||||
<partial name="~/Views/Common/RegionSelect.cshtml" />
|
||||
@@ -0,0 +1,59 @@
|
||||
@model SaxModel_Online
|
||||
@inject SaxLocaliser Localiser
|
||||
@{
|
||||
/* Online Code Select */
|
||||
// Ensure view is only included once in page.
|
||||
if (!Model.RegisterView(ViewContext)) return;
|
||||
// Scripts.
|
||||
Model.AdditionalFiles_JS.Add("js/sax-code-sel.js");
|
||||
}
|
||||
|
||||
<link rel="stylesheet" href="~/css/sax-code-sel.css?@Model.HrefVersion" />
|
||||
<div id="dlgCodeSelect" class="sax-dialog sax-form" style="padding-bottom:8px;">
|
||||
|
||||
@* Filter *@
|
||||
<div class=""></div>
|
||||
|
||||
<div class="row h-100">
|
||||
|
||||
@* Available codes *@
|
||||
<div class="col-sm-5">
|
||||
|
||||
<div class="h-100 sax-codeSelect-codes AvailableCodes"></div>
|
||||
|
||||
</div>
|
||||
|
||||
@* Code selection *@
|
||||
<div class="col-sm-2">
|
||||
|
||||
<div class="row">
|
||||
|
||||
<div class="col-sx-6 col-sm-12 center">
|
||||
<button class="sax-button Select">@Localiser["label.select"]</button>
|
||||
</div>
|
||||
|
||||
<div class="col-sx-6 col-sm-12 center">
|
||||
<button class="sax-button Remove">@Localiser["label.remove"]</button>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
@* Selected codes *@
|
||||
<div class="col-sm-5">
|
||||
|
||||
<div class="h-100 sax-codeSelect-codes SelectedCodes">
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="sax-panel-item-template">
|
||||
<div class="sax-panel-item Code">
|
||||
<div class="CodeDesc"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
@@ -0,0 +1,50 @@
|
||||
@model SaxModel_Online
|
||||
@inject SaxLocaliser Localiser
|
||||
@{
|
||||
/* Online Contact Methods */
|
||||
// Ensure view is only included once in page.
|
||||
if (!Model.RegisterView(ViewContext)) return;
|
||||
// Scripts.
|
||||
Model.AdditionalFiles_JS.Add("js/sax-cnt-mth.js");
|
||||
}
|
||||
<div id="dlgContactMethod" class="sax-dialog sax-form" title="@Localiser["caption.contact.method"]">
|
||||
<div class="spacer4"></div>
|
||||
|
||||
@* Method *@
|
||||
<div class="sax-form-control ContactMethod">
|
||||
<div class="row">
|
||||
<div class="col-sm-3">
|
||||
<div class="sax-label">
|
||||
<label for=""><span>@Localiser["label.method"]</span></label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-sm">
|
||||
<div class="sax-control">
|
||||
<select name="ContactMethod" class="ContactMethod sax-select" style="max-width:240px;"></select>
|
||||
</div>
|
||||
<div class="sax-message"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="spacer"></div>
|
||||
|
||||
@* Value *@
|
||||
<div class="sax-form-control ContactValue">
|
||||
<div class="row">
|
||||
<div class="col-sm-3">
|
||||
<div class="sax-label">
|
||||
<label for=""><span>@Localiser["label.value"]</span></label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-sm">
|
||||
<div class="sax-control">
|
||||
<input type="text" name="ContactValue" class="ContactValue sax-input" maxlength="200" />
|
||||
</div>
|
||||
<div class="sax-message"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="spacer"></div>
|
||||
</div>
|
||||
|
||||
@@ -0,0 +1,98 @@
|
||||
@* Organisation controls - Address *@
|
||||
@model SaxModel_Online
|
||||
@inject SaxLocaliser Localiser
|
||||
@* NB Organisation address controls may be present more than once on a page, eg. Profile Organisation. *@
|
||||
|
||||
@* Organisation address - Line 1 *@
|
||||
<div class="sax-form-control OrganisationAddressLine1">
|
||||
<div class="row">
|
||||
<div class="col-sm-3">
|
||||
<div class="sax-caption">
|
||||
<label for=""><span>@Localiser["label.address"]</span></label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-sm">
|
||||
<div class="sax-control row">
|
||||
<div class="col"><input type="text" name="Organisation.Address.Line1" class="OrganisationAddressLine1 sax-input" autocomplete="off" maxlength="@Model.GetControlMaxLength(SaxDbDfn_Core.ColumnIdx.ItemAddress_Line1)" /> </div>
|
||||
</div>
|
||||
<div class="sax-message"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@* Organisation address - Line 2 *@
|
||||
<div class="sax-form-control OrganisationAddressLine2">
|
||||
<div class="row">
|
||||
<div class="col-sm-3"></div>
|
||||
<div class="col-sm">
|
||||
<div class="sax-control row">
|
||||
<div class="col"><input type="text" name="Organisation.Address.Line2" class="OrganisationAddressLine2 sax-input" autocomplete="off" maxlength="@Model.GetControlMaxLength(SaxDbDfn_Core.ColumnIdx.ItemAddress_Line2)" /> </div>
|
||||
</div>
|
||||
<div class="sax-message"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@* Organisation address - Line 3 *@
|
||||
<div class="sax-form-control OrganisationAddressLine3">
|
||||
<div class="row">
|
||||
<div class="col-sm-3"></div>
|
||||
<div class="col-sm">
|
||||
<div class="sax-control row">
|
||||
<div class="col"><input type="text" name="Organisation.Address.Line3" class="OrganisationAddressLine3 sax-input" autocomplete="off" maxlength="@Model.GetControlMaxLength(SaxDbDfn_Core.ColumnIdx.ItemAddress_Line3)" /> </div>
|
||||
</div>
|
||||
<div class="sax-message"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@* Organisation address - Town *@
|
||||
<div class="sax-form-control OrganisationAddressTown">
|
||||
<div class="row">
|
||||
<div class="col-sm-3">
|
||||
<div class="sax-label">
|
||||
<label for=""><span>@Localiser["label.town"]</span><span class="required"> (*)</span></label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-sm">
|
||||
<div class="sax-control row">
|
||||
<div class="col"><input type="text" name="Organisation.Address.Town" class="OrganisationAddressTown sax-input" autocomplete="off" maxlength="@Model.GetControlMaxLength(SaxDbDfn_Core.ColumnIdx.ItemAddress_Town)" /> </div>
|
||||
</div>
|
||||
<div class="sax-message"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@* Organisation address - Province *@
|
||||
<div class="sax-form-control OrganisationAddressProvince">
|
||||
<div class="row">
|
||||
<div class="col-sm-3">
|
||||
<div class="sax-label">
|
||||
<label for=""><span>@Localiser["label.province"]</span></label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-sm">
|
||||
<div class="sax-control row">
|
||||
<div class="col"><input type="text" name="Organisation.Address.Province" class="OrganisationAddressProvince sax-input" autocomplete="off" maxlength="@Model.GetControlMaxLength(SaxDbDfn_Core.ColumnIdx.ItemAddress_Province)" /> </div>
|
||||
</div>
|
||||
<div class="sax-message"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@* Organisation address - PostalCode *@
|
||||
<div class="sax-form-control OrganisationAddressPostalCode">
|
||||
<div class="row">
|
||||
<div class="col-sm-3">
|
||||
<div class="sax-label">
|
||||
<label for=""><span>@Localiser["label.postal.code"]</span></label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-sm">
|
||||
<div class="sax-control row">
|
||||
<div class="col"><input type="text" name="Organisation.Address.PostalCode" class="OrganisationAddressPostalCode sax-input" autocomplete="off" maxlength="@Model.GetControlMaxLength(SaxDbDfn_Core.ColumnIdx.ItemAddress_PostalCode)" /> </div>
|
||||
</div>
|
||||
<div class="sax-message"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -0,0 +1,77 @@
|
||||
@* Organisation controls - Contact *@
|
||||
@model SaxModel_Online
|
||||
@inject SaxLocaliser Localiser
|
||||
@* NB Organisation contact controls may be present more than once on a page, eg. Profile Organisation. *@
|
||||
|
||||
@if (!Model.RegisterView(ViewContext)) return;
|
||||
|
||||
<style>
|
||||
.OrganisationContactMethods .ContactMethods
|
||||
{
|
||||
min-height: 32px;
|
||||
max-height: 64px;
|
||||
background-color: #fff;
|
||||
border: 1px solid #808080;
|
||||
border-top-left-radius: 4px;
|
||||
border-bottom-left-radius: 4px;
|
||||
overflow-y: scroll;
|
||||
}
|
||||
|
||||
.OrganisationContactMethods .ContactMethods table.sax-data tr:hover
|
||||
{
|
||||
background-color: #f0f0f0;
|
||||
}
|
||||
|
||||
.OrganisationContactMethods .ContactMethods table.sax-data .sax-label
|
||||
{
|
||||
margin: 0;
|
||||
padding: 0 8px 0 0;
|
||||
}
|
||||
</style>
|
||||
|
||||
@* Organisation Contact Methods *@
|
||||
<div class="sax-form-control OrganisationContactMethods">
|
||||
<input type="hidden" name="Organisation.ContactMethods" value="0" />
|
||||
<div class="row">
|
||||
<div class="col-sm-3 row">
|
||||
<div class="col">
|
||||
<div class="sax-label">
|
||||
<label for=""><span>@Localiser["label.contact"]</span></label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="fixed">
|
||||
@* Action to add new contact method. *@
|
||||
<div class="sax-actions">
|
||||
<div class="sax-action sax-add pr4"><img src="~/img/action/add24.png" alt="@(Localiser["label.add"])" title="@(Localiser["label.add"])" /></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-sm">
|
||||
<div class="sax-control row">
|
||||
<div class="col">
|
||||
@* List of existing contact methods with actions to edit/remove. *@
|
||||
<div class="ContactMethods">
|
||||
<table class="sax-data fullwidth"></table>
|
||||
</div>
|
||||
<table class="sax-panel-item-template">
|
||||
<tr class="ContactMethod">
|
||||
<td style="width:20px;"><div class="sax-label nowrap"></div></td>
|
||||
<td class="sax-value " style="width:70%;word-break: break-all;"></td>
|
||||
<td class="sax-actions right nowrap" style="min-width:10px;">
|
||||
<input type="hidden" name="Organisation.ContactMethod" />
|
||||
<input type="hidden" name="Organisation.ContactValue" />
|
||||
<div class="nowrap">
|
||||
<div class="inlineb sax-action sax-edit"><img src="~/img/action/edit16.png" alt="@(Localiser["label.edit"])" title="@(Localiser["label.edit"])" /></div>
|
||||
<div class="inlineb sax-action sax-remove"><img src="~/img/action/delete16.png" alt="@(Localiser["label.remove"])" title="@(Localiser["label.remove"])" /></div>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
<div class="sax-message"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<partial name="~/Views/Common/ContactMethods.cshtml" />
|
||||
@@ -0,0 +1,93 @@
|
||||
@* Organisation controls - Core *@
|
||||
@model SaxModel_Online
|
||||
@inject SaxLocaliser Localiser
|
||||
@* NB Core Organisation controls may be present more than once on a page, eg. Profile Organisation. *@
|
||||
|
||||
@* Organisation name *@
|
||||
<div class="sax-form-control OrganisationName">
|
||||
<div class="row">
|
||||
<div class="col-sm-3">
|
||||
<div class="sax-label">
|
||||
<label for=""><span>@Localiser["label.name"]</span><span class="required"> *</span></label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-sm">
|
||||
<div class="sax-control">
|
||||
<input type="text" name="Organisation.Name" class="OrganisationName sax-input" autocomplete="off" maxlength="@Model.GetControlMaxLength(SaxDbDfn_Core.ColumnIdx.Organisation_Name)" />
|
||||
</div>
|
||||
<div class="sax-message"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-sm-3"></div>
|
||||
<div class="col-sm row">
|
||||
|
||||
@* Organisation category *@
|
||||
<div class="col-sm-6">
|
||||
<div class="sax-form-control OrganisationCategory pr4">
|
||||
<div class="sax-label">
|
||||
<label for=""><span>@Localiser["label.category"]</span><span class="required"> *</span></label>
|
||||
</div>
|
||||
<div class="sax-control">
|
||||
@Html.DropDownList("", Model.OrganisationCategoriesForSelect, Localiser["label.select"] + ":", new { @id = "", @name = "Organisation.Category", @class = "OrganisationCategory sax-select" })
|
||||
</div>
|
||||
<div class="sax-message"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@* Organisation type *@
|
||||
<div class="col-sm-6">
|
||||
<div class="sax-form-control OrganisationType">
|
||||
<div class="sax-label">
|
||||
<label for=""><span>@Localiser["label.type"]</span><span class="required"> *</span></label>
|
||||
</div>
|
||||
<div class="sax-control">
|
||||
@Html.DropDownList("", Model.OrganisationTypesForSelect, Localiser["label.select"] + ":", new { @id = "", @name = "Organisation.Type", @class = "OrganisationType sax-select" })
|
||||
</div>
|
||||
<div class="sax-message"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@* Organisation sport *@
|
||||
<div class="sax-form-control OrganisationSportId">
|
||||
<div class="row">
|
||||
<div class="col-sm-3">
|
||||
<div class="sax-label">
|
||||
<label for=""><span>@Localiser["label.sport"]</span><span class="required"> (*)</span></label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-sm">
|
||||
<div class="sax-control row">
|
||||
<input type="hidden" name="Organisation.SportId" class="OrganisationSportId" />
|
||||
<div class="col"><input type="text" class="OrganisationSportName sax-input" readonly="readonly" /> </div>
|
||||
<div class="fixed"><button class="SelectOrganisationSport sax-button" style="min-width:auto;margin-left:4px;padding:4px 6px">@Localiser["label.select"]</button></div>
|
||||
</div>
|
||||
<div class="sax-message"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@* Organisation primary region *@
|
||||
<div class="sax-form-control OrganisationRegionIdPrimary">
|
||||
<div class="row">
|
||||
<div class="col-sm-3">
|
||||
<div class="sax-label">
|
||||
<label for=""><span>@Localiser["label.region"]</span><span class="required"> *</span></label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-sm">
|
||||
<div class="sax-control row">
|
||||
<input type="hidden" name="Organisation.RegionIdPrimary" class="OrganisationRegionIdPrimary" />
|
||||
<div class="col"><input type="text" class="OrganisationRegionNamePrimary sax-input" readonly="readonly" /> </div>
|
||||
<div class="fixed"><button class="SelectOrganisationRegionPrimary sax-button" style="min-width:auto;margin-left:4px;padding:4px 6px">@Localiser["label.select"]</button></div>
|
||||
</div>
|
||||
<div class="sax-message"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -0,0 +1,103 @@
|
||||
@model SaxModel_Online
|
||||
@inject SaxLocaliser Localiser
|
||||
|
||||
@{
|
||||
/* Online Organisation Request. */
|
||||
// Ensure view is only included once in page.
|
||||
if (!Model.RegisterView(ViewContext)) return;
|
||||
// Scripts.
|
||||
Model.AdditionalFiles_JS.Add("js/sax-org-req.js");
|
||||
Microsoft.AspNetCore.Html.HtmlString regionIdCountry = new Microsoft.AspNetCore.Html.HtmlString(Model.ValidUserSession ? Model.GetEncryptedRegionId(Model.SessionData.User.RegionIdCountry) : "");
|
||||
String regionNameCountry = Model.ValidUserSession ? Localiser.EscapeJavascriptText(Model.GetRegionCaption(Model.SessionData.User.RegionIdCountry)) : "";
|
||||
}
|
||||
<script type="text/javascript">
|
||||
let or = sax.orgReq = {};
|
||||
or.dlgTitleRequestOrganisation = '@Localiser.GetJavascriptText("organisation.caption.organisation.request")';
|
||||
sax.data.regionIdCountryDefault = '@regionIdCountry';
|
||||
sax.data.regionNameCountryDefault = '@regionNameCountry';
|
||||
</script>
|
||||
|
||||
<div id="dlgOrganisationRequest" class="sax-dialog sax-form">
|
||||
|
||||
@using (@Html.BeginForm(FormMethod.Post, new { @id = "frmOrganisationRequest", @class = "sax-form", @onSubmit = "return false;" }))
|
||||
{
|
||||
|
||||
@* Contact details are only required when user not logged in. *@
|
||||
@if (!Model.ValidUserSession)
|
||||
{
|
||||
|
||||
<div class="sax-form-control pt8">
|
||||
<div class="sax-caption">
|
||||
<label for="ifContactEmailAddress"><span>@Localiser["label.contact.details"]</span></label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@* Contact Email Address *@
|
||||
<div class="sax-form-control ContactEmailAddress">
|
||||
<div class="row">
|
||||
<div class="col-sm-3">
|
||||
<div class="sax-label">
|
||||
<label for="ifContactEmailAddress"><span>@Localiser["label.email"]</span><span class="required"> *</span></label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-sm">
|
||||
<div class="sax-control">
|
||||
<input type="text" id="ifContactEmailAddress" name="ContactEmailAddress" class="ContactEmailAddress sax-input" autocomplete="off" maxlength="@Model.GetControlMaxLength(SaxDbDfn_Core.ColumnIdx.UserAccount_EmailAddress)" />
|
||||
</div>
|
||||
<div class="sax-message"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-sm-3">@* No label. *@</div>
|
||||
<div class="col-sm row">
|
||||
|
||||
@* Contact First Name *@
|
||||
<div class="col-sm-6">
|
||||
<div class="sax-form-control ContactFirstName pr4">
|
||||
<div class="sax-label">
|
||||
<label for="cbContactFirstName"><span>@Localiser["label.first.name"]</span><span class="required"> *</span></label>
|
||||
</div>
|
||||
<div class="sax-control">
|
||||
<input type="text" id="ifContactFirstName" name="ContactFirstName" class="ContactFirstName sax-input" autocomplete="off" maxlength="@Model.GetControlMaxLength(SaxDbDfn_Core.ColumnIdx.UserAccount_FirstName)" />
|
||||
</div>
|
||||
<div class="sax-message"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@* Contact Last Name *@
|
||||
<div class="col-sm-6">
|
||||
<div class="sax-form-control ContactLastName">
|
||||
<div class="sax-label">
|
||||
<label for="cbContactLastName"><span>@Localiser["label.last.name"]</span><span class="required"> *</span></label>
|
||||
</div>
|
||||
<div class="sax-control">
|
||||
<input type="text" id="ifContactLastName" name="ContactLastName" class="ContactLastName sax-input" autocomplete="off" maxlength="@Model.GetControlMaxLength(SaxDbDfn_Core.ColumnIdx.UserAccount_LastName)" />
|
||||
</div>
|
||||
<div class="sax-message"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
}
|
||||
|
||||
@* Organisation core details - name, category, sport, region etc *@
|
||||
<div class="sax-form-control">
|
||||
<div class="sax-caption">
|
||||
<label for=""><span>@Localiser["label.organsiation.details"]</span></label>
|
||||
</div>
|
||||
</div>
|
||||
<partial name="~/Views/Common/OrganisationControls-Core.cshtml" />
|
||||
|
||||
@* Organisation Address *@
|
||||
<partial name="~/Views/Common/OrganisationControls-Address.cshtml" />
|
||||
|
||||
}
|
||||
|
||||
</div>
|
||||
|
||||
<partial name="~/Views/Common/SportSelect.cshtml" />
|
||||
<partial name="~/Views/Common/RegionSelect.cshtml" />
|
||||
@@ -0,0 +1,52 @@
|
||||
@model SaxModel_Online
|
||||
@inject SaxLocaliser Localiser
|
||||
@{
|
||||
/* Online Organisation Select. */
|
||||
// Ensure view is only included once in page.
|
||||
if (!Model.RegisterView(ViewContext)) return;
|
||||
// Scripts.
|
||||
Model.AdditionalFiles_JS.Add("js/sax-org-sel.js");
|
||||
}
|
||||
|
||||
<link rel="stylesheet" href="~/css/sax-org-sel.css?@Model.HrefVersion" />
|
||||
<script type="text/javascript">
|
||||
sax.selectOrganisation = sax.selectOrganisation || {};
|
||||
sax.selectOrganisation.dlgTitleSelectOrganisation = '@Localiser.GetJavascriptText("organisation.caption.organisation.select")';
|
||||
</script>
|
||||
<div id="dlgSelectOrganisation" class="sax-dialog sax-form">
|
||||
|
||||
@* Filter *@
|
||||
<div class="sax-panel-filter">
|
||||
|
||||
<div class="sax-content">
|
||||
|
||||
@using (@Html.BeginForm(FormMethod.Post, new { @id = "frmSelectOrganisationFilter", @class = "sax-form", @onSubmit = "return false;" }))
|
||||
{
|
||||
<input type="hidden" class="FilterRegionId" name="Filter.RegionId" />
|
||||
<input type="hidden" class="FilterSportId" name="Filter.SportId" />
|
||||
<input type="hidden" class="FilterPageLength" name="DataPageLength" value="0" />
|
||||
<input type="hidden" class="FilterPageNo" name="DataPageNo" value="0" />
|
||||
<div class="row">
|
||||
<div class="col-sm-5 sax-label text-left text-sm-right">@Localiser["label.search"]</div>
|
||||
<div class="col-sm-7"><input type="search" class="sax-input FilterOrganisation" name="Filter.Organisation" maxlength="32" autocomplete="off" /></div>
|
||||
</div>
|
||||
}
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="">
|
||||
|
||||
@* Organisations *@
|
||||
<div class="sax-selection-results Organisations"></div>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="sax-panel-item-template">
|
||||
<div class="sax-panel-item Organisation">
|
||||
<div class="Name"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
@@ -0,0 +1,56 @@
|
||||
@model SaxModel_Online
|
||||
@inject SaxLocaliser Localiser
|
||||
@{
|
||||
/* Online Region Select */
|
||||
// Ensure view is only included once in page.
|
||||
if (!Model.RegisterView(ViewContext)) return;
|
||||
// Scripts.
|
||||
Model.AdditionalFiles_JS.Add("js/sax-reg-sel.js");
|
||||
}
|
||||
|
||||
<link rel="stylesheet" href="~/css/sax-reg-sel.css?@Model.HrefVersion" />
|
||||
<script type="text/javascript">
|
||||
</script>
|
||||
|
||||
<div id="dlgSelectRegion" class="sax-dialog sax-form">
|
||||
|
||||
<div class="container-fluid h-100">
|
||||
|
||||
@* Selected Region *@
|
||||
<div class="SelectedRegion">
|
||||
<div class="row">
|
||||
<div class="col-12"><div class="sax-label">@Localiser["label.region.selected"]:</div></div>
|
||||
<div class="col-12"><div class="SelectedRegionName"></div></div>
|
||||
</div>
|
||||
<div class="spacer2"></div>
|
||||
</div>
|
||||
|
||||
@* Region Filter *@
|
||||
<div class="RegionFilter sax-form">
|
||||
<div class="row">
|
||||
<div class="col right"><div class="sax-label">@Localiser["label.search"]</div></div>
|
||||
<div class="fixed"><input type="search" id="ifRegionFilter" class="sax-input" maxlength="16" autocomplete="off" onkeyup="sax.mdl.selectRegion.fn.displayRegions();" /></div>
|
||||
</div>
|
||||
<div class="spacer2"></div>
|
||||
</div>
|
||||
|
||||
@* Available regions *@
|
||||
<div class="row">
|
||||
<div class="col"><div class="sax-label bottom">@Localiser["label.regions.available"]:</div></div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
|
||||
<div class="col-12 sax-selectRegion-regions AvailableRegions"></div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="sax-panel-item-template">
|
||||
<div class="sax-panel-item Region">
|
||||
<div class="RegionName"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
@@ -0,0 +1,27 @@
|
||||
@model SaxModel_Online
|
||||
@inject SaxLocaliser Localiser
|
||||
@{
|
||||
/* Online Results Paging. */
|
||||
// NB View can be included more than once on a page.
|
||||
// Scripts.
|
||||
Model.AdditionalFiles_JS.Add("js/sax-res-pag.js");
|
||||
}
|
||||
|
||||
<script type="text/javascript">
|
||||
sax.mdl.resultsPaging = sax.mdl.resultsPaging || {msg:{}};
|
||||
sax.mdl.resultsPaging.msg.pageInfo = '@Localiser.GetJavascriptText("label.page.info","{0}","{1}")';
|
||||
</script>
|
||||
|
||||
@* Results paging *@
|
||||
<div class="sax-results-paging hidden">
|
||||
|
||||
@Html.HiddenFor(model => model.Paging.PageNoValue, new { @id = "", @class = "PagingPageNo" })
|
||||
@Html.HiddenFor(model => model.Paging.PageLengthValue, new { @id = "", @class = "PagingPageLength" })
|
||||
|
||||
<div class="iblock sax-action sax-paging-first"><img src="~/img/action/first24.png" alt="@(Localiser["label.first"])" title="@(Localiser["label.first"])" /></div>
|
||||
<div class="iblock sax-action sax-paging-prev"><img src="~/img/action/prev24.png" alt="@(Localiser["label.previous"])" title="@(Localiser["label.previous"])" /></div>
|
||||
<div class="iblock sax-paging-info"></div>
|
||||
<div class="iblock sax-action sax-paging-next"><img src="~/img/action/next24.png" alt="@(Localiser["label.next"])" title="@(Localiser["label.next"])" /></div>
|
||||
<div class="iblock sax-action sax-paging-last"><img src="~/img/action/last24.png" alt="@(Localiser["label.last"])" title="@(Localiser["label.last"])" /></div>
|
||||
|
||||
</div>
|
||||
@@ -0,0 +1,106 @@
|
||||
@model SaxModel_Online
|
||||
@inject SaxLocaliser Localiser
|
||||
@{
|
||||
// Sport Contacts.
|
||||
// Ensure view is only included once in page.
|
||||
if (!Model.RegisterView(ViewContext)) return;
|
||||
// Scripts.
|
||||
Model.AdditionalFiles_JS.Add("js/sax-spt-cnt.js");
|
||||
}
|
||||
<link rel="stylesheet" href="~/css/sax-spt-cnt.css?@Model.HrefVersion" />
|
||||
<div id="dlgSportContact" class="sax-dialog sax-form" style="padding-bottom:8px;">
|
||||
<div class="spacer4"></div>
|
||||
@using (Html.BeginForm(FormMethod.Post, new { @id = "frmProfileSportContact", @class = "sax-form", @onSubmit = "return false;" }))
|
||||
{
|
||||
|
||||
@* Contact type *@
|
||||
<div class="sax-form-control ContactType">
|
||||
<div class="row">
|
||||
<div class="col-sm-3">
|
||||
<div class="sax-label">
|
||||
<label for=""><span>@Localiser["label.contact"]</span><span class="required"> *</span></label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-sm">
|
||||
<div class="sax-control">
|
||||
<select name="SportContact.Type" class="ContactType sax-select" style="max-width:240px;"></select>
|
||||
</div>
|
||||
<div class="sax-message"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="spacer"></div>
|
||||
|
||||
@* User email *@
|
||||
<div class="sax-form-control ContactEmailAddress">
|
||||
<div class="row">
|
||||
<div class="col-sm-3">
|
||||
<div class="sax-label">
|
||||
<label for="ifContactEmailAddress"><span>@Localiser["label.email"]</span></label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-sm">
|
||||
<div class="sax-control">
|
||||
<input type="text" id="ifContactEmailAddress" name="SportContact.EmailAddress" class="ContactEmailAddress sax-input" maxlength="@Model.GetControlMaxLength(SaxDbDfn_Core.ColumnIdx.UserAccount_EmailAddress)" />
|
||||
</div>
|
||||
<div class="sax-message"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@* Contact Name *@
|
||||
<div class="row">
|
||||
|
||||
<div class="col-sm-3">
|
||||
<div class="sax-label d-none d-sm-block">
|
||||
<label for="ifContactFirstName"><span>@Localiser["label.name"]</span></label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-sm row">
|
||||
|
||||
<div class="col-sm-4">
|
||||
@* Contact Title *@
|
||||
<div class="sax-form-control ContactTitle pr8">
|
||||
<div class="sax-label">
|
||||
<label for="cbContactTitle"><span>@Localiser["label.title"]</span></label>
|
||||
</div>
|
||||
<div class="sax-control">
|
||||
<select name="SportContact.Title" class="ContactTitle sax-select"></select>
|
||||
</div>
|
||||
<div class="sax-message"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-sm-4">
|
||||
@* Contact first name *@
|
||||
<div class="sax-form-control ContactFirstName pr8">
|
||||
<div class="sax-label">
|
||||
<label for="ifContactFirstName"><span>@Localiser["label.first.name"]</span><span class="required"> *</span></label>
|
||||
</div>
|
||||
<div class="sax-control">
|
||||
<input type="text" name="SportContact.FirstName" class="ContactFirstName sax-input" maxlength="@Model.GetControlMaxLength(SaxDbDfn_Core.ColumnIdx.UserAccount_FirstName)" />
|
||||
</div>
|
||||
<div class="sax-message"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-sm-4">
|
||||
@* Contact last name *@
|
||||
<div class="sax-form-control ContactLastName">
|
||||
<div class="sax-label">
|
||||
<label for="ifContactLastName"><span>@Localiser["label.last.name"]</span><span class="required"> *</span></label>
|
||||
</div>
|
||||
<div class="sax-control">
|
||||
<input type="text" name="SportContact.LastName" class="ContactLastName sax-input" maxlength="@Model.GetControlMaxLength(SaxDbDfn_Core.ColumnIdx.UserAccount_LastName)" />
|
||||
</div>
|
||||
<div class="sax-message"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
}
|
||||
<div class="spacer"></div>
|
||||
</div>
|
||||
@@ -0,0 +1,80 @@
|
||||
@* Organisation controls - Contact *@
|
||||
@model SaxModel_Online
|
||||
@inject SaxLocaliser Localiser
|
||||
@* NB Organisation contact controls may be present more than once on a page, eg. Profile Organisation. *@
|
||||
|
||||
@if (!Model.RegisterView(ViewContext)) return;
|
||||
|
||||
<style>
|
||||
.SportContacts .Contacts
|
||||
{
|
||||
min-height: 32px;
|
||||
max-height: 64px;
|
||||
background-color: #fff;
|
||||
border: 1px solid #808080;
|
||||
border-top-left-radius: 4px;
|
||||
border-bottom-left-radius: 4px;
|
||||
overflow-y: scroll;
|
||||
}
|
||||
|
||||
.SportContacts.Contacts table.sax-data tr:hover
|
||||
{
|
||||
background-color: #f0f0f0;
|
||||
}
|
||||
|
||||
.SportContacts .Contacts table.sax-data .sax-label
|
||||
{
|
||||
margin: 0;
|
||||
padding: 0 8px 0 0;
|
||||
}
|
||||
</style>
|
||||
|
||||
@* Sport Contacts *@
|
||||
<div class="sax-form-control SportContacts">
|
||||
<input type="hidden" name="Contacts.Count" value="0" />
|
||||
<div class="row">
|
||||
<div class="col-sm-3 row">
|
||||
<div class="col">
|
||||
<div class="sax-label">
|
||||
<label for=""><span>@Localiser["label.contacts"]</span></label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="fixed">
|
||||
@* Action to add new contact. *@
|
||||
<div class="sax-actions">
|
||||
<div class="sax-action sax-add pr4"><img src="~/img/action/add24.png" alt="@(Localiser["label.add"])" title="@(Localiser["label.add"])" /></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-sm">
|
||||
<div class="sax-control row">
|
||||
<div class="col">
|
||||
@* List of existing contacts with actions to edit/remove. *@
|
||||
<div class="Contacts">
|
||||
<table class="sax-data fullwidth"></table>
|
||||
</div>
|
||||
<table class="sax-panel-item-template">
|
||||
<tr class="Contact">
|
||||
<td style="width:20px;"><div class="sax-label nowrap"></div></td>
|
||||
<td class="sax-value Name" style="width:40%;word-break: break-all;"></td>
|
||||
<td class="sax-value Details" style="width:40%;overflow-x:hidden;"></td>
|
||||
<td class="sax-actions right nowrap" style="min-width:10px;">
|
||||
<input type="hidden" name="Contacts.ContactType" />
|
||||
<input type="hidden" name="Contacts.Title" />
|
||||
<input type="hidden" name="Contacts.FirstName" />
|
||||
<input type="hidden" name="Contacts.LastName" />
|
||||
<input type="hidden" name="Contacts.Phone" />
|
||||
<input type="hidden" name="Contacts.EmailAddress" />
|
||||
<div class="nowrap">
|
||||
<div class="inlineb sax-action sax-edit"><img src="~/img/action/edit16.png" alt="@(Localiser["label.edit"])" title="@(Localiser["label.edit"])" /></div>
|
||||
<div class="inlineb sax-action sax-remove"><img src="~/img/action/delete16.png" alt="@(Localiser["label.remove"])" title="@(Localiser["label.remove"])" /></div>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
<div class="sax-message"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -0,0 +1,53 @@
|
||||
@model SaxModel_Online
|
||||
@inject SaxLocaliser Localiser
|
||||
@{
|
||||
/* Online Sport Select */
|
||||
// Ensure view is only included once in page.
|
||||
if (!Model.RegisterView(ViewContext)) return;
|
||||
// Scripts.
|
||||
Model.AdditionalFiles_JS.Add("js/sax-spt-sel.js");
|
||||
}
|
||||
|
||||
<link rel="stylesheet" href="~/css/sax-spt-sel.css?@Model.HrefVersion" />
|
||||
<div id="dlgSelectSport" class="sax-dialog sax-form">
|
||||
|
||||
<div class="container-fluid h-100">
|
||||
|
||||
@* Selected Sport *@
|
||||
<div class="SelectedSport">
|
||||
<div class="row">
|
||||
<div class="col-12"><div class="sax-label">@Localiser["label.sport.selected"]</div></div>
|
||||
<div class="col-12"><div class="SelectedSportName"></div></div>
|
||||
</div>
|
||||
<div class="spacer2"></div>
|
||||
</div>
|
||||
|
||||
@* Sport Filter *@
|
||||
<div class="SportFilter sax-form">
|
||||
<div class="row">
|
||||
<div class="col right"><div class="sax-label">@Localiser["label.search"]</div></div>
|
||||
<div class="fixed"><input type="search" id="ifSportFilter" class="sax-input" maxlength="16" autocomplete="off" oninput="sax.mdl.selectSport.fn.displaySports();" /></div>
|
||||
</div>
|
||||
<div class="spacer2"></div>
|
||||
</div>
|
||||
|
||||
@* Available sports *@
|
||||
<div class="row">
|
||||
<div class="col"><div class="sax-label bottom">@Localiser["label.sports.available"]:</div></div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
|
||||
<div class="col-12 sax-selectSport-sports AvailableSports"></div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="sax-panel-item-template">
|
||||
<div class="sax-panel-item Sport">
|
||||
<div class="SportName"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
@@ -0,0 +1,152 @@
|
||||
@model Model_Home
|
||||
@inject SaxLocaliser Localiser
|
||||
@{
|
||||
ViewData["Title"] = "Home";
|
||||
}
|
||||
|
||||
@if (Model.AwaitingLogin)
|
||||
{
|
||||
@* No user session *@
|
||||
<div class="text-center">
|
||||
<h1 class="display-4">@Localiser["home.caption.welcome"]</h1>
|
||||
</div>
|
||||
<div class="spacer8"></div>
|
||||
|
||||
@* Register Organisation *@
|
||||
@if (true)
|
||||
{
|
||||
<div class="sax-panel-info">
|
||||
<div class="sax-content">
|
||||
<div class="sax-para">@Localiser["home.organisation.request.para1"]</div>
|
||||
<div class="sax-para">@Localiser["home.organisation.request.para2"]</div>
|
||||
<div class="sax-para center"><div class="sax-button-cta" onclick="sax.orgReq.fn.requestOrganisation()">@Localiser["home.organisation.request.action"]</div></div>
|
||||
</div>
|
||||
</div>
|
||||
<partial name="~/Views/Common/OrganisationRequest.cshtml" />
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@* User logged in *@
|
||||
|
||||
@* Activity filter *@
|
||||
<div class="sax-panel-filter">
|
||||
<div class="sax-header row">
|
||||
<div class="col"><div class="sax-caption">@Localiser["home.caption.activities"]</div></div>
|
||||
<div class="fixed row">
|
||||
</div>
|
||||
</div>
|
||||
<div class="sax-content">
|
||||
@using (@Html.BeginForm(FormMethod.Post, new { @id = "frmActivityFilter", @class = "sax-form", @action = "#", @method = "POST", onsubmit = "return false;" }))
|
||||
{
|
||||
<div class="row">
|
||||
<div class="col-sm-4"><div class="sax-label text-left text-sm-right">@Localiser["label.search"]</div></div>
|
||||
<div class="col-sm-8"><input type="search" name="Filter.Search" id="ifFilterSearch" class="FilterSearch sax-input" maxlength="64" /></div>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@* Results panel *@
|
||||
<div class="sax-panel-results">
|
||||
<div class="sax-panel-messages"></div>
|
||||
<div class="sax-panel-item-list"></div>
|
||||
|
||||
@* Item templates *@
|
||||
<div class="sax-panel-item-template">
|
||||
@* Activity template *@
|
||||
<div class="sax-panel-item Activity">
|
||||
<div class="sax-header row">
|
||||
<div class="col">
|
||||
<div class="sax-caption">
|
||||
<div class="row">
|
||||
<div class="col"><div class="sax-action ActivityCaption"></div></div>
|
||||
<div class="fixed row">
|
||||
<div class="col sax-action ActivityOrganisation"></div>
|
||||
<div class="fixed right ActivityReaction"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="fixed sax-actions">
|
||||
</div>
|
||||
</div>
|
||||
<div class="sax-content">
|
||||
<div class="row">
|
||||
<div class="fixed ActivityThumbnail"><img src="" class="" alt="" title="" style="max-width:@(Sax.Config.Activities.Thumbnail.DisplayWidthMax_List + "px");max-height:@(Sax.Config.Activities.Thumbnail.DisplayHeightMax_List + "px");padding:0 4px 0 0;" /></div>
|
||||
<div class="col">
|
||||
<div class="row">
|
||||
<div class="col-lg">
|
||||
<div class="ActivityBlurb"></div>
|
||||
<div class="sax-note"><span class="ActivitySport"></span> - <span class="ActivityRegion"></span></div>
|
||||
</div>
|
||||
<div class="fixed">
|
||||
<div class="sax-note ActivityAuthor"></div>
|
||||
<div class="sax-note ActivityPublished">@Localiser["label.published"]: <span class="ActivityPublishedOn"></span></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="fixed ActivityOrganisationLogo"><img src="" class="" alt="" title="" style="max-width:@(Sax.Config.Organisation.Logo.DisplayWidthMax_List + "px");max-height:@(Sax.Config.Organisation.Logo.DisplayHeightMax_List + "px");padding:0 0 0 4px;" /></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@* Activity Id form - to retrieve details for the selected activity. *@
|
||||
@using (@Html.BeginForm(FormMethod.Post, new { @id = "frmActivityId", @class = "", @action = "#", onsubmit = "return false;" }))
|
||||
{
|
||||
<input type="hidden" name="ActivityItemType" class="ActivityItemType" />
|
||||
<input type="hidden" name="ActivityItemId" class="ActivityItemId" />
|
||||
}
|
||||
|
||||
@* Activity React form - to record reaction to the selected activity. *@
|
||||
@using (@Html.BeginForm(FormMethod.Post, new { @id = "frmActivityReact", @class = "", @action = "#", onsubmit = "return false;" }))
|
||||
{
|
||||
<input type="hidden" name="ActivityItemType" class="ActivityItemType" />
|
||||
<input type="hidden" name="ActivityItemId" class="ActivityItemId" />
|
||||
<input type="hidden" name="ActivityReaction" class="ActivityReaction" />
|
||||
}
|
||||
|
||||
@* Activity popup dialog with details. *@
|
||||
<div id="dlgActivity" class="sax-dialog">
|
||||
<div class="sax-content">
|
||||
</div>
|
||||
<div class="sax-panel-item-template">
|
||||
<div class="sax-panel-item Article">
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<div class="ArticleHeadline"></div>
|
||||
<div class="ArticleSummary"></div>
|
||||
</div>
|
||||
<div class="fixed ArticleOrganisationLogo"><img src="" class="" alt="" title="" style="max-width:@(Sax.Config.Organisation.Logo.DisplayWidthMax_Item + "px");max-height:@(Sax.Config.Organisation.Logo.DisplayHeightMax_Item + "px");padding:0 0 4px 4px;" /></div>
|
||||
</div>
|
||||
<div class="ArticleOrigin">
|
||||
<div class="row">
|
||||
<div class="col"><div class="ArticleAuthor"></div></div>
|
||||
<div class="fixed right"><div class="ArticleOrganisation"></div></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="ArticleContent">
|
||||
<div class="ArticleContentSegments"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="sax-panel-item ArticleContentSegment">
|
||||
</div>
|
||||
<div class="sax-panel-item ArticleContentSegmentImage center">
|
||||
<img src="" alt="" title="" />
|
||||
</div>
|
||||
<div class="sax-panel-item Event">
|
||||
<div class="EventOrganisation"></div>
|
||||
<div class="EventAt"></div>
|
||||
<div class="EventSummary"></div>
|
||||
<div class="EventDetails"></div>
|
||||
</div>
|
||||
<div class="sax-panel-item Opportunity">
|
||||
<div class="OpportunityOrganisation"></div>
|
||||
<div class="OpportunityPosition"></div>
|
||||
<div class="OpportunityOutline"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
@@ -0,0 +1,118 @@
|
||||
@model Model_Organisation_Events
|
||||
@inject SaxLocaliser Localiser
|
||||
@{
|
||||
ViewData["Title"] = "Organisation - Events";
|
||||
}
|
||||
|
||||
<div class="sax-panel Events">
|
||||
|
||||
<script type="text/javascript">
|
||||
sax.lbl.edit = '@(Localiser.GetJavascriptText("label.edit"))';
|
||||
sax.lbl.copy = '@(Localiser.GetJavascriptText("label.copy"))';
|
||||
</script>
|
||||
|
||||
@* Filter Form *@
|
||||
@using (@Html.BeginForm(FormMethod.Post, new { @id = "frmEventFilter", @class = "sax-form", @action = "#", @method = "POST", onsubmit = "return false;" }))
|
||||
{
|
||||
|
||||
@* Filter Panel *@
|
||||
<div class="sax-panel-filter">
|
||||
@* Filter header *@
|
||||
<div class="sax-header row">
|
||||
<div class="col"><div class="sax-caption">@Localiser["organisation.caption.events"]</div></div>
|
||||
<div class="fixed row">
|
||||
@* Burger menu *@
|
||||
<ul class="nav navbar-nav navbar-dark navbar-right sax-burger">
|
||||
<li class="dropdown-toggle caret-off">
|
||||
<a href="#" class="dropdown" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false"><span class="navbar-toggler-icon"></span></a>
|
||||
<ul class="dropdown-menu dropdown-menu-right sax-dropdown-menu">@* Menu items will be inserted here. *@</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<div class="sax-content">
|
||||
<div class="sax-control row">
|
||||
<div class="col-sm-3"><div class="sax-label text-left text-sm-right">@Localiser["label.organisation"]</div></div>
|
||||
<div class="col-sm-9 row">
|
||||
@Html.HiddenFor(model => model.Filter.OrganisationId, new { @id = "ifFilterOrganisationId", @class = "FilterOrganisationId" })
|
||||
<div class="col"><input type="text" id="ifFilterOrganisation" class="FilterOrganisation sax-input" readonly="readonly" value="@(Model.Filter.OrganisationCaption)" /></div>
|
||||
<div class="fixed"><button class="sax-button SelectFilterOrganisation">@Localiser["label.select"]</button></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="sax-control row">
|
||||
<div class="col-sm-3"><div class="sax-label text-left text-sm-right">@Localiser["label.period"]</div></div>
|
||||
<div class="col-sm-3">@Html.DropDownListFor(model => model.Filter.Period.Type, Model.EventPeriodTypesForDropdown, new { @id = "cbFilterPeriodType", @class = "FilterPeriodType sax-select" })</div>
|
||||
<div class="col-sm-3"><div class="sax-label text-left text-sm-right">@Localiser["label.search"]</div></div>
|
||||
<div class="col-sm-3"><input type="search" id="ifEventFilter" name="Filter.Event" class="EventFilter sax-input" maxlength="64" autocomplete="off" /></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@* Filter item templates *@
|
||||
<div class="sax-panel-item-template">
|
||||
@* Burger dropdown item template - ul is ignored *@
|
||||
<ul class="sax-dropdown-menu Events">
|
||||
<li class="sax-dropdown-item sax-action"><div class="sax-label">...</div></li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
}
|
||||
|
||||
@* Results Panel *@
|
||||
<div class="sax-panel-results">
|
||||
<div class="sax-panel-messages"></div>
|
||||
<div class="sax-panel-item-table">
|
||||
<div class="sax-panel-info" style="min-height:120px;max-height:100%;overflow-y:auto;">
|
||||
<table class="sax-item-list">
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="center">@Localiser["label.date"]</th>
|
||||
<th class="center">@Localiser["label.time"]</th>
|
||||
<th class="">@Localiser["label.summary"]</th>
|
||||
<th class="center">@Localiser["label.published"]</th>
|
||||
<th class="center">@Localiser["label.actions"]</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody></tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@* Element templates *@
|
||||
<div class="sax-panel-item-template">
|
||||
|
||||
@* Item template *@
|
||||
<table>
|
||||
<tr class="sax-row-item Event">
|
||||
<td><div class="EventAtDate center"></div></td>
|
||||
<td><div class="EventAtTime center"></div></td>
|
||||
<td><div class="EventSummary pointer"></div></td>
|
||||
<td><div class="EventPublishedOn center"></div></td>
|
||||
<td>
|
||||
<div class="EventActions center">
|
||||
@* Burger menu *@
|
||||
<ul class="nav navbar-nav navbar-light navbar-right sax-burger">
|
||||
<li class="dropdown-toggle caret-off">
|
||||
<a href="#" class="dropdown" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false"><span class="navbar-toggler-icon"></span></a>
|
||||
<ul class="dropdown-menu dropdown-menu-right sax-dropdown-menu">@* Menu items will be inserted here. *@</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
@* Burger dropdown item template - ul is ignored *@
|
||||
<ul class="sax-dropdown-menu Event">
|
||||
<li class="sax-dropdown-item sax-action"><div class="sax-label">...</div></li>
|
||||
</ul>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<partial name="~/Views/Common/OrganisationSelect.cshtml" />
|
||||
<partial name="Panel-EventDialog.cshtml" />
|
||||
|
||||
@@ -0,0 +1,117 @@
|
||||
@model Model_Organisation_Members
|
||||
@inject SaxLocaliser Localiser
|
||||
@{
|
||||
ViewData["Title"] = "Organisation - Members";
|
||||
}
|
||||
|
||||
<div class="sax-panel Members">
|
||||
|
||||
<script type="text/javascript">
|
||||
sax.lbl.edit = '@(Localiser.GetJavascriptText("label.edit"))';
|
||||
sax.lbl.remove = '@(Localiser.GetJavascriptText("label.remove"))';
|
||||
sax.lbl.activate = '@(Localiser.GetJavascriptText("label.activate"))';
|
||||
sax.msg.activate = '@(Localiser.GetJavascriptText("account.activate.info"))';
|
||||
sax.dlg.title.remove = '@(Localiser.GetJavascriptText("organisation.member.remove"))';
|
||||
sax.dlg.title.selectRoles = '@(Localiser.GetJavascriptText("organisation.member.select.roles"))';
|
||||
sax.msg.remove= '@(Localiser.GetJavascriptText("organisation.member.remove.confirm"))';
|
||||
sax.dlg.title.activate = '@(Localiser.GetJavascriptText("account.activate.caption"))';
|
||||
</script>
|
||||
|
||||
@* Filter Form *@
|
||||
@using (@Html.BeginForm(FormMethod.Post, new { @id = "frmMemberFilter", @class = "sax-form", @action = "#", @method = "POST", onsubmit = "return false;" }))
|
||||
{
|
||||
|
||||
@* Filter panel *@
|
||||
<div class="sax-panel-filter">
|
||||
@* Filter header *@
|
||||
<div class="sax-header row">
|
||||
@* Filter caption *@
|
||||
<div class="col"><div class="sax-caption">@Localiser["organisation.members"]</div></div>
|
||||
<div class="fixed row">
|
||||
@* Burger menu *@
|
||||
<ul class="nav navbar-nav navbar-dark navbar-right sax-burger">
|
||||
<li class="dropdown-toggle caret-off">
|
||||
<a href="#" class="dropdown" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false"><span class="navbar-toggler-icon"></span></a>
|
||||
<ul class="dropdown-menu dropdown-menu-right sax-dropdown-menu">@* Menu items will be inserted here. *@</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<div class="sax-content">
|
||||
<div class="sax-control row">
|
||||
<div class="col-sm-4"><div class="sax-label text-left text-sm-right">@Localiser["label.organisation"]</div></div>
|
||||
<div class="col-sm-8 row">
|
||||
@Html.HiddenFor(model => model.Filter.OrganisationId, new { @id = "ifFilterOrganisationId", @class = "FilterOrganisationId" })
|
||||
<div class="col"><input type="text" id="ifFilterOrganisation" class="FilterOrganisation sax-input" value="@(Model.Filter.OrganisationCaption)" /></div>
|
||||
<div class="fixed"><button class="sax-button SelectFilterOrganisation">@Localiser["label.select"]</button></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="sax-control row">
|
||||
<div class="col-sm-4"><div class="sax-label text-left text-sm-right">@Localiser["label.search"]</div></div>
|
||||
<div class="col-sm-8"><input type="search" id="ifMemberFilter" name="Filter.Member" class="MemberFilter sax-input" maxlength="64" autocomplete="off" /></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@* Filter item templates *@
|
||||
<div class="sax-panel-item-template">
|
||||
@* Burger dropdown item template - ul is ignored *@
|
||||
<ul class="sax-dropdown-menu Members">
|
||||
<li class="sax-dropdown-item sax-action"><div class="sax-label">...</div></li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
}
|
||||
|
||||
@* Results Panel *@
|
||||
<div class="sax-panel-results">
|
||||
<div class="sax-panel-messages"></div>
|
||||
<div class="sax-panel-item-list"></div>
|
||||
|
||||
@* Element templates *@
|
||||
<div class="sax-panel-item-template">
|
||||
|
||||
@* Item template *@
|
||||
<div class="sax-panel-item Member">
|
||||
<div class="sax-header row">
|
||||
<div class="col">
|
||||
@* Member caption *@
|
||||
<div class="sax-caption"><div class="sax-action"><span class="MemberDisplayName"></span></div></div>
|
||||
</div>
|
||||
<div class="fixed sax-actions">
|
||||
@* Burger menu *@
|
||||
<ul class="nav navbar-nav navbar-light navbar-right sax-burger">
|
||||
<li class="dropdown-toggle caret-off">
|
||||
<a href="#" class="dropdown" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false"><span class="navbar-toggler-icon"></span></a>
|
||||
<ul class="dropdown-menu dropdown-menu-right sax-dropdown-menu">@* Menu items will be inserted here. *@</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<div class="sax-content">
|
||||
<div class="row">
|
||||
<div class="col-sm-6"><div class="MemberEmail"></div></div>
|
||||
<div class="col-sm-6 text-sm-right"><div class="MemberRoles"></div></div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-sm-8"><div class="MemberAdminComment sax-note"></div></div>
|
||||
<div class="col-sm-4 text-sm-right"><div class="MemberStatus sax-note"></div></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@* Burger dropdown item template - ul is ignored *@
|
||||
<ul class="sax-dropdown-menu Member">
|
||||
<li class="sax-dropdown-item sax-action"><div class="sax-label">...</div></li>
|
||||
</ul>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<partial name="Panel-MemberDialog.cshtml" />
|
||||
<partial name="~/Views/Common/OrganisationSelect.cshtml" />
|
||||
<partial name="~/Views/Common/CodeSelect.cshtml" />
|
||||
|
||||
@@ -0,0 +1,109 @@
|
||||
@model Model_Organisation_Opportunities
|
||||
@inject SaxLocaliser Localiser
|
||||
@{
|
||||
ViewData["Title"] = "Organisation - Opportunities";
|
||||
}
|
||||
|
||||
<div class="sax-panel Opportunities">
|
||||
|
||||
<script type="text/javascript">
|
||||
sax.lbl.edit = '@(Localiser.GetJavascriptText("label.edit"))';
|
||||
</script>
|
||||
|
||||
@* Filter Form *@
|
||||
@using (@Html.BeginForm(FormMethod.Post, new { @id = "frmOpportunityFilter", @class = "sax-form", @action = "#", @method = "POST", onsubmit = "return false;" }))
|
||||
{
|
||||
|
||||
@* Filter Panel *@
|
||||
<div class="sax-panel-filter">
|
||||
@* Filter header *@
|
||||
<div class="sax-header row">
|
||||
<div class="col"><div class="sax-caption">@Localiser["organisation.caption.opportunities"]</div></div>
|
||||
<div class="fixed row">
|
||||
@* Burger menu *@
|
||||
<ul class="nav navbar-nav navbar-dark navbar-right sax-burger">
|
||||
<li class="dropdown-toggle caret-off">
|
||||
<a href="#" class="dropdown" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false"><span class="navbar-toggler-icon"></span></a>
|
||||
<ul class="dropdown-menu dropdown-menu-right sax-dropdown-menu">@* Menu items will be inserted here. *@</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<div class="sax-content">
|
||||
<div class="sax-control row">
|
||||
<div class="col-sm-4"><div class="sax-label text-left text-sm-right">@Localiser["label.organisation"]</div></div>
|
||||
<div class="col-sm-8 row">
|
||||
@Html.HiddenFor(model => model.Filter.OrganisationId, new { @id = "ifFilterOrganisationId", @class = "FilterOrganisationId" })
|
||||
<div class="col"><input type="text" id="ifFilterOrganisation" class="FilterOrganisation sax-input" readonly="readonly" value="@(Model.Filter.OrganisationCaption)" /></div>
|
||||
<div class="fixed"><button class="sax-button SelectFilterOrganisation">@Localiser["label.select"]</button></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="sax-control row">
|
||||
<div class="col-sm-4"><div class="sax-label text-left text-sm-right">@Localiser["label.search"]</div></div>
|
||||
<div class="col-sm-8"><input type="search" id="ifOpportunityFilter" name="Filter.Opportunity" class="OpportunityFilter sax-input" maxlength="64" autocomplete="off" /></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@* Filter item templates *@
|
||||
<div class="sax-panel-item-template">
|
||||
@* Burger dropdown item template - ul is ignored *@
|
||||
<ul class="sax-dropdown-menu Opportunities">
|
||||
<li class="sax-dropdown-item sax-action"><div class="sax-label">...</div></li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
}
|
||||
|
||||
@* Results Panel *@
|
||||
<div class="sax-panel-results">
|
||||
<div class="sax-panel-messages"></div>
|
||||
<div class="sax-panel-item-list"></div>
|
||||
|
||||
@* Element templates *@
|
||||
<div class="sax-panel-item-template">
|
||||
|
||||
@* Item template *@
|
||||
<div class="sax-panel-item Opportunity">
|
||||
<div class="sax-header row">
|
||||
<div class="col">
|
||||
<div class="sax-caption"><div class="sax-action"><span class="OpportunityType"></span> - <span class="OpportunityPosition"></span></div></div>
|
||||
</div>
|
||||
<div class="fixed sax-actions">
|
||||
@* Burger menu *@
|
||||
<ul class="nav navbar-nav navbar-light navbar-right sax-burger">
|
||||
<li class="dropdown-toggle caret-off">
|
||||
<a href="#" class="dropdown" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false"><span class="navbar-toggler-icon"></span></a>
|
||||
<ul class="dropdown-menu dropdown-menu-right sax-dropdown-menu">@* Menu items will be inserted here. *@</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<div class="sax-content">
|
||||
<div class="row">
|
||||
<div class="col-sm-12"><div class="OpportunityOutline"></div></div>
|
||||
<div class="col-sm-6"><div class="OpportunityRegionCaption sax-note"></div></div>
|
||||
<div class="col-sm-6 right"><div class="OpportunitySportCaption sax-note"></div></div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-sm-4"><div class="sax-note">@Localiser["label.created"]: <span class="OpportunityCreatedOn"></span></div></div>
|
||||
<div class="col-sm-4"><div class="OpportunityPublished sax-note">@Localiser["label.published"]: <span class="OpportunityPublishedOn"></span></div></div>
|
||||
<div class="col-sm-4 right"><div class="OpportunityStatusDesc sax-note"></div></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@* Burger dropdown item template - ul is ignored *@
|
||||
<ul class="sax-dropdown-menu Opportunity">
|
||||
<li class="sax-dropdown-item sax-action"><div class="sax-label">...</div></li>
|
||||
</ul>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<partial name="~/Views/Common/OrganisationSelect.cshtml" />
|
||||
<partial name="Panel-OpportunityDialog.cshtml" />
|
||||
|
||||
@@ -0,0 +1,198 @@
|
||||
@model Model_Organisation_Events
|
||||
@inject SaxLocaliser Localiser
|
||||
@{
|
||||
/* Organisation Events - Event dialog panel */
|
||||
//Model.AdditionalFiles_CSS.Add("lib/jquery-timepicker/jquery.timepicker.min.css");
|
||||
//Model.AdditionalFiles_JS.Add("lib/jquery-timepicker/jquery.timepicker.min.js");
|
||||
//Model.AdditionalFiles_CSS.Add("lib/bootstrap4-datetimepicker/bootstrap-datetimepicker.min.css");
|
||||
//Model.AdditionalFiles_JS.Add("lib/moment.js/moment.min.js");
|
||||
//Model.AdditionalFiles_JS.Add("lib/bootstrap4-datetimepicker/bootstrap-datetimepicker.min.js");
|
||||
}
|
||||
|
||||
<script type="text/javascript">
|
||||
sax.dlg.title.createEvent = '@Localiser.GetJavascriptText("organisation.caption.event.create")';
|
||||
sax.dlg.title.updateEvent = '@Localiser.GetJavascriptText("organisation.caption.event.update")';
|
||||
sax.dlg.title.selectRegion = '@Localiser.GetJavascriptText("reference.caption.region.select")';
|
||||
sax.dlg.title.selectSport = '@Localiser.GetJavascriptText("reference.caption.sport.select")';
|
||||
</script>
|
||||
@using (@Html.BeginForm(FormMethod.Post, new { @id = "frmEventId", @class = "sax-form" }))
|
||||
{
|
||||
@Html.HiddenFor(model => model.EventId, new { @class = "EventId" })
|
||||
}
|
||||
<div id="dlgEvent" class="sax-dialog" title="">
|
||||
|
||||
<div class="spacer2"></div>
|
||||
@using (@Html.BeginForm(FormMethod.Post, new { @id = "frmEvent", @class = "sax-form", @onSubmit = "return false;" }))
|
||||
{
|
||||
|
||||
@Html.HiddenFor(model => model.EventId, new { @id = "ifEventId", @class = "EventId" })
|
||||
@Html.HiddenFor(model => model.EventExists, new { @id = "ifEventExists", @class = "EventExists" })
|
||||
<input type="hidden" id="ifEventOrganisationId" class="EventOrganisationId" name="EventOrganisationId" value="@(Model.Filter.OrganisationId)" />
|
||||
|
||||
@* Event type *@
|
||||
<div class="sax-form-control EventTypeCode">
|
||||
<div class="row">
|
||||
<div class="col-sm-3">
|
||||
<div class="sax-label">
|
||||
<label for="cbEventType"><span>@Localiser["label.type"]</span><span class="required"> *</span></label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-sm">
|
||||
<div class="sax-control">
|
||||
<select id="cbEventType" class="EventType sax-select" name="EventTypeCode"></select>
|
||||
</div>
|
||||
<div class="sax-message"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@* Event At date and time *@
|
||||
<div class="sax-form-control EventAtDate">
|
||||
<div class="row">
|
||||
<div class="col-sm-3">
|
||||
<div class="sax-label">
|
||||
<label for="ifEventAtDate"><span>@Localiser["label.occurs"]</span><span class="required"> *</span></label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-sm">
|
||||
<div class="row">
|
||||
<div class="col-sm">
|
||||
<div class="sax-control">
|
||||
<input id="ifEventAtDate" name="EventAtDate" class="EventAtDate sax-input sax-calendar" readonly="readonly" />
|
||||
</div>
|
||||
<div class="sax-message"></div>
|
||||
</div>
|
||||
<div class="col-sm">
|
||||
<div class="row">
|
||||
<div class="col pl-sm-4 pt-2">
|
||||
@Html.CheckBoxFor(model => model.EventAtTimeSet, new { @id = "chkEventAtTimeSet", @class = "sax-checkbox" })
|
||||
|
||||
<span class="sax-label pointer" onclick="$('#chkEventAtTimeSet').click()">@Localiser["label.starts"]</span>
|
||||
</div>
|
||||
<div class="col">
|
||||
<div class="sax-control">
|
||||
<input type="time" id="ifEventAtTime" name="EventAtTime" class="EventAtTime sax-input" />
|
||||
</div>
|
||||
<div class="sax-message"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@* Event To date and time *@
|
||||
<div class="sax-form-control EventToDate">
|
||||
<div class="row">
|
||||
<div class="col-sm-3 row">
|
||||
<div class="col">
|
||||
<div class="sax-label"><span>@Localiser["label.until"]</span></div>
|
||||
</div>
|
||||
<div class="fixed">
|
||||
<div class="pt-2 pr-2">
|
||||
@Html.CheckBoxFor(model => model.EventToDateSet, new { @id = "chkEventToDateSet", @class = "sax-checkbox" })
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-sm">
|
||||
<div class="row">
|
||||
<div class="col-sm">
|
||||
<div class="sax-control">
|
||||
<input id="ifEventToDate" name="EventToDate" class="EventToDate sax-input sax-calendar" readonly="readonly" />
|
||||
</div>
|
||||
<div class="sax-message"></div>
|
||||
</div>
|
||||
<div class="col-sm">
|
||||
<div class="row">
|
||||
<div class="col pl-sm-4 pt-2">
|
||||
@Html.CheckBoxFor(model => model.EventToTimeSet, new { @id = "chkEventToTimeSet", @class = "sax-checkbox" })
|
||||
|
||||
<span class="sax-label pointer" onclick="$('#chkEventToTimeSet').click()">@Localiser["label.finishes"]</span>
|
||||
</div>
|
||||
<div class="col">
|
||||
<div class="sax-control">
|
||||
<input type="time" id="ifEventToTime" name="EventToTime" class="EventToTime sax-input" />
|
||||
</div>
|
||||
<div class="sax-message"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@* Event summary *@
|
||||
<div class="sax-form-control EventSummary">
|
||||
<div class="sax-label">
|
||||
<label for="ifEventSummary"><span>@Localiser["label.summary"]</span><span class="required"> *</span></label>
|
||||
</div>
|
||||
<div class="sax-control">
|
||||
@Html.TextAreaFor(model => model.EventSummary, new
|
||||
{
|
||||
@id = "ifEventSummary",
|
||||
@class = "EventSummary sax-textarea",
|
||||
@rows = 3,
|
||||
@maxlength = @Model.GetControlMaxLength(SaxDbDfn_Core.ColumnIdx.OrganisationEvent_Summary)
|
||||
})
|
||||
</div>
|
||||
<div class="sax-message"></div>
|
||||
</div>
|
||||
|
||||
@* Event details *@
|
||||
<div class="sax-form-control EventDetails">
|
||||
<div class="sax-label">
|
||||
<label for="ifEventDetails"><span>@Localiser["label.details"]</span><span class="required"> </span></label>
|
||||
</div>
|
||||
<div class="sax-control">
|
||||
@Html.TextAreaFor(model => model.EventDetails, new { @id = "ifEventDetails", @class = "EventDetails sax-textarea", @rows = 6, @maxlength = @Model.GetControlMaxLength(SaxDbDfn_Core.ColumnIdx.OrganisationEvent_Details) })
|
||||
</div>
|
||||
<div class="sax-message"></div>
|
||||
</div>
|
||||
|
||||
@* Sport *@
|
||||
<div class="sax-form-control EventSportPrimary">
|
||||
<div class="row">
|
||||
<div class="col-sm-3">
|
||||
<div class="sax-label">
|
||||
<label for="ifEventSportPrimaryCaption"><span>@Localiser["label.sport"]</span><span class="required"> *</span></label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-sm">
|
||||
<div class="sax-control row">
|
||||
@Html.HiddenFor(model => model.EventSportIdPrimary, new { @id = "ifEventSportIdPrimary", @class = "EventSportIdPrimary" })
|
||||
<div class="col"><input type="text" id="ifEventSportCaptionPrimary" class="EventSportCaptionPrimary sax-input" readonly="readonly" /></div>
|
||||
<div class="fixed"><button class="SelectEventSportPrimary sax-button" style="min-width:auto;margin-left:4px;padding:4px 6px">@Localiser["label.select"]</button></div>
|
||||
</div>
|
||||
<div class="sax-message"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@* Region *@
|
||||
<div class="sax-form-control EventRegionCountry">
|
||||
<div class="row">
|
||||
<div class="col-sm-3">
|
||||
<div class="sax-label">
|
||||
<label for="ifEventRegionCountryCaption"><span>@Localiser["label.region"]</span><span class="required"> *</span></label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-sm">
|
||||
<div class="sax-control row">
|
||||
@Html.HiddenFor(model => model.EventRegionIdCountry, new { @id = "ifEventRegionIdCountry", @class = "EventRegionIdCountry" })
|
||||
<div class="col"><input type="text" id="ifEventRegionCaptionCountry" class="EventRegionCaptionCountry sax-input" readonly="readonly" /></div>
|
||||
<div class="fixed"><button class="SelectEventRegionCountry sax-button" style="min-width:auto;margin-left:4px;padding:4px 6px">@Localiser["label.select"]</button></div>
|
||||
</div>
|
||||
<div class="sax-message"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
}
|
||||
<div class="spacer2"></div>
|
||||
|
||||
</div>
|
||||
|
||||
<partial name="~/Views/Common/RegionSelect.cshtml" />
|
||||
<partial name="~/Views/Common/SportSelect.cshtml" />
|
||||
@@ -0,0 +1,149 @@
|
||||
@model Model_Organisation_Members
|
||||
@inject SaxLocaliser Localiser
|
||||
@{
|
||||
/* Organisation Members - Member dialog panel */
|
||||
}
|
||||
|
||||
<script type="text/javascript">
|
||||
sax.dlg.title.createMember = '@Localiser.GetJavascriptText("caption.member.create")';
|
||||
sax.dlg.title.updateMember = '@Localiser.GetJavascriptText("caption.member.update")';
|
||||
sax.dlg.title.selectRegion = '@Localiser.GetJavascriptText("reference.caption.region.select")';
|
||||
sax.dlg.title.selectSport = '@Localiser.GetJavascriptText("reference.caption.sport.select")';
|
||||
sax.data.userRoleCodeDelim = '@Model.MemberRoleCodeDelim';
|
||||
</script>
|
||||
@using (@Html.BeginForm(FormMethod.Post, new { @id = "frmMemberId", @class = "sax-form" }))
|
||||
{
|
||||
<input type="hidden" name="MemberId" class="MemberId" />
|
||||
}
|
||||
<div id="dlgMember" class="sax-dialog" title="">
|
||||
<div class="spacer2"></div>
|
||||
|
||||
@using (@Html.BeginForm(FormMethod.Post, new { @id = "frmMember", @class = "sax-form", @onSubmit = "return false;" }))
|
||||
{
|
||||
<input type="hidden" name="MemberId" class="MemberId" />
|
||||
<input type="hidden" name="MemberExists" class="MemberExists" />
|
||||
<input type="hidden" name="MemberNameSupplied" class="MemberNameSupplied" />
|
||||
<input type="hidden" class="MemberOrganisationId" name="MemberOrganisationId" value="@(Model.Filter.OrganisationId)" />
|
||||
|
||||
@* Member Email Address *@
|
||||
<div class="sax-form-control MemberEmailAddress">
|
||||
<div class="row">
|
||||
<div class="col-sm-3">
|
||||
<div class="sax-label">
|
||||
<label for="ifMemberEmailAddress"><span>@Localiser["label.email"]</span><span class="required"> *</span></label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-sm">
|
||||
<div class="sax-control">
|
||||
<input type="text" name="MemberEmailAddress" class="MemberEmailAddress sax-input" autocomplete="off" readonly="readonly" maxlength="@(Model.GetControlMaxLength(SaxDbDfn_Core.ColumnIdx.UserAccount_EmailAddress))" />
|
||||
</div>
|
||||
<div class="sax-message"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@* Member Display Name *@
|
||||
<div class="sax-form-control MemberDisplayName">
|
||||
<div class="row">
|
||||
<div class="col-sm-3">
|
||||
<div class="sax-label">
|
||||
<label for="ifMemberDisplayName"><span>@Localiser["label.name"]</span></label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-sm">
|
||||
<div class="sax-control">
|
||||
<input type="text" if="ifMemberDisplayName" class="MemberDisplayName sax-input" readonly="readonly" />
|
||||
</div>
|
||||
<div class="sax-message"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@* Member Name *@
|
||||
<div class="row">
|
||||
<div class="col-sm-3"></div>
|
||||
<div class="col-sm">
|
||||
<div class="row">
|
||||
|
||||
<div class="col-sm-4">
|
||||
@* User Title *@
|
||||
<div class="sax-form-control MemberTitle pr-sm-1">
|
||||
<div class="sax-label">
|
||||
<label for="cbMemberTitle"><span>@Localiser["label.title"]</span></label>
|
||||
</div>
|
||||
<div class="sax-control">
|
||||
<select id="cbMemberTitle" name="MemberTitle" class="MemberTitle sax-input"></select>
|
||||
</div>
|
||||
<div class="sax-message"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-sm-4">
|
||||
@* User First Name *@
|
||||
<div class="sax-form-control MemberFirstName pr-sm-1">
|
||||
<div class="sax-label">
|
||||
<label for="ifMemberFirstName"><span>@Localiser["label.first.name"]</span><span class="required"> *</span></label>
|
||||
</div>
|
||||
<div class="sax-control">
|
||||
<input type="text" id="ifMemberFirstName" name="MemberFirstName" class="MemberFirstName sax-input" autocomplete="off" maxlength="@(Model.GetControlMaxLength(SaxDbDfn_Core.ColumnIdx.UserAccount_FirstName))" />
|
||||
</div>
|
||||
<div class="sax-message"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-sm-4">
|
||||
@* User Last Name *@
|
||||
<div class="sax-form-control MemberLastName">
|
||||
<div class="sax-label">
|
||||
<label for="ifMemberLastName"><span>@Localiser["label.last.name"]</span><span class="required"> *</span></label>
|
||||
</div>
|
||||
<div class="sax-control">
|
||||
<input type="text" id="ifMemberLastName" name="MemberLastName" class="MemberLastName sax-input" autocomplete="off" maxlength="@(Model.GetControlMaxLength(SaxDbDfn_Core.ColumnIdx.UserAccount_LastName))" />
|
||||
</div>
|
||||
<div class="sax-message"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@* Member roles *@
|
||||
<div class="sax-form-control MemberRoleCodes">
|
||||
<div class="row">
|
||||
<div class="col-sm-3">
|
||||
<div class="sax-label">
|
||||
<label for="ifMemberRoles"><span>@Localiser["label.roles"]</span></label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-sm">
|
||||
<div class="sax-control row">
|
||||
<input type="hidden" name="MemberRoleCodes" class="MemberRoleCodes sax-input" />
|
||||
<div class="col"><textarea class="MemberRoles sax-input" rows="4" readonly="readonly"></textarea></div>
|
||||
<div class="fixed"><button class="sax-button SelectMemberRoles" style="min-width:auto;margin-left:4px;padding:4px 6px">@Localiser["label.select"]</button></div>
|
||||
</div>
|
||||
<div class="sax-message"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@* Admin Comment *@
|
||||
<div class="sax-form-control MemberAdminComment">
|
||||
<div class="row">
|
||||
<div class="col-sm-3">
|
||||
<div class="sax-label">
|
||||
<label for="ifMemberAdminComment"><span>@Localiser["label.comment"]</span></label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-sm">
|
||||
<div class="sax-control">
|
||||
<textarea type="text" id="ifMemberAdminComment" name="MemberAdminComment" class="MemberAdminComment sax-textarea" rows="6" autocomplete="off" maxlength="@(Model.GetControlMaxLength(SaxDbDfn_Core.ColumnIdx.UserOrganisation_AdminComment))"></textarea>
|
||||
</div>
|
||||
<div class="sax-message"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
}
|
||||
|
||||
</div>
|
||||
@@ -0,0 +1,116 @@
|
||||
@model Model_Organisation_Opportunities
|
||||
@inject SaxLocaliser Localiser
|
||||
@{
|
||||
/* Organisation Opportunities - Opportunity dialog panel */
|
||||
}
|
||||
|
||||
<script type="text/javascript">
|
||||
sax.dlg.title.createOpportunity = '@Localiser.GetJavascriptText("organisation.caption.opportunity.create")';
|
||||
sax.dlg.title.updateOpportunity = '@Localiser.GetJavascriptText("organisation.caption.opportunity.update")';
|
||||
sax.dlg.title.selectRegion = '@Localiser.GetJavascriptText("reference.caption.region.select")';
|
||||
sax.dlg.title.selectSport = '@Localiser.GetJavascriptText("reference.caption.sport.select")';
|
||||
</script>
|
||||
@using (@Html.BeginForm(FormMethod.Post, new { @id = "frmOpportunityId", @class = "sax-form" }))
|
||||
{
|
||||
@Html.HiddenFor(model => model.OpportunityId, new { @class = "OpportunityId" })
|
||||
}
|
||||
<div id="dlgOpportunity" class="sax-dialog" title="">
|
||||
|
||||
<div class="spacer2"></div>
|
||||
@using (@Html.BeginForm(FormMethod.Post, new { @id = "frmOpportunity", @class = "sax-form", @onSubmit = "return false;" }))
|
||||
{
|
||||
|
||||
@Html.HiddenFor(model => model.OpportunityId, new { @id = "ifOpportunityId", @class = "OpportunityId" })
|
||||
@Html.HiddenFor(model => model.OpportunityExists, new { @id = "ifOpportunityExists", @class = "OpportunityExists" })
|
||||
<input type="hidden" id="ifOpportunityOrganisationId" class="OpportunityOrganisationId" name="OpportunityOrganisationId" value="@(Model.Filter.OrganisationId)" />
|
||||
|
||||
@* Opportunity type *@
|
||||
<div class="sax-form-control OpportunityTypeCode">
|
||||
<div class="row">
|
||||
<div class="col-sm-3">
|
||||
<div class="sax-label">
|
||||
<label for="cbOpportunityType"><span>@Localiser["label.type"]</span><span class="required"> *</span></label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-sm">
|
||||
<div class="sax-control">
|
||||
<select id="cbOpportunityType" class="OpportunityType sax-select" name="OpportunityTypeCode"></select>
|
||||
</div>
|
||||
<div class="sax-message"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@* Opportunity position *@
|
||||
<div class="sax-form-control OpportunityPosition">
|
||||
<div class="row">
|
||||
<div class="col-sm-3">
|
||||
<div class="sax-label">
|
||||
<label for="ifOpportunityPosition"><span>@Localiser["label.position"]</span><span class="required"> *</span></label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-sm">
|
||||
<div class="sax-control">
|
||||
@Html.TextBoxFor(model => model.OpportunityPosition, new { @id = "ifOpportunityPosition", @class = "OpportunityPosition sax-input", @maxlength = @Model.GetControlMaxLength(SaxDbDfn_Core.ColumnIdx.OrganisationOpportunity_Position) })
|
||||
</div>
|
||||
<div class="sax-message"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@* Opportunity outline *@
|
||||
<div class="sax-form-control OpportunityOutline">
|
||||
<div class="sax-label">
|
||||
<label for="ifOpportunityOutline"><span>@Localiser["label.outline"]</span><span class="required"> *</span></label>
|
||||
</div>
|
||||
<div class="sax-control">
|
||||
@Html.TextAreaFor(model => model.OpportunityOutline, new { @id = "ifOpportunityOutline", @class = "OpportunityOutline sax-textarea", @rows = 4, @maxlength = @Model.GetControlMaxLength(SaxDbDfn_Core.ColumnIdx.OrganisationOpportunity_Outline) })
|
||||
</div>
|
||||
<div class="sax-message"></div>
|
||||
</div>
|
||||
|
||||
@* Sport *@
|
||||
<div class="sax-form-control OpportunitySportId">
|
||||
<div class="row">
|
||||
<div class="col-sm-3">
|
||||
<div class="sax-label">
|
||||
<label for="ifOpportunitySportCaption"><span>@Localiser["label.sport"]</span><span class="required"> *</span></label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-sm">
|
||||
<div class="sax-control row">
|
||||
@Html.HiddenFor(model => model.OpportunitySportId, new { @id = "ifOpportunitySportId", @class = "OpportunitySportId" })
|
||||
<div class="col"><input type="text" id="ifOpportunitySportCaption" class="OpportunitySportCaption sax-input" readonly="readonly" /></div>
|
||||
<div class="fixed"><button class="SelectOpportunitySport sax-button" style="min-width:auto;margin-left:4px;padding:4px 6px">@Localiser["label.select"]</button></div>
|
||||
</div>
|
||||
<div class="sax-message"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@* Region *@
|
||||
<div class="sax-form-control OpportunityRegionId">
|
||||
<div class="row">
|
||||
<div class="col-sm-3">
|
||||
<div class="sax-label">
|
||||
<label for="ifOpportunityRegionCaption"><span>@Localiser["label.region"]</span><span class="required"> *</span></label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-sm">
|
||||
<div class="sax-control row">
|
||||
@Html.HiddenFor(model => model.OpportunityRegionId, new { @id = "ifOpportunityRegionId", @class = "OpportunityRegionId" })
|
||||
<div class="col"><input type="text" id="ifOpportunityRegionCaption" class="OpportunityRegionCaption sax-input" readonly="readonly" /></div>
|
||||
<div class="fixed"><button class="SelectOpportunityRegion sax-button" style="min-width:auto;margin-left:4px;padding:4px 6px">@Localiser["label.select"]</button></div>
|
||||
</div>
|
||||
<div class="sax-message"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
}
|
||||
<div class="spacer2"></div>
|
||||
|
||||
</div>
|
||||
|
||||
<partial name="~/Views/Common/RegionSelect.cshtml" />
|
||||
<partial name="~/Views/Common/SportSelect.cshtml" />
|
||||
@@ -0,0 +1,9 @@
|
||||
@model Model_Policies
|
||||
@inject SaxLocaliser Localiser
|
||||
@{
|
||||
ViewData["Title"] = "Privacy Policy";
|
||||
}
|
||||
|
||||
<h1>@Localiser["policies.caption.privacy.policy"]</h1>
|
||||
|
||||
<p>Use this page to detail your site's privacy policy.</p>
|
||||
@@ -0,0 +1,169 @@
|
||||
@model Model_Search_Organisations
|
||||
@inject SaxLocaliser Localiser
|
||||
@{
|
||||
ViewData["Title"] = "Search Organisations";
|
||||
}
|
||||
|
||||
<div class="sax-panel Organisations sax-alpha">
|
||||
|
||||
<script type="text/javascript">
|
||||
sax.lbl.view = '@(Localiser.GetJavascriptText("label.view"))';
|
||||
sax.lbl.follow = '@(Localiser.GetJavascriptText("label.follow"))';
|
||||
sax.dlg.title.organisation = '@(Localiser.GetJavascriptText("label.organisation"))';
|
||||
</script>
|
||||
|
||||
<div class="row">
|
||||
|
||||
<div class="col-sm-5">
|
||||
|
||||
@* Filter Form *@
|
||||
@using (@Html.BeginForm(FormMethod.Post, new { @id = "frmOrganisationFilter", @class = "sax-form", @action = "#", @method = "POST", onsubmit = "return false;" }))
|
||||
{
|
||||
|
||||
@* Filter panel *@
|
||||
<div class="sax-panel-filter mr-sm-2">
|
||||
@* Filter header *@
|
||||
<div class="sax-header row">
|
||||
@* Filter caption *@
|
||||
<div class="col"><div class="sax-caption">@Localiser["organisation.caption.organisations"]</div></div>
|
||||
<div class="fixed row">
|
||||
<div class="col">
|
||||
<partial name="~/Views/Common/ResultsPaging.cshtml" />
|
||||
</div>
|
||||
<div class="fixed">
|
||||
@* Burger menu *@
|
||||
<ul class="nav navbar-nav navbar-dark navbar-right sax-burger">
|
||||
<li class="dropdown-toggle caret-off">
|
||||
<a href="#" class="dropdown" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false"><span class="navbar-toggler-icon"></span></a>
|
||||
<ul class="dropdown-menu dropdown-menu-right sax-dropdown-menu">@* Menu items will be inserted here. *@</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="sax-content">
|
||||
|
||||
@* Generic Organisation filter - name etc. *@
|
||||
<div class="sax-control row">
|
||||
<div class="col-sm-4"><div class="sax-label text-left text-sm-right">@Localiser["label.search"]</div></div>
|
||||
<div class="col-sm row">
|
||||
<div class="col"><input type="search" name="Filter.Organisation" class="sax-input FilterOrganisation" maxlength="32" autocomplete="off" /></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@* Organisation type *@
|
||||
<div class="sax-control row">
|
||||
<div class="col-sm-4"><div class="sax-label text-left text-sm-right">@Localiser["label.category"]</div></div>
|
||||
<div class="col-sm">
|
||||
@Html.DropDownListFor(model => model.Filter.Category, Model.OrganisationCategoriesForSelect, Localiser["label.any"], new { @id = "", @class = "FilterCategory sax-select" })
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@* Organisation sport *@
|
||||
<div class="row pb4">
|
||||
<div class="col-sm-4 sax-label text-left text-sm-right">@Localiser["label.sport"]</div>
|
||||
<div class="col-sm">
|
||||
<div class="row">
|
||||
@Html.HiddenFor(model => model.Filter.SportId, new { @id = "", @class = "FilterSportId" })
|
||||
<div class="col"><input type="text" class="FilterSportCaption sax-input" readonly="readonly" ondblclick="sax.searchOrganisations.selectFilterSport()" /> </div>
|
||||
<div class="fixed row">
|
||||
<div class="sax-action" onclick="sax.searchOrganisations.selectFilterSport();"><img src="~/img/action/search24.png" alt="@(Localiser["label.search"])" title="@(Localiser["label.search"])" /></div>
|
||||
<div class="sax-action" onclick="sax.searchOrganisations.clearFilterSport();"><img src="~/img/action/delete24.png" alt="@(Localiser["label.clear"])" title="@(Localiser["label.clear"])" /></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@* Organisation region *@
|
||||
<div class="row pb4">
|
||||
<div class="col-sm-4 sax-label text-left text-sm-right">@Localiser["label.region"]</div>
|
||||
<div class="col-sm">
|
||||
<div class="row">
|
||||
@Html.HiddenFor(model => model.Filter.RegionId, new { @id = "", @class = "FilterRegionId" })
|
||||
<div class="col"><input type="text" class="FilterRegionCaption sax-input" readonly="readonly" ondblclick="sax.searchOrganisations.selectFilterRegion()" /> </div>
|
||||
<div class="fixed row">
|
||||
<div class="sax-action" onclick="sax.searchOrganisations.selectFilterRegion();"><img src="~/img/action/search24.png" alt="@(Localiser["label.search"])" title="@(Localiser["label.search"])" /></div>
|
||||
<div class="sax-action" onclick="sax.searchOrganisations.clearFilterRegion();"><img src="~/img/action/delete24.png" alt="@(Localiser["label.clear"])" title="@(Localiser["label.clear"])" /></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
@* Filter item templates *@
|
||||
<div class="sax-panel-item-template">
|
||||
@* Burger dropdown item template - ul is ignored *@
|
||||
<ul class="sax-dropdown-menu Organisations">
|
||||
<li class="sax-dropdown-item sax-action"><div class="sax-label">...</div></li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
}
|
||||
|
||||
</div>
|
||||
|
||||
<div class="col">
|
||||
|
||||
@* Results Panel *@
|
||||
<div class="sax-panel-results">
|
||||
<div class="sax-panel-messages"></div>
|
||||
<div class="sax-panel-item-list"></div>
|
||||
|
||||
@* Element templates *@
|
||||
<div class="sax-panel-item-template">
|
||||
|
||||
@* Item template *@
|
||||
<div class="sax-panel-item Organisation">
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<div class="sax-header row">
|
||||
<div class="col">
|
||||
@* Organisation caption *@
|
||||
<div class="sax-caption"><div class="sax-action"><span class="OrganisationName"></span></div></div>
|
||||
</div>
|
||||
<div class="fixed">
|
||||
<div class="OrganisationCategory"></div>
|
||||
</div>
|
||||
<div class="fixed sax-actions">
|
||||
@* Burger menu *@
|
||||
<ul class="nav navbar-nav navbar-light navbar-right sax-burger">
|
||||
<li class="dropdown-toggle caret-off">
|
||||
<a href="#" class="dropdown" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false"><span class="navbar-toggler-icon"></span></a>
|
||||
<ul class="dropdown-menu dropdown-menu-right sax-dropdown-menu">@* Menu items will be inserted here. *@</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<div class="sax-content">
|
||||
<div class="col">
|
||||
<div class="row">
|
||||
<div class="col-sm-6"><div class="OrganisationSport"></div></div>
|
||||
<div class="col-sm-6 text-sm-right"><div class="OrganisationLocation"></div></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="fixed"><div style="min-width:48px;"><img src="" class="OrganisationLogo" alt="" title=""></div></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@* Burger dropdown item template - ul is ignored *@
|
||||
<ul class="sax-dropdown-menu Organisation">
|
||||
<li class="sax-dropdown-item sax-action"><div class="sax-label">...</div></li>
|
||||
</ul>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<partial name="~/Views/Common/RegionSelect.cshtml" />
|
||||
<partial name="~/Views/Common/SportSelect.cshtml" />
|
||||
<partial name="Panel-OrganisationDialog.cshtml" />
|
||||
@@ -0,0 +1,99 @@
|
||||
@model Model_Search_Organisations
|
||||
@inject SaxLocaliser Localiser
|
||||
@{
|
||||
/* Organisation dialog panel */
|
||||
}
|
||||
|
||||
<style>
|
||||
#dlgOrganisation .OrganisationContact .sax-value img
|
||||
{
|
||||
margin-right: 8px;
|
||||
}
|
||||
|
||||
#dlgOrganisation .OrganisationAssociations .sax-value, #dlgOrganisation .OrganisationAbout .sax-value, #dlgOrganisation .OrganisationFacilities .sax-value
|
||||
{
|
||||
min-height: 40px;
|
||||
max-height: 170px;
|
||||
padding: 4px 4px 2px 4px;
|
||||
border: 1px solid #a0a0a0;
|
||||
border-top-left-radius: 4px;
|
||||
border-bottom-left-radius: 4px;
|
||||
overflow-y: scroll;
|
||||
}
|
||||
|
||||
#dlgOrganisation .OrganisationAssociations .sax-value .sax-assoc-type
|
||||
{
|
||||
padding: 2px 4px 2px 4px;
|
||||
font-weight: bold;
|
||||
background-color: #e0e0e0;
|
||||
}
|
||||
|
||||
#dlgOrganisation .OrganisationAssociations .sax-value .sax-assoc-org
|
||||
{
|
||||
margin: 2px 0 0 12px;
|
||||
padding: 0 0 0 8px;
|
||||
}
|
||||
|
||||
#dlgOrganisation .OrganisationAssociations .sax-value .sax-assoc-org:hover
|
||||
{
|
||||
cursor: pointer;
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
#dlgOrganisation .OrganisationAssociations .sax-value .sax-assoc-org img.icon
|
||||
{
|
||||
height: 24px;
|
||||
margin-right:4px;
|
||||
}
|
||||
</style>
|
||||
<script type="text/javascript">
|
||||
</script>
|
||||
|
||||
@using (@Html.BeginForm(FormMethod.Post, new { @id = "frmOrganisationId", @class = "sax-form" }))
|
||||
{
|
||||
<input type="hidden" name="OrganisationId" class="OrganisationId" />
|
||||
}
|
||||
<div id="dlgOrganisation" class="sax-dialog" title="">
|
||||
|
||||
<div class="spacer"><a href="#"></a>"</div>
|
||||
|
||||
<div class="row OrganisationCategory">
|
||||
<div class="col-sm-3"><div class="sax-label text-sm-right">@Localiser["label.type"]</div></div>
|
||||
<div class="col-sm"><div class="sax-value"></div></div>
|
||||
</div>
|
||||
<div class="row OrganisationSport">
|
||||
<div class="col-sm-3"><div class="sax-label text-sm-right">@Localiser["label.sport"]</div></div>
|
||||
<div class="col-sm"><div class="sax-value"></div></div>
|
||||
</div>
|
||||
<div class="row OrganisationLocation">
|
||||
<div class="col-sm-3"><div class="sax-label text-sm-right">@Localiser["label.location"]</div></div>
|
||||
<div class="col-sm"><div class="sax-value"></div></div>
|
||||
</div>
|
||||
<div class="row OrganisationAbout">
|
||||
<div class="col-sm-3"><div class="sax-label text-sm-right">@Localiser["label.about"]</div></div>
|
||||
<div class="col-sm"><div class="sax-value"></div></div>
|
||||
</div>
|
||||
<div class="row OrganisationFacilities">
|
||||
<div class="col-sm-3"><div class="sax-label text-sm-right">@Localiser["label.facilities"]</div></div>
|
||||
<div class="col-sm"><div class="sax-value"></div></div>
|
||||
</div>
|
||||
<div class="row OrganisationContact">
|
||||
<div class="col-sm-3"><div class="sax-label text-sm-right">@Localiser["label.contact"]</div></div>
|
||||
<div class="col-sm"><div class="sax-value"></div></div>
|
||||
</div>
|
||||
<div class="row OrganisationAddress">
|
||||
<div class="col-sm-3"><div class="sax-label text-sm-right">@Localiser["label.address"]</div></div>
|
||||
<div class="col-sm"><div class="sax-value"></div></div>
|
||||
</div>
|
||||
<div class="row OrganisationPostalCode">
|
||||
<div class="col-sm-3"><div class="sax-label text-sm-right">@Localiser["label.postal.code"]</div></div>
|
||||
<div class="col-sm"><div class="sax-value"></div></div>
|
||||
</div>
|
||||
<div class="row OrganisationAssociations">
|
||||
<div class="col-sm-3"><div class="sax-label text-sm-right">@Localiser["label.associations"]</div></div>
|
||||
<div class="col-sm"><div class="sax-value"></div></div>
|
||||
</div>
|
||||
|
||||
<div class="spacer"></div>
|
||||
|
||||
</div>
|
||||
@@ -0,0 +1,30 @@
|
||||
@model Model_Search_Users
|
||||
@inject SaxLocaliser Localiser
|
||||
@{
|
||||
/* User dialog panel */
|
||||
}
|
||||
|
||||
<script type="text/javascript">
|
||||
</script>
|
||||
|
||||
@using (@Html.BeginForm(FormMethod.Post, new { @id = "frmUserId", @class = "sax-form" }))
|
||||
{
|
||||
<input type="hidden" name="UserId" class="UserId" />
|
||||
}
|
||||
<div id="dlgUser" class="sax-dialog" title="">
|
||||
|
||||
<div class="spacer"></div>
|
||||
|
||||
<div class="row UserName">
|
||||
<div class="col-sm-5"><div class="sax-label text-sm-right">@Localiser["label.name"]</div></div>
|
||||
<div class="col-sm"><div class="sax-value"></div></div>
|
||||
</div>
|
||||
|
||||
<div class="row UserLocation">
|
||||
<div class="col-sm-5"><div class="sax-label text-sm-right">@Localiser["label.location"]</div></div>
|
||||
<div class="col-sm"><div class="sax-value"></div></div>
|
||||
</div>
|
||||
|
||||
<div class="spacer"></div>
|
||||
|
||||
</div>
|
||||
@@ -0,0 +1,154 @@
|
||||
@model Model_Search_Users
|
||||
@inject SaxLocaliser Localiser
|
||||
@{
|
||||
ViewData["Title"] = "Search Users";
|
||||
}
|
||||
|
||||
<div class="sax-panel Users sax-alpha">
|
||||
|
||||
<script type="text/javascript">
|
||||
sax.lbl.view = '@(Localiser.GetJavascriptText("label.view"))';
|
||||
sax.lbl.follow = '@(Localiser.GetJavascriptText("label.follow"))';
|
||||
sax.dlg.title.user = '@(Localiser.GetJavascriptText("label.user"))';
|
||||
</script>
|
||||
|
||||
<div class="row">
|
||||
|
||||
<div class="col-sm-5">
|
||||
|
||||
@* Filter Form *@
|
||||
@using (@Html.BeginForm(FormMethod.Post, new { @id = "frmUserFilter", @class = "sax-form", @action = "#", @method = "POST", onsubmit = "return false;" }))
|
||||
{
|
||||
|
||||
@* Filter panel *@
|
||||
<div class="sax-panel-filter mr-sm-2">
|
||||
@* Filter header *@
|
||||
<div class="sax-header row">
|
||||
@* Filter caption *@
|
||||
<div class="col"><div class="sax-caption">@Localiser["label.users"]</div></div>
|
||||
<div class="fixed row">
|
||||
<div class="col">
|
||||
<partial name="~/Views/Common/ResultsPaging.cshtml" />
|
||||
</div>
|
||||
<div class="fixed">
|
||||
@* Burger menu *@
|
||||
<ul class="nav navbar-nav navbar-dark navbar-right sax-burger">
|
||||
<li class="dropdown-toggle caret-off">
|
||||
<a href="#" class="dropdown" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false"><span class="navbar-toggler-icon"></span></a>
|
||||
<ul class="dropdown-menu dropdown-menu-right sax-dropdown-menu">@* Menu items will be inserted here. *@</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="sax-content">
|
||||
|
||||
@* Generic User filter - name etc. *@
|
||||
<div class="sax-control row">
|
||||
<div class="col-sm-4"><div class="sax-label text-left text-sm-right">@Localiser["label.search"]</div></div>
|
||||
<div class="col-sm row">
|
||||
<div class="col"><input type="search" name="Filter.User" class="sax-input FilterUser" maxlength="32" autocomplete="off" /></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@* User sport *@
|
||||
<div class="row pb4">
|
||||
<div class="col-sm-4 sax-label text-left text-sm-right">@Localiser["label.sport"]</div>
|
||||
<div class="col-sm">
|
||||
<div class="row">
|
||||
@Html.HiddenFor(model => model.Filter.SportId, new { @id = "", @class = "FilterSportId" })
|
||||
<div class="col"><input type="text" class="FilterSportCaption sax-input" readonly="readonly" ondblclick="sax.searchUsers.selectFilterSport()" /> </div>
|
||||
<div class="fixed row">
|
||||
<div class="sax-action" onclick="sax.searchUsers.selectFilterSport();"><img src="~/img/action/search24.png" alt="@(Localiser["label.search"])" title="@(Localiser["label.search"])" /></div>
|
||||
<div class="sax-action" onclick="sax.searchUsers.clearFilterSport();"><img src="~/img/action/delete24.png" alt="@(Localiser["label.clear"])" title="@(Localiser["label.clear"])" /></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@* User region *@
|
||||
<div class="row pb4">
|
||||
<div class="col-sm-4 sax-label text-left text-sm-right">@Localiser["label.region"]</div>
|
||||
<div class="col-sm">
|
||||
<div class="row">
|
||||
@Html.HiddenFor(model => model.Filter.RegionId, new { @id = "", @class = "FilterRegionId" })
|
||||
<div class="col"><input type="text" class="FilterRegionCaption sax-input" readonly="readonly" ondblclick="sax.searchUsers.selectFilterRegion()" /> </div>
|
||||
<div class="fixed row">
|
||||
<div class="sax-action" onclick="sax.searchUsers.selectFilterRegion();"><img src="~/img/action/search24.png" alt="@(Localiser["label.search"])" title="@(Localiser["label.search"])" /></div>
|
||||
<div class="sax-action" onclick="sax.searchUsers.clearFilterRegion();"><img src="~/img/action/delete24.png" alt="@(Localiser["label.clear"])" title="@(Localiser["label.clear"])" /></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
@* Filter item templates *@
|
||||
<div class="sax-panel-item-template">
|
||||
@* Burger dropdown item template - ul is ignored *@
|
||||
<ul class="sax-dropdown-menu Users">
|
||||
<li class="sax-dropdown-item sax-action"><div class="sax-label">...</div></li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
}
|
||||
|
||||
</div>
|
||||
|
||||
<div class="col">
|
||||
|
||||
@* Results Panel *@
|
||||
<div class="sax-panel-results">
|
||||
<div class="sax-panel-messages"></div>
|
||||
<div class="sax-panel-item-list"></div>
|
||||
|
||||
@* Element templates *@
|
||||
<div class="sax-panel-item-template">
|
||||
|
||||
@* Item template *@
|
||||
<div class="sax-panel-item User">
|
||||
<div class="sax-header row">
|
||||
<div class="col">
|
||||
@* User caption *@
|
||||
<div class="sax-caption"><div class="sax-action"><span class="UserName"></span></div></div>
|
||||
</div>
|
||||
<div class="fixed">
|
||||
<div class="UserCategory"></div>
|
||||
</div>
|
||||
<div class="fixed sax-actions">
|
||||
@* Burger menu *@
|
||||
<ul class="nav navbar-nav navbar-light navbar-right sax-burger">
|
||||
<li class="dropdown-toggle caret-off">
|
||||
<a href="#" class="dropdown" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false"><span class="navbar-toggler-icon"></span></a>
|
||||
<ul class="dropdown-menu dropdown-menu-right sax-dropdown-menu">@* Menu items will be inserted here. *@</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<div class="sax-content">
|
||||
<div class="row">
|
||||
<div class="col-sm-6"><div class="UserLocation"></div></div>
|
||||
<div class="col-sm-6 text-sm-right"><div class=""></div></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@* Burger dropdown item template - ul is ignored *@
|
||||
<ul class="sax-dropdown-menu User">
|
||||
<li class="sax-dropdown-item sax-action"><div class="sax-label">...</div></li>
|
||||
</ul>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<partial name="~/Views/Common/RegionSelect.cshtml" />
|
||||
<partial name="~/Views/Common/SportSelect.cshtml" />
|
||||
<partial name="Panel-UserDialog.cshtml" />
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user