Add project files.
8
.vscode/tasks.json
vendored
Normal file
@ -0,0 +1,8 @@
|
||||
|
||||
// Sass configuration
|
||||
{
|
||||
"version": "0.1.0",
|
||||
"command": "node-sass",
|
||||
"isShellCommand": true,
|
||||
"args": ["Amen/Content/Site.scss", "Amen/Content/Site.css"]
|
||||
}
|
25
Amen.sln
Normal file
@ -0,0 +1,25 @@
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio 2013
|
||||
VisualStudioVersion = 12.0.31101.0
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Amen", "Amen\Amen.csproj", "{599AF714-D8F5-408C-B14F-915AC646D9EA}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
Release|Any CPU = Release|Any CPU
|
||||
Stage|Any CPU = Stage|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{599AF714-D8F5-408C-B14F-915AC646D9EA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{599AF714-D8F5-408C-B14F-915AC646D9EA}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{599AF714-D8F5-408C-B14F-915AC646D9EA}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{599AF714-D8F5-408C-B14F-915AC646D9EA}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{599AF714-D8F5-408C-B14F-915AC646D9EA}.Stage|Any CPU.ActiveCfg = Stage|Any CPU
|
||||
{599AF714-D8F5-408C-B14F-915AC646D9EA}.Stage|Any CPU.Build.0 = Stage|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
EndGlobal
|
579
Amen/Amen.csproj
Normal file
@ -0,0 +1,579 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
|
||||
<PropertyGroup>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||
<ProductVersion>
|
||||
</ProductVersion>
|
||||
<SchemaVersion>2.0</SchemaVersion>
|
||||
<ProjectGuid>{599AF714-D8F5-408C-B14F-915AC646D9EA}</ProjectGuid>
|
||||
<ProjectTypeGuids>{349c5851-65df-11da-9384-00065b846f21};{fae04ec0-301f-11d3-bf4b-00c04f79efbc}</ProjectTypeGuids>
|
||||
<OutputType>Library</OutputType>
|
||||
<AppDesignerFolder>Properties</AppDesignerFolder>
|
||||
<RootNamespace>Amen</RootNamespace>
|
||||
<AssemblyName>Amen</AssemblyName>
|
||||
<TargetFrameworkVersion>v4.8</TargetFrameworkVersion>
|
||||
<MvcBuildViews>false</MvcBuildViews>
|
||||
<UseIISExpress>true</UseIISExpress>
|
||||
<IISExpressSSLPort />
|
||||
<IISExpressAnonymousAuthentication />
|
||||
<IISExpressWindowsAuthentication />
|
||||
<IISExpressUseClassicPipelineMode />
|
||||
<UseGlobalApplicationHostFile />
|
||||
<TargetFrameworkProfile />
|
||||
<Use64BitIISExpress />
|
||||
<NuGetPackageImportStamp>
|
||||
</NuGetPackageImportStamp>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<DebugType>full</DebugType>
|
||||
<Optimize>false</Optimize>
|
||||
<OutputPath>bin\</OutputPath>
|
||||
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||
<DebugType>pdbonly</DebugType>
|
||||
<Optimize>true</Optimize>
|
||||
<OutputPath>bin\</OutputPath>
|
||||
<DefineConstants>TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="EPPlus">
|
||||
<HintPath>..\packages\EPPlus.4.1.0\lib\net40\EPPlus.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Facebook">
|
||||
<HintPath>..\packages\Facebook.7.0.6\lib\net45\Facebook.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="ImageResizer">
|
||||
<HintPath>..\packages\ImageResizer.4.1.9\lib\net45\ImageResizer.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Microsoft.Azure.KeyVault.Core">
|
||||
<HintPath>..\packages\Microsoft.Azure.KeyVault.Core.1.0.0\lib\net40\Microsoft.Azure.KeyVault.Core.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Microsoft.Crm.Sdk.Proxy, Version=9.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Microsoft.PowerPlatform.Dataverse.Client.1.0.9\lib\net48\Microsoft.Crm.Sdk.Proxy.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Microsoft.CSharp" />
|
||||
<Reference Include="Microsoft.Data.Edm, Version=5.6.4.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
|
||||
<SpecificVersion>False</SpecificVersion>
|
||||
<HintPath>..\packages\Microsoft.Data.Edm.5.6.4\lib\net40\Microsoft.Data.Edm.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Microsoft.Data.OData, Version=5.6.4.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
|
||||
<SpecificVersion>False</SpecificVersion>
|
||||
<HintPath>..\packages\Microsoft.Data.OData.5.6.4\lib\net40\Microsoft.Data.OData.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Microsoft.Data.Services.Client, Version=5.6.4.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
|
||||
<SpecificVersion>False</SpecificVersion>
|
||||
<HintPath>..\packages\Microsoft.Data.Services.Client.5.6.4\lib\net40\Microsoft.Data.Services.Client.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Microsoft.Extensions.Caching.Abstractions">
|
||||
<HintPath>..\packages\Microsoft.Extensions.Caching.Abstractions.3.1.8\lib\netstandard2.0\Microsoft.Extensions.Caching.Abstractions.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Microsoft.Extensions.Caching.Memory">
|
||||
<HintPath>..\packages\Microsoft.Extensions.Caching.Memory.3.1.8\lib\netstandard2.0\Microsoft.Extensions.Caching.Memory.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Microsoft.Extensions.DependencyInjection, Version=3.1.8.0, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL">
|
||||
<SpecificVersion>False</SpecificVersion>
|
||||
<HintPath>..\packages\Microsoft.Extensions.DependencyInjection.3.1.8\lib\netstandard2.0\Microsoft.Extensions.DependencyInjection.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Microsoft.Extensions.DependencyInjection.Abstractions">
|
||||
<HintPath>..\packages\Microsoft.Extensions.DependencyInjection.Abstractions.3.1.8\lib\netstandard2.0\Microsoft.Extensions.DependencyInjection.Abstractions.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Microsoft.Extensions.Http">
|
||||
<HintPath>..\packages\Microsoft.Extensions.Http.3.1.8\lib\netstandard2.0\Microsoft.Extensions.Http.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Microsoft.Extensions.Logging">
|
||||
<HintPath>..\packages\Microsoft.Extensions.Logging.3.1.8\lib\netstandard2.0\Microsoft.Extensions.Logging.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Microsoft.Extensions.Logging.Abstractions">
|
||||
<HintPath>..\packages\Microsoft.Extensions.Logging.Abstractions.3.1.8\lib\netstandard2.0\Microsoft.Extensions.Logging.Abstractions.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Microsoft.Extensions.Options">
|
||||
<HintPath>..\packages\Microsoft.Extensions.Options.3.1.8\lib\netstandard2.0\Microsoft.Extensions.Options.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Microsoft.Extensions.Primitives">
|
||||
<HintPath>..\packages\Microsoft.Extensions.Primitives.3.1.8\lib\netstandard2.0\Microsoft.Extensions.Primitives.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Microsoft.Identity.Client">
|
||||
<HintPath>..\packages\Microsoft.Identity.Client.4.35.1\lib\netstandard1.3\Microsoft.Identity.Client.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Microsoft.IdentityModel.Clients.ActiveDirectory, Version=5.2.8.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
|
||||
<SpecificVersion>False</SpecificVersion>
|
||||
<HintPath>..\packages\Microsoft.IdentityModel.Clients.ActiveDirectory.3.19.8\lib\net45\Microsoft.IdentityModel.Clients.ActiveDirectory.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Microsoft.IdentityModel.Clients.ActiveDirectory.Platform">
|
||||
<HintPath>..\packages\Microsoft.IdentityModel.Clients.ActiveDirectory.3.19.8\lib\net45\Microsoft.IdentityModel.Clients.ActiveDirectory.Platform.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Microsoft.Owin">
|
||||
<HintPath>..\packages\Microsoft.Owin.3.1.0-rc1\lib\net45\Microsoft.Owin.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Microsoft.Owin.Cors">
|
||||
<HintPath>..\packages\Microsoft.Owin.Cors.3.1.0-rc1\lib\net45\Microsoft.Owin.Cors.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Microsoft.Owin.Host.SystemWeb">
|
||||
<HintPath>..\packages\Microsoft.Owin.Host.SystemWeb.3.1.0-rc1\lib\net45\Microsoft.Owin.Host.SystemWeb.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Microsoft.Owin.Security">
|
||||
<HintPath>..\packages\Microsoft.Owin.Security.3.1.0-rc1\lib\net45\Microsoft.Owin.Security.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Microsoft.Owin.Security.Cookies">
|
||||
<HintPath>..\packages\Microsoft.Owin.Security.Cookies.3.1.0-rc1\lib\net45\Microsoft.Owin.Security.Cookies.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Microsoft.Owin.Security.Facebook">
|
||||
<HintPath>..\packages\Microsoft.Owin.Security.Facebook.3.1.0-rc1\lib\net45\Microsoft.Owin.Security.Facebook.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Microsoft.Owin.Security.Google">
|
||||
<HintPath>..\packages\Microsoft.Owin.Security.Google.3.1.0-rc1\lib\net45\Microsoft.Owin.Security.Google.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Microsoft.Owin.Security.MicrosoftAccount">
|
||||
<HintPath>..\packages\Microsoft.Owin.Security.MicrosoftAccount.3.1.0-rc1\lib\net45\Microsoft.Owin.Security.MicrosoftAccount.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Microsoft.Owin.Security.OAuth">
|
||||
<HintPath>..\packages\Microsoft.Owin.Security.OAuth.3.1.0-rc1\lib\net45\Microsoft.Owin.Security.OAuth.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Microsoft.Owin.Security.Twitter">
|
||||
<HintPath>..\packages\Microsoft.Owin.Security.Twitter.3.1.0-rc1\lib\net45\Microsoft.Owin.Security.Twitter.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Microsoft.PowerPlatform.Dataverse.Client, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Microsoft.PowerPlatform.Dataverse.Client.1.0.9\lib\net48\Microsoft.PowerPlatform.Dataverse.Client.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Microsoft.Rest.ClientRuntime, Version=2.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Microsoft.CrmSdk.XrmTooling.CoreAssembly.9.1.1.1\lib\net462\Microsoft.Rest.ClientRuntime.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Microsoft.WindowsAzure.Storage, Version=7.2.1.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
|
||||
<SpecificVersion>False</SpecificVersion>
|
||||
<HintPath>..\packages\WindowsAzure.Storage.7.2.1\lib\net40\Microsoft.WindowsAzure.Storage.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Microsoft.Xrm.Sdk, Version=9.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Microsoft.PowerPlatform.Dataverse.Client.1.0.9\lib\net48\Microsoft.Xrm.Sdk.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Microsoft.Xrm.Sdk.Deployment, Version=9.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Microsoft.CrmSdk.Deployment.9.0.2.25\lib\net462\Microsoft.Xrm.Sdk.Deployment.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Microsoft.Xrm.Sdk.Workflow, Version=9.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Microsoft.CrmSdk.Workflow.9.0.2.42\lib\net462\Microsoft.Xrm.Sdk.Workflow.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Microsoft.Xrm.Tooling.Connector, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Microsoft.CrmSdk.XrmTooling.CoreAssembly.9.1.1.1\lib\net462\Microsoft.Xrm.Tooling.Connector.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Newtonsoft.Json, Version=13.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Newtonsoft.Json.13.0.1\lib\net45\Newtonsoft.Json.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Owin">
|
||||
<HintPath>..\packages\Owin.1.0\lib\net40\Owin.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="PagedList">
|
||||
<HintPath>..\packages\PagedList.1.17.0.0\lib\net40\PagedList.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="PagedList.Mvc">
|
||||
<HintPath>..\packages\PagedList.Mvc.4.5.0.0\lib\net40\PagedList.Mvc.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="PresentationFramework" />
|
||||
<Reference Include="RestSharp">
|
||||
<HintPath>..\packages\RestSharp.105.2.2\lib\net45\RestSharp.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Activities" />
|
||||
<Reference Include="System.Activities.Presentation" />
|
||||
<Reference Include="System.Buffers, Version=4.0.3.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\System.Buffers.4.5.1\lib\net461\System.Buffers.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System.ComponentModel.Annotations, Version=4.2.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\System.ComponentModel.Annotations.4.7.0\lib\net461\System.ComponentModel.Annotations.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System.Data" />
|
||||
<Reference Include="System.Data.DataSetExtensions" />
|
||||
<Reference Include="System.DirectoryServices" />
|
||||
<Reference Include="System.DirectoryServices.AccountManagement" />
|
||||
<Reference Include="System.Drawing" />
|
||||
<Reference Include="System.IdentityModel" />
|
||||
<Reference Include="System.IO" />
|
||||
<Reference Include="System.Linq" />
|
||||
<Reference Include="System.Linq.Expressions" />
|
||||
<Reference Include="System.Memory, Version=4.0.1.1, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\System.Memory.4.5.4\lib\net461\System.Memory.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System.Net" />
|
||||
<Reference Include="System.Numerics" />
|
||||
<Reference Include="System.Numerics.Vectors, Version=4.1.4.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\System.Numerics.Vectors.4.5.0\lib\net46\System.Numerics.Vectors.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System.Reflection" />
|
||||
<Reference Include="System.Runtime" />
|
||||
<Reference Include="System.Runtime.CompilerServices.Unsafe, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\System.Runtime.CompilerServices.Unsafe.6.0.0\lib\net461\System.Runtime.CompilerServices.Unsafe.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System.Runtime.Serialization" />
|
||||
<Reference Include="System.Runtime.Serialization.Primitives" />
|
||||
<Reference Include="System.Runtime.Serialization.Xml" />
|
||||
<Reference Include="System.Security" />
|
||||
<Reference Include="System.Security.Cryptography.Algorithms" />
|
||||
<Reference Include="System.Security.Cryptography.Encoding" />
|
||||
<Reference Include="System.Security.Cryptography.Primitives" />
|
||||
<Reference Include="System.ServiceModel" />
|
||||
<Reference Include="System.ServiceModel.Web" />
|
||||
<Reference Include="System.Spatial, Version=5.6.4.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
|
||||
<SpecificVersion>False</SpecificVersion>
|
||||
<HintPath>..\packages\System.Spatial.5.6.4\lib\net40\System.Spatial.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System.Text.Encodings.Web, Version=6.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\System.Text.Encodings.Web.6.0.0\lib\net461\System.Text.Encodings.Web.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System.Text.Json, Version=6.0.0.2, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\System.Text.Json.6.0.2\lib\net461\System.Text.Json.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System.Threading.Tasks.Extensions, Version=4.2.0.1, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\System.Threading.Tasks.Extensions.4.5.4\lib\net461\System.Threading.Tasks.Extensions.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System.ValueTuple, Version=4.0.3.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\System.ValueTuple.4.5.0\lib\net47\System.ValueTuple.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System.Web.Cors">
|
||||
<HintPath>..\packages\Microsoft.AspNet.Cors.5.0.0\lib\net45\System.Web.Cors.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System.Web.DynamicData" />
|
||||
<Reference Include="System.Web.Entity" />
|
||||
<Reference Include="System.Web.ApplicationServices" />
|
||||
<Reference Include="System.ComponentModel.DataAnnotations" />
|
||||
<Reference Include="System.Web.Extensions" />
|
||||
<Reference Include="System.Web" />
|
||||
<Reference Include="System.Web.Abstractions" />
|
||||
<Reference Include="System.Web.Routing" />
|
||||
<Reference Include="System.Windows.Forms" />
|
||||
<Reference Include="System.Workflow.Activities" />
|
||||
<Reference Include="System.Workflow.ComponentModel" />
|
||||
<Reference Include="System.Workflow.Runtime" />
|
||||
<Reference Include="System.Xml" />
|
||||
<Reference Include="System.Configuration" />
|
||||
<Reference Include="System.Web.Services" />
|
||||
<Reference Include="System.EnterpriseServices" />
|
||||
<Reference Include="Microsoft.Web.Infrastructure, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
|
||||
<Private>True</Private>
|
||||
<HintPath>..\packages\Microsoft.Web.Infrastructure.1.0.0.0\lib\net40\Microsoft.Web.Infrastructure.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System.Net.Http">
|
||||
</Reference>
|
||||
<Reference Include="System.Net.Http.WebRequest">
|
||||
</Reference>
|
||||
<Reference Include="System.Web.Helpers, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
|
||||
<Private>True</Private>
|
||||
<HintPath>..\packages\Microsoft.AspNet.WebPages.3.2.2\lib\net45\System.Web.Helpers.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System.Web.Mvc, Version=__MvcPagesVersion__, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
|
||||
<Private>True</Private>
|
||||
<HintPath>..\packages\Microsoft.AspNet.Mvc.5.2.2\lib\net45\System.Web.Mvc.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System.Web.Optimization">
|
||||
<HintPath>..\packages\Microsoft.AspNet.Web.Optimization.1.1.3\lib\net40\System.Web.Optimization.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System.Web.Razor, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
|
||||
<Private>True</Private>
|
||||
<HintPath>..\packages\Microsoft.AspNet.Razor.3.2.2\lib\net45\System.Web.Razor.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System.Web.WebPages, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
|
||||
<Private>True</Private>
|
||||
<HintPath>..\packages\Microsoft.AspNet.WebPages.3.2.2\lib\net45\System.Web.WebPages.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System.Web.WebPages.Deployment, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
|
||||
<Private>True</Private>
|
||||
<HintPath>..\packages\Microsoft.AspNet.WebPages.3.2.2\lib\net45\System.Web.WebPages.Deployment.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System.Web.WebPages.Razor, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
|
||||
<Private>True</Private>
|
||||
<HintPath>..\packages\Microsoft.AspNet.WebPages.3.2.2\lib\net45\System.Web.WebPages.Razor.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System.Xml.Linq" />
|
||||
<Reference Include="System.Xml.XmlDocument" />
|
||||
<Reference Include="Twilio.Api">
|
||||
<HintPath>..\packages\Twilio.4.7.2\lib\3.5\Twilio.Api.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Antlr3.Runtime">
|
||||
<Private>True</Private>
|
||||
<HintPath>..\packages\Antlr.3.4.1.9004\lib\Antlr3.Runtime.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="WebGrease">
|
||||
<HintPath>..\packages\WebGrease.1.5.2\lib\WebGrease.dll</HintPath>
|
||||
</Reference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="System.Net.Http.Formatting">
|
||||
<HintPath>..\packages\Microsoft.AspNet.WebApi.Client.5.2.2\lib\net45\System.Net.Http.Formatting.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System.Web.Http">
|
||||
<HintPath>..\packages\Microsoft.AspNet.WebApi.Core.5.2.2\lib\net45\System.Web.Http.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System.Web.Http.WebHost">
|
||||
<HintPath>..\packages\Microsoft.AspNet.WebApi.WebHost.5.2.2\lib\net45\System.Web.Http.WebHost.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="EntityFramework">
|
||||
<HintPath>..\packages\EntityFramework.6.1.1\lib\net45\EntityFramework.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="EntityFramework.SqlServer">
|
||||
<HintPath>..\packages\EntityFramework.6.1.1\lib\net45\EntityFramework.SqlServer.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Microsoft.AspNet.Identity.Core">
|
||||
<HintPath>..\packages\Microsoft.AspNet.Identity.Core.2.1.0\lib\net45\Microsoft.AspNet.Identity.Core.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Microsoft.AspNet.Identity.Owin">
|
||||
<HintPath>..\packages\Microsoft.AspNet.Identity.Owin.2.1.0\lib\net45\Microsoft.AspNet.Identity.Owin.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Microsoft.AspNet.Identity.EntityFramework">
|
||||
<HintPath>..\packages\Microsoft.AspNet.Identity.EntityFramework.2.1.0\lib\net45\Microsoft.AspNet.Identity.EntityFramework.dll</HintPath>
|
||||
</Reference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="App_Start\BundleConfig.cs" />
|
||||
<Compile Include="App_Start\FilterConfig.cs" />
|
||||
<Compile Include="App_Start\IdentityConfig.cs" />
|
||||
<Compile Include="App_Start\RouteConfig.cs" />
|
||||
<Compile Include="App_Start\Startup.Auth.cs" />
|
||||
<Compile Include="App_Start\WebApiConfig.cs" />
|
||||
<Compile Include="Controllers\AccountController.cs" />
|
||||
<Compile Include="Controllers\AffiliateController.cs" />
|
||||
<Compile Include="Controllers\AffiliateController.Extended.cs" />
|
||||
<Compile Include="Controllers\APIController.cs" />
|
||||
<Compile Include="Controllers\BaseController.cs" />
|
||||
<Compile Include="Controllers\ControllerHelper.cs" />
|
||||
<Compile Include="Controllers\CSSController.cs" />
|
||||
<Compile Include="Controllers\HomeController.cs" />
|
||||
<Compile Include="Controllers\ManageController.cs" />
|
||||
<Compile Include="Controllers\NotificationController.cs" />
|
||||
<Compile Include="Controllers\PrayerController.cs" />
|
||||
<Compile Include="Helpers\BlobStorageHelper.cs" />
|
||||
<Compile Include="Helpers\RequestHelper.cs" />
|
||||
<Compile Include="Helpers\StringHelper.cs" />
|
||||
<Compile Include="Helpers\UserHelper.cs" />
|
||||
<Compile Include="Migrations\201701031255563_AddCreatedUTCColumns.cs" />
|
||||
<Compile Include="Migrations\201701031255563_AddCreatedUTCColumns.Designer.cs">
|
||||
<DependentUpon>201701031255563_AddCreatedUTCColumns.cs</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Migrations\201708042356577_AddAffiliateIntructions.cs" />
|
||||
<Compile Include="Migrations\201708042356577_AddAffiliateIntructions.Designer.cs">
|
||||
<DependentUpon>201708042356577_AddAffiliateIntructions.cs</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Migrations\201708050049099_AddFieldsToSupportShowingUserNameAndLocation.cs" />
|
||||
<Compile Include="Migrations\201708050049099_AddFieldsToSupportShowingUserNameAndLocation.Designer.cs">
|
||||
<DependentUpon>201708050049099_AddFieldsToSupportShowingUserNameAndLocation.cs</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Migrations\Configuration.cs" />
|
||||
<Compile Include="Models\Affiliate.cs" />
|
||||
<Compile Include="Models\AffiliateAdmin.cs" />
|
||||
<Compile Include="Models\AffiliateStyle.cs" />
|
||||
<Compile Include="Models\AffiliateViewModels.cs" />
|
||||
<Compile Include="Models\AutoFlagItem.cs" />
|
||||
<Compile Include="Models\BlacklistEmail.cs" />
|
||||
<Compile Include="Models\BlacklistIP.cs" />
|
||||
<Compile Include="Models\EmailViewModels.cs" />
|
||||
<Compile Include="Models\FacebookAuthModels.cs" />
|
||||
<Compile Include="Models\Prayer.cs" />
|
||||
<Compile Include="Global.asax.cs">
|
||||
<DependentUpon>Global.asax</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Models\AccountViewModels.cs" />
|
||||
<Compile Include="Models\IdentityModels.cs" />
|
||||
<Compile Include="Models\ManageViewModels.cs" />
|
||||
<Compile Include="Models\PrayerSource.cs" />
|
||||
<Compile Include="Models\PrayerSubscription.cs" />
|
||||
<Compile Include="Models\PrayerFlag.cs" />
|
||||
<Compile Include="Models\PrayerItem.cs" />
|
||||
<Compile Include="Models\PrayerBookmark.cs" />
|
||||
<Compile Include="Models\PrayerNote.cs" />
|
||||
<Compile Include="Models\PrayerViewModels.cs" />
|
||||
<Compile Include="Models\RelatedPrayer.cs" />
|
||||
<Compile Include="Models\SubscriptionType.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
<Compile Include="Startup.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Content Include="Content\bootstrap-tagsinput-typeahead.css" />
|
||||
<Content Include="Content\bootstrap-tagsinput.css" />
|
||||
<Content Include="Content\bootstrap.css" />
|
||||
<Content Include="Content\bootstrap.min.css" />
|
||||
<Content Include="Content\Images\ajax-loader-2.gif" />
|
||||
<Content Include="Content\Images\ajax-loader.gif" />
|
||||
<Content Include="Content\Images\amen-logo-flyin.gif" />
|
||||
<Content Include="Content\Images\amenico100.png" />
|
||||
<Content Include="Content\Images\Blank.png" />
|
||||
<Content Include="Content\Images\fb-share-logo-small.png" />
|
||||
<Content Include="Content\Images\fb-share-logo.png" />
|
||||
<Content Include="Content\Images\poweredbyamenprayer.png" />
|
||||
<Content Include="Content\PagedList.css" />
|
||||
<Content Include="Content\SiteCustom.css" />
|
||||
<Content Include="favicon.ico" />
|
||||
<Content Include="fonts\glyphicons-halflings-regular.svg" />
|
||||
<Content Include="Global.asax" />
|
||||
<Content Include="Content\Site.css" />
|
||||
<Content Include="Scripts\bootstrap-tagsinput-angular.js" />
|
||||
<Content Include="Scripts\bootstrap-tagsinput-angular.min.js" />
|
||||
<Content Include="Scripts\bootstrap-tagsinput.js" />
|
||||
<Content Include="Scripts\bootstrap-tagsinput.min.js" />
|
||||
<Content Include="Scripts\bootstrap.js" />
|
||||
<Content Include="Scripts\bootstrap.min.js" />
|
||||
<Content Include="Content\Site.scss" />
|
||||
<Content Include="Content\bootstrap-tagsinput.less" />
|
||||
<Content Include="Scripts\bootstrap-tagsinput-angular.min.js.map" />
|
||||
<Content Include="Scripts\bootstrap-tagsinput.min.js.map" />
|
||||
<Content Include="libman.json" />
|
||||
<None Include="Properties\PublishProfiles\Prod.pubxml" />
|
||||
<None Include="Properties\PublishProfiles\Stage.pubxml" />
|
||||
<None Include="Scripts\jquery-1.10.2.intellisense.js" />
|
||||
<Content Include="Scripts\jquery-1.10.2.js" />
|
||||
<Content Include="Scripts\jquery-1.10.2.min.js" />
|
||||
<None Include="Scripts\jquery.validate-vsdoc.js" />
|
||||
<Content Include="Scripts\jquery.validate.js" />
|
||||
<Content Include="Scripts\jquery.validate.min.js" />
|
||||
<Content Include="Scripts\jquery.validate.unobtrusive.js" />
|
||||
<Content Include="Scripts\jquery.validate.unobtrusive.min.js" />
|
||||
<Content Include="Scripts\modernizr-2.6.2.js" />
|
||||
<Content Include="Scripts\site-user.js" />
|
||||
<Content Include="Scripts\site-affiliate.js" />
|
||||
<Content Include="Scripts\site-prayer.js" />
|
||||
<Content Include="Scripts\respond.js" />
|
||||
<Content Include="Scripts\respond.min.js" />
|
||||
<Content Include="Scripts\site-common.js" />
|
||||
<Content Include="Scripts\_references.js" />
|
||||
<Content Include="Web.config">
|
||||
<SubType>Designer</SubType>
|
||||
</Content>
|
||||
<Content Include="Web.Debug.config">
|
||||
<DependentUpon>Web.config</DependentUpon>
|
||||
</Content>
|
||||
<Content Include="Web.Release.config">
|
||||
<DependentUpon>Web.config</DependentUpon>
|
||||
<SubType>Designer</SubType>
|
||||
</Content>
|
||||
<Content Include="Views\Web.config" />
|
||||
<Content Include="Views\_ViewStart.cshtml" />
|
||||
<Content Include="Views\Shared\Error.cshtml" />
|
||||
<Content Include="Views\Shared\_Layout.cshtml" />
|
||||
<Content Include="Views\Home\UpgradeInProgress.cshtml" />
|
||||
<Content Include="Scripts\jquery-1.10.2.min.map" />
|
||||
<Content Include="Views\Account\_ExternalLoginsListPartial.cshtml" />
|
||||
<Content Include="Views\Account\ConfirmEmail.cshtml" />
|
||||
<Content Include="Views\Account\ExternalLoginConfirmation.cshtml" />
|
||||
<Content Include="Views\Account\ExternalLoginFailure.cshtml" />
|
||||
<Content Include="Views\Account\ForgotPassword.cshtml" />
|
||||
<Content Include="Views\Account\ForgotPasswordConfirmation.cshtml" />
|
||||
<Content Include="Views\Account\Login.cshtml" />
|
||||
<Content Include="Views\Account\Register.cshtml" />
|
||||
<Content Include="Views\Account\ResetPassword.cshtml" />
|
||||
<Content Include="Views\Account\ResetPasswordConfirmation.cshtml" />
|
||||
<Content Include="Views\Account\SendCode.cshtml" />
|
||||
<Content Include="Views\Account\VerifyCode.cshtml" />
|
||||
<Content Include="Views\Manage\AddPhoneNumber.cshtml" />
|
||||
<Content Include="Views\Manage\ChangePassword.cshtml" />
|
||||
<Content Include="Views\Manage\Index.cshtml" />
|
||||
<Content Include="Views\Manage\ManageLogins.cshtml" />
|
||||
<Content Include="Views\Manage\SetPassword.cshtml" />
|
||||
<Content Include="Views\Manage\VerifyPhoneNumber.cshtml" />
|
||||
<Content Include="Views\Shared\Lockout.cshtml" />
|
||||
<Content Include="Views\Shared\_LoginPartial.cshtml" />
|
||||
<Content Include="Views\Prayer\Index.cshtml" />
|
||||
<Content Include="Views\Prayer\_PrayerItems.cshtml" />
|
||||
<Content Include="Views\Affiliate\Select.cshtml" />
|
||||
<Content Include="Views\Affiliate\Create.cshtml" />
|
||||
<Content Include="Views\Affiliate\Delete.cshtml" />
|
||||
<Content Include="Views\Affiliate\Details.cshtml" />
|
||||
<Content Include="Views\Affiliate\Edit.cshtml" />
|
||||
<Content Include="Views\Affiliate\Index.cshtml" />
|
||||
<Content Include="Views\Affiliate\_Tabs.cshtml" />
|
||||
<Content Include="Views\Affiliate\Style.cshtml" />
|
||||
<Content Include="Views\Affiliate\Prayers.cshtml" />
|
||||
<Content Include="Views\Affiliate\Praise.cshtml" />
|
||||
<Content Include="Views\Affiliate\PrayerEdit.cshtml" />
|
||||
<Content Include="Views\Affiliate\Stats.cshtml" />
|
||||
<Content Include="Views\Email\PrayerSubmitted.cshtml" />
|
||||
<Content Include="Views\Email\Prayed.cshtml" />
|
||||
<Content Include="Views\Email\NoteSent.cshtml" />
|
||||
<Content Include="Views\Affiliate\Users.cshtml" />
|
||||
<Content Include="Views\Affiliate\FlagWords.cshtml" />
|
||||
<Content Include="Views\Email\AdminNotification.cshtml" />
|
||||
<Content Include="Views\Affiliate\FlagIPs.cshtml" />
|
||||
<Content Include="Views\Affiliate\FlagEmails.cshtml" />
|
||||
<Content Include="Views\Prayer\_EditPrayer.cshtml" />
|
||||
<None Include="Web.Stage.config">
|
||||
<DependentUpon>Web.config</DependentUpon>
|
||||
<SubType>Designer</SubType>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Folder Include="App_Data\" />
|
||||
<Folder Include="Views\API\" />
|
||||
<Folder Include="Views\Notification\" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Content Include="fonts\glyphicons-halflings-regular.woff" />
|
||||
<Content Include="fonts\glyphicons-halflings-regular.ttf" />
|
||||
<Content Include="fonts\glyphicons-halflings-regular.eot" />
|
||||
<Content Include="packages.config" />
|
||||
<None Include="Project_Readme.html" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<EmbeddedResource Include="Migrations\201701031255563_AddCreatedUTCColumns.resx">
|
||||
<DependentUpon>201701031255563_AddCreatedUTCColumns.cs</DependentUpon>
|
||||
</EmbeddedResource>
|
||||
<EmbeddedResource Include="Migrations\201708042356577_AddAffiliateIntructions.resx">
|
||||
<DependentUpon>201708042356577_AddAffiliateIntructions.cs</DependentUpon>
|
||||
</EmbeddedResource>
|
||||
<EmbeddedResource Include="Migrations\201708050049099_AddFieldsToSupportShowingUserNameAndLocation.resx">
|
||||
<DependentUpon>201708050049099_AddFieldsToSupportShowingUserNameAndLocation.cs</DependentUpon>
|
||||
</EmbeddedResource>
|
||||
</ItemGroup>
|
||||
<PropertyGroup>
|
||||
<VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">10.0</VisualStudioVersion>
|
||||
<VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Stage|AnyCPU'">
|
||||
<OutputPath>bin\</OutputPath>
|
||||
<DefineConstants>TRACE</DefineConstants>
|
||||
<Optimize>true</Optimize>
|
||||
<DebugType>pdbonly</DebugType>
|
||||
<PlatformTarget>AnyCPU</PlatformTarget>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
|
||||
<Import Project="$(VSToolsPath)\WebApplications\Microsoft.WebApplication.targets" Condition="'$(VSToolsPath)' != ''" />
|
||||
<Import Project="$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v10.0\WebApplications\Microsoft.WebApplication.targets" Condition="false" />
|
||||
<Target Name="MvcBuildViews" AfterTargets="AfterBuild" Condition="'$(MvcBuildViews)'=='true'">
|
||||
<AspNetCompiler VirtualPath="temp" PhysicalPath="$(WebProjectOutputDir)" />
|
||||
</Target>
|
||||
<ProjectExtensions>
|
||||
<VisualStudio>
|
||||
<FlavorProperties GUID="{349c5851-65df-11da-9384-00065b846f21}">
|
||||
<WebProjectProperties>
|
||||
<UseIIS>True</UseIIS>
|
||||
<AutoAssignPort>True</AutoAssignPort>
|
||||
<DevelopmentServerPort>22024</DevelopmentServerPort>
|
||||
<DevelopmentServerVPath>/</DevelopmentServerVPath>
|
||||
<IISUrl>http://localhost:50539/</IISUrl>
|
||||
<NTLMAuthentication>False</NTLMAuthentication>
|
||||
<UseCustomServer>False</UseCustomServer>
|
||||
<CustomServerUrl>
|
||||
</CustomServerUrl>
|
||||
<SaveServerSettingsInUserFile>False</SaveServerSettingsInUserFile>
|
||||
</WebProjectProperties>
|
||||
</FlavorProperties>
|
||||
</VisualStudio>
|
||||
</ProjectExtensions>
|
||||
<Import Project="..\packages\System.Text.Json.6.0.2\build\System.Text.Json.targets" Condition="Exists('..\packages\System.Text.Json.6.0.2\build\System.Text.Json.targets')" />
|
||||
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
|
||||
<PropertyGroup>
|
||||
<ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
|
||||
</PropertyGroup>
|
||||
<Error Condition="!Exists('..\packages\System.Text.Json.6.0.2\build\System.Text.Json.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\System.Text.Json.6.0.2\build\System.Text.Json.targets'))" />
|
||||
</Target>
|
||||
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
|
||||
Other similar extension points exist, see Microsoft.Common.targets.
|
||||
<Target Name="BeforeBuild">
|
||||
</Target>
|
||||
<Target Name="AfterBuild">
|
||||
</Target> -->
|
||||
</Project>
|
33
Amen/App_Start/BundleConfig.cs
Normal file
@ -0,0 +1,33 @@
|
||||
using System.Web;
|
||||
using System.Web.Optimization;
|
||||
|
||||
namespace Amen
|
||||
{
|
||||
public class BundleConfig
|
||||
{
|
||||
// For more information on bundling, visit http://go.microsoft.com/fwlink/?LinkId=301862
|
||||
public static void RegisterBundles(BundleCollection bundles)
|
||||
{
|
||||
bundles.Add(new ScriptBundle("~/bundles/jquery").Include(
|
||||
"~/Scripts/jquery-{version}.js"));
|
||||
|
||||
bundles.Add(new ScriptBundle("~/bundles/jqueryval").Include(
|
||||
"~/Scripts/jquery.validate*"));
|
||||
|
||||
// Use the development version of Modernizr to develop with and learn from. Then, when you're
|
||||
// ready for production, use the build tool at http://modernizr.com to pick only the tests you need.
|
||||
bundles.Add(new ScriptBundle("~/bundles/modernizr").Include(
|
||||
"~/Scripts/modernizr-*"));
|
||||
|
||||
bundles.Add(new ScriptBundle("~/bundles/bootstrap").Include(
|
||||
"~/Scripts/bootstrap.js",
|
||||
"~/Scripts/bootstrap-tagsinput.min.js",
|
||||
"~/Scripts/respond.js"));
|
||||
|
||||
var assemblyVersion = System.Reflection.Assembly.GetExecutingAssembly().GetName().Version.ToString();
|
||||
bundles.Add(new StyleBundle("~/Content/css").Include(
|
||||
"~/Content/bootstrap.css",
|
||||
"~/Content/bootstrap-tagsinput.css"));
|
||||
}
|
||||
}
|
||||
}
|
13
Amen/App_Start/FilterConfig.cs
Normal file
@ -0,0 +1,13 @@
|
||||
using System.Web;
|
||||
using System.Web.Mvc;
|
||||
|
||||
namespace Amen
|
||||
{
|
||||
public class FilterConfig
|
||||
{
|
||||
public static void RegisterGlobalFilters(GlobalFilterCollection filters)
|
||||
{
|
||||
filters.Add(new HandleErrorAttribute());
|
||||
}
|
||||
}
|
||||
}
|
126
Amen/App_Start/IdentityConfig.cs
Normal file
@ -0,0 +1,126 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Data.Entity;
|
||||
using System.Linq;
|
||||
using System.Security.Claims;
|
||||
using System.Threading.Tasks;
|
||||
using System.Web;
|
||||
using Microsoft.AspNet.Identity;
|
||||
using Microsoft.AspNet.Identity.EntityFramework;
|
||||
using Microsoft.AspNet.Identity.Owin;
|
||||
using Microsoft.Owin;
|
||||
using Microsoft.Owin.Security;
|
||||
using Amen.Models;
|
||||
using Twilio;
|
||||
using System.Net;
|
||||
using System.Net.Mail;
|
||||
using Amen.Controllers;
|
||||
|
||||
namespace Amen
|
||||
{
|
||||
public class EmailService : IIdentityMessageService
|
||||
{
|
||||
public Task SendAsync(IdentityMessage message)
|
||||
{
|
||||
NotificationController.SendEmailMessage(message.Destination, message.Subject, message.Body, NotificationController.EmailSendType.Account);
|
||||
|
||||
return Task.FromResult(0);
|
||||
}
|
||||
}
|
||||
|
||||
public class SmsIdentityMessage : IdentityMessage
|
||||
{
|
||||
public string TwilioSID { get; set; }
|
||||
public string TwilioAuthToken { get; set; }
|
||||
public string TwilioPhoneNumber { get; set; }
|
||||
}
|
||||
|
||||
public class SmsService : IIdentityMessageService
|
||||
{
|
||||
public Task SendAsync(IdentityMessage message)
|
||||
{
|
||||
if (message is SmsIdentityMessage)
|
||||
{
|
||||
var smsmessage = (SmsIdentityMessage)message;
|
||||
NotificationController.SendSmsMessage(smsmessage.TwilioSID, smsmessage.TwilioAuthToken, smsmessage.TwilioPhoneNumber, message.Destination, message.Body);
|
||||
}
|
||||
|
||||
return Task.FromResult(0);
|
||||
}
|
||||
}
|
||||
|
||||
// Configure the application user manager used in this application. UserManager is defined in ASP.NET Identity and is used by the application.
|
||||
public class ApplicationUserManager : UserManager<ApplicationUser>
|
||||
{
|
||||
public ApplicationUserManager(IUserStore<ApplicationUser> store)
|
||||
: base(store)
|
||||
{
|
||||
}
|
||||
|
||||
public static ApplicationUserManager Create(IdentityFactoryOptions<ApplicationUserManager> options, IOwinContext context)
|
||||
{
|
||||
var manager = new ApplicationUserManager(new UserStore<ApplicationUser>(context.Get<ApplicationDbContext>()));
|
||||
// Configure validation logic for usernames
|
||||
manager.UserValidator = new UserValidator<ApplicationUser>(manager)
|
||||
{
|
||||
AllowOnlyAlphanumericUserNames = false,
|
||||
RequireUniqueEmail = true
|
||||
};
|
||||
|
||||
// Configure validation logic for passwords
|
||||
manager.PasswordValidator = new PasswordValidator
|
||||
{
|
||||
RequiredLength = 6,
|
||||
RequireNonLetterOrDigit = true,
|
||||
RequireDigit = true,
|
||||
RequireLowercase = true,
|
||||
RequireUppercase = true,
|
||||
};
|
||||
|
||||
// Configure user lockout defaults
|
||||
manager.UserLockoutEnabledByDefault = true;
|
||||
manager.DefaultAccountLockoutTimeSpan = TimeSpan.FromMinutes(5);
|
||||
manager.MaxFailedAccessAttemptsBeforeLockout = 5;
|
||||
|
||||
// Register two factor authentication providers. This application uses Phone and Emails as a step of receiving a code for verifying the user
|
||||
// You can write your own provider and plug it in here.
|
||||
manager.RegisterTwoFactorProvider("Phone Code", new PhoneNumberTokenProvider<ApplicationUser>
|
||||
{
|
||||
MessageFormat = "Your security code is {0}"
|
||||
});
|
||||
manager.RegisterTwoFactorProvider("Email Code", new EmailTokenProvider<ApplicationUser>
|
||||
{
|
||||
Subject = "Security Code",
|
||||
BodyFormat = "Your security code is {0}"
|
||||
});
|
||||
manager.EmailService = new EmailService();
|
||||
manager.SmsService = new SmsService();
|
||||
var dataProtectionProvider = options.DataProtectionProvider;
|
||||
if (dataProtectionProvider != null)
|
||||
{
|
||||
manager.UserTokenProvider =
|
||||
new DataProtectorTokenProvider<ApplicationUser>(dataProtectionProvider.Create("ASP.NET Identity"));
|
||||
}
|
||||
return manager;
|
||||
}
|
||||
}
|
||||
|
||||
// Configure the application sign-in manager which is used in this application.
|
||||
public class ApplicationSignInManager : SignInManager<ApplicationUser, string>
|
||||
{
|
||||
public ApplicationSignInManager(ApplicationUserManager userManager, IAuthenticationManager authenticationManager)
|
||||
: base(userManager, authenticationManager)
|
||||
{
|
||||
}
|
||||
|
||||
public override Task<ClaimsIdentity> CreateUserIdentityAsync(ApplicationUser user)
|
||||
{
|
||||
return user.GenerateUserIdentityAsync((ApplicationUserManager)UserManager);
|
||||
}
|
||||
|
||||
public static ApplicationSignInManager Create(IdentityFactoryOptions<ApplicationSignInManager> options, IOwinContext context)
|
||||
{
|
||||
return new ApplicationSignInManager(context.GetUserManager<ApplicationUserManager>(), context.Authentication);
|
||||
}
|
||||
}
|
||||
}
|
85
Amen/App_Start/RouteConfig.cs
Normal file
@ -0,0 +1,85 @@
|
||||
using Amen.Controllers;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Web;
|
||||
using System.Web.Mvc;
|
||||
using System.Web.Routing;
|
||||
|
||||
namespace Amen
|
||||
{
|
||||
public class RouteConfig
|
||||
{
|
||||
public static void RegisterRoutes(RouteCollection routes)
|
||||
{
|
||||
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
|
||||
|
||||
routes.MapRoute(
|
||||
name: "APIRoute",
|
||||
url: "API/{action}/{id}", // URL with parameters
|
||||
defaults: new { controller = "API", action = "Index", id = UrlParameter.Optional, affiliatekey = ControllerHelper.DefaultAffiliateKey }
|
||||
);
|
||||
|
||||
routes.MapRoute(
|
||||
name: "HomeRoute",
|
||||
url: "Home/{action}/{id}", // URL with parameters
|
||||
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional, affiliatekey = ControllerHelper.DefaultAffiliateKey }
|
||||
);
|
||||
|
||||
routes.MapRoute(
|
||||
name: "AccountRoute",
|
||||
url: "Account/{action}/{id}", // URL with parameters
|
||||
defaults: new { controller = "Account", action = "Index", id = UrlParameter.Optional, affiliatekey = ControllerHelper.DefaultAffiliateKey }
|
||||
);
|
||||
|
||||
routes.MapRoute(
|
||||
name: "ManageRoute",
|
||||
url: "Manage/{action}/{id}", // URL with parameters
|
||||
defaults: new { controller = "Manage", action = "Index", id = UrlParameter.Optional, affiliatekey = ControllerHelper.DefaultAffiliateKey }
|
||||
);
|
||||
|
||||
routes.MapRoute(
|
||||
name: "NotificationRout",
|
||||
url: "Notification/{action}/{id}", // URL with parameters
|
||||
defaults: new { controller = "Notification", action = "Index", id = UrlParameter.Optional, affiliatekey = ControllerHelper.DefaultAffiliateKey }
|
||||
);
|
||||
|
||||
routes.MapRoute(
|
||||
name: "PrayerRoute",
|
||||
url: "Prayer/{action}/{id}", // URL with parameters
|
||||
defaults: new { controller = "Prayer", action = "Index", id = UrlParameter.Optional, affiliatekey = ControllerHelper.DefaultAffiliateKey }
|
||||
);
|
||||
|
||||
routes.MapRoute(
|
||||
name: "AffiliateAdminRoute",
|
||||
url: "Affiliate/{action}/{id}", // URL with parameters
|
||||
defaults: new { controller = "Affiliate", action = "Index", id = UrlParameter.Optional, affiliatekey = ControllerHelper.DefaultAffiliateKey }
|
||||
);
|
||||
|
||||
routes.MapRoute(
|
||||
name: "AffiliateGroupAliasRoute",
|
||||
url: "Group/{action}/{id}", // URL with parameters
|
||||
defaults: new { controller = "Affiliate", action = "Index", id = UrlParameter.Optional, affiliatekey = ControllerHelper.DefaultAffiliateKey }
|
||||
);
|
||||
|
||||
routes.MapRoute(
|
||||
name: "CSSRoute",
|
||||
url: "CSS/{action}/{id}", // URL with parameters
|
||||
defaults: new { controller = "CSS", action = "GetTheme", id = UrlParameter.Optional, affiliatekey = ControllerHelper.DefaultAffiliateKey }
|
||||
);
|
||||
|
||||
routes.MapRoute(
|
||||
name: "AffiliateGroupPrayerRoute",
|
||||
url: "{affiliatekey}/Group/{action}/{id}", // URL with parameters
|
||||
defaults: new { controller = "Affiliate", action = "Index", id = UrlParameter.Optional, affiliatekey = ControllerHelper.DefaultAffiliateKey }
|
||||
);
|
||||
|
||||
routes.MapRoute(
|
||||
name: "AffiliatePrayerRoute",
|
||||
url: "{affiliatekey}/{controller}/{action}/{id}", // URL with parameters
|
||||
defaults: new { controller = "Prayer", action = "Index", id = UrlParameter.Optional, affiliatekey = ControllerHelper.DefaultAffiliateKey }
|
||||
);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
93
Amen/App_Start/Startup.Auth.cs
Normal file
@ -0,0 +1,93 @@
|
||||
using System;
|
||||
using Microsoft.AspNet.Identity;
|
||||
using Microsoft.AspNet.Identity.Owin;
|
||||
using Microsoft.Owin;
|
||||
using Microsoft.Owin.Security.Cookies;
|
||||
using Microsoft.Owin.Security.Google;
|
||||
using Owin;
|
||||
using Amen.Models;
|
||||
using Microsoft.Owin.Security.Facebook;
|
||||
using System.Threading.Tasks;
|
||||
using System.Configuration;
|
||||
using System.Security.Claims;
|
||||
|
||||
namespace Amen
|
||||
{
|
||||
public partial class Startup
|
||||
{
|
||||
// For more information on configuring authentication, please visit http://go.microsoft.com/fwlink/?LinkId=301864
|
||||
public void ConfigureAuth(IAppBuilder app)
|
||||
{
|
||||
// Configure the db context, user manager and signin manager to use a single instance per request
|
||||
app.CreatePerOwinContext(ApplicationDbContext.Create);
|
||||
app.CreatePerOwinContext<ApplicationUserManager>(ApplicationUserManager.Create);
|
||||
app.CreatePerOwinContext<ApplicationSignInManager>(ApplicationSignInManager.Create);
|
||||
|
||||
// Enable the application to use a cookie to store information for the signed in user
|
||||
// and to use a cookie to temporarily store information about a user logging in with a third party login provider
|
||||
// Configure the sign in cookie
|
||||
app.UseCookieAuthentication(new CookieAuthenticationOptions
|
||||
{
|
||||
AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,
|
||||
LoginPath = new PathString("/Account/Login"),
|
||||
Provider = new CookieAuthenticationProvider
|
||||
{
|
||||
// Enables the application to validate the security stamp when the user logs in.
|
||||
// This is a security feature which is used when you change a password or add an external login to your account.
|
||||
OnValidateIdentity = SecurityStampValidator.OnValidateIdentity<ApplicationUserManager, ApplicationUser>(
|
||||
validateInterval: TimeSpan.FromMinutes(30),
|
||||
regenerateIdentity: (manager, user) => user.GenerateUserIdentityAsync(manager))
|
||||
}
|
||||
});
|
||||
app.UseExternalSignInCookie(DefaultAuthenticationTypes.ExternalCookie);
|
||||
|
||||
// Enables the application to temporarily store user information when they are verifying the second factor in the two-factor authentication process.
|
||||
app.UseTwoFactorSignInCookie(DefaultAuthenticationTypes.TwoFactorCookie, TimeSpan.FromMinutes(5));
|
||||
|
||||
// Enables the application to remember the second login verification factor such as phone or email.
|
||||
// Once you check this option, your second step of verification during the login process will be remembered on the device where you logged in from.
|
||||
// This is similar to the RememberMe option when you log in.
|
||||
app.UseTwoFactorRememberBrowserCookie(DefaultAuthenticationTypes.TwoFactorRememberBrowserCookie);
|
||||
|
||||
// Uncomment the following lines to enable logging in with third party login providers
|
||||
//app.UseMicrosoftAccountAuthentication(
|
||||
// clientId: "",
|
||||
// clientSecret: "");
|
||||
|
||||
//app.UseTwitterAuthentication(
|
||||
// consumerKey: "",
|
||||
// consumerSecret: "");
|
||||
|
||||
|
||||
//dev app id
|
||||
//app.UseFacebookAuthentication(
|
||||
// appId: "632247943624667",
|
||||
// appSecret: "6e7ea1d9453593071b1bc350cda718b7");
|
||||
|
||||
app.UseFacebookAuthentication(new FacebookAuthenticationOptions
|
||||
{
|
||||
//AppId = "1837084549899587",
|
||||
//AppSecret = "53452d285d8cf760f8fe8da491ddfb20",
|
||||
|
||||
AppId = ConfigurationManager.AppSettings["FacebookAppId"],
|
||||
AppSecret = ConfigurationManager.AppSettings["FacebookAppSecret"],
|
||||
Scope = { "email" },
|
||||
Provider = new FacebookAuthenticationProvider
|
||||
{
|
||||
OnAuthenticated = context =>
|
||||
{
|
||||
context.Identity.AddClaim(new System.Security.Claims.Claim("FacebookAccessToken", context.AccessToken));
|
||||
return Task.FromResult(true);
|
||||
}
|
||||
},
|
||||
//BackchannelHttpHandler = new FacebookBackChannelHandler()
|
||||
});
|
||||
|
||||
//app.UseGoogleAuthentication(new GoogleOAuth2AuthenticationOptions()
|
||||
//{
|
||||
// ClientId = "",
|
||||
// ClientSecret = ""
|
||||
//});
|
||||
}
|
||||
}
|
||||
}
|
24
Amen/App_Start/WebApiConfig.cs
Normal file
@ -0,0 +1,24 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Web.Http;
|
||||
|
||||
namespace Amen
|
||||
{
|
||||
public static class WebApiConfig
|
||||
{
|
||||
public static void Register(HttpConfiguration config)
|
||||
{
|
||||
// Web API configuration and services
|
||||
|
||||
// Web API routes
|
||||
config.MapHttpAttributeRoutes();
|
||||
|
||||
config.Routes.MapHttpRoute(
|
||||
name: "DefaultApi",
|
||||
routeTemplate: "api/{controller}/{id}",
|
||||
defaults: new { id = RouteParameter.Optional }
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
BIN
Amen/Content/Images/Blank.png
Normal file
After Width: | Height: | Size: 179 B |
BIN
Amen/Content/Images/ajax-loader-2.gif
Normal file
After Width: | Height: | Size: 6.7 KiB |
BIN
Amen/Content/Images/ajax-loader.gif
Normal file
After Width: | Height: | Size: 673 B |
BIN
Amen/Content/Images/amen-logo-flyin.gif
Normal file
After Width: | Height: | Size: 155 KiB |
BIN
Amen/Content/Images/amenico100.png
Normal file
After Width: | Height: | Size: 8.0 KiB |
BIN
Amen/Content/Images/fb-share-logo-small.png
Normal file
After Width: | Height: | Size: 18 KiB |
BIN
Amen/Content/Images/fb-share-logo.png
Normal file
After Width: | Height: | Size: 349 KiB |
BIN
Amen/Content/Images/poweredbyamenprayer.png
Normal file
After Width: | Height: | Size: 14 KiB |
166
Amen/Content/PagedList.css
Normal file
@ -0,0 +1,166 @@
|
||||
.pagination {
|
||||
display: inline-block;
|
||||
padding-left: 0;
|
||||
margin: 20px 0;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.pagination > li {
|
||||
display: inline;
|
||||
}
|
||||
|
||||
.pagination > li > a,
|
||||
.pagination > li > span {
|
||||
position: relative;
|
||||
float: left;
|
||||
padding: 6px 12px;
|
||||
margin-left: -1px;
|
||||
line-height: 1.428571429;
|
||||
text-decoration: none;
|
||||
background-color: #ffffff;
|
||||
border: 1px solid #dddddd;
|
||||
}
|
||||
|
||||
.pagination > li:first-child > a,
|
||||
.pagination > li:first-child > span {
|
||||
margin-left: 0;
|
||||
border-bottom-left-radius: 4px;
|
||||
border-top-left-radius: 4px;
|
||||
}
|
||||
|
||||
.pagination > li:last-child > a,
|
||||
.pagination > li:last-child > span {
|
||||
border-top-right-radius: 4px;
|
||||
border-bottom-right-radius: 4px;
|
||||
}
|
||||
|
||||
.pagination > li > a:hover,
|
||||
.pagination > li > span:hover,
|
||||
.pagination > li > a:focus,
|
||||
.pagination > li > span:focus {
|
||||
background-color: #eeeeee;
|
||||
}
|
||||
|
||||
.pagination > .active > a,
|
||||
.pagination > .active > span,
|
||||
.pagination > .active > a:hover,
|
||||
.pagination > .active > span:hover,
|
||||
.pagination > .active > a:focus,
|
||||
.pagination > .active > span:focus {
|
||||
z-index: 2;
|
||||
color: #ffffff;
|
||||
cursor: default;
|
||||
background-color: #428bca;
|
||||
border-color: #428bca;
|
||||
}
|
||||
|
||||
.pagination > .disabled > span,
|
||||
.pagination > .disabled > a,
|
||||
.pagination > .disabled > a:hover,
|
||||
.pagination > .disabled > a:focus {
|
||||
color: #999999;
|
||||
cursor: not-allowed;
|
||||
background-color: #ffffff;
|
||||
border-color: #dddddd;
|
||||
}
|
||||
|
||||
.pagination-lg > li > a,
|
||||
.pagination-lg > li > span {
|
||||
padding: 10px 16px;
|
||||
font-size: 18px;
|
||||
}
|
||||
|
||||
.pagination-lg > li:first-child > a,
|
||||
.pagination-lg > li:first-child > span {
|
||||
border-bottom-left-radius: 6px;
|
||||
border-top-left-radius: 6px;
|
||||
}
|
||||
|
||||
.pagination-lg > li:last-child > a,
|
||||
.pagination-lg > li:last-child > span {
|
||||
border-top-right-radius: 6px;
|
||||
border-bottom-right-radius: 6px;
|
||||
}
|
||||
|
||||
.pagination-sm > li > a,
|
||||
.pagination-sm > li > span {
|
||||
padding: 5px 10px;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.pagination-sm > li:first-child > a,
|
||||
.pagination-sm > li:first-child > span {
|
||||
border-bottom-left-radius: 3px;
|
||||
border-top-left-radius: 3px;
|
||||
}
|
||||
|
||||
.pagination-sm > li:last-child > a,
|
||||
.pagination-sm > li:last-child > span {
|
||||
border-top-right-radius: 3px;
|
||||
border-bottom-right-radius: 3px;
|
||||
}
|
||||
|
||||
.pager {
|
||||
padding-left: 0;
|
||||
margin: 20px 0;
|
||||
text-align: center;
|
||||
list-style: none;
|
||||
}
|
||||
|
||||
.pager:before,
|
||||
.pager:after {
|
||||
display: table;
|
||||
content: " ";
|
||||
}
|
||||
|
||||
.pager:after {
|
||||
clear: both;
|
||||
}
|
||||
|
||||
.pager:before,
|
||||
.pager:after {
|
||||
display: table;
|
||||
content: " ";
|
||||
}
|
||||
|
||||
.pager:after {
|
||||
clear: both;
|
||||
}
|
||||
|
||||
.pager li {
|
||||
display: inline;
|
||||
}
|
||||
|
||||
.pager li > a,
|
||||
.pager li > span {
|
||||
display: inline-block;
|
||||
padding: 5px 14px;
|
||||
background-color: #ffffff;
|
||||
border: 1px solid #dddddd;
|
||||
border-radius: 15px;
|
||||
}
|
||||
|
||||
.pager li > a:hover,
|
||||
.pager li > a:focus {
|
||||
text-decoration: none;
|
||||
background-color: #eeeeee;
|
||||
}
|
||||
|
||||
.pager .next > a,
|
||||
.pager .next > span {
|
||||
float: right;
|
||||
}
|
||||
|
||||
.pager .previous > a,
|
||||
.pager .previous > span {
|
||||
float: left;
|
||||
}
|
||||
|
||||
.pager .disabled > a,
|
||||
.pager .disabled > a:hover,
|
||||
.pager .disabled > a:focus,
|
||||
.pager .disabled > span {
|
||||
color: #999999;
|
||||
cursor: not-allowed;
|
||||
background-color: #ffffff;
|
||||
}
|
581
Amen/Content/Site.css
Normal file
@ -0,0 +1,581 @@
|
||||
/*
|
||||
$SiteLightColor: #FDEFEF;
|
||||
$SiteMediumColor: rgba(172, 25, 25, 0.5);
|
||||
$SiteDarkColor: #741111;
|
||||
$SiteForeground: #ffffff;
|
||||
$SiteForegroundHover: #F9D4D4;
|
||||
$SiteBorder: #F7CACA;
|
||||
$SiteButtonHilight: #F9D9D9;
|
||||
|
||||
*/
|
||||
body {
|
||||
padding-top: 0px;
|
||||
padding-bottom: 20px;
|
||||
font-family: "Source Sans Pro", sans-serif;
|
||||
font-size: 15px; }
|
||||
|
||||
.container {
|
||||
padding-right: 0px;
|
||||
padding-left: 0px;
|
||||
margin-right: auto;
|
||||
margin-left: auto; }
|
||||
|
||||
h2 {
|
||||
color: #1a346b;
|
||||
font-weight: 200; }
|
||||
|
||||
a {
|
||||
color: #1a346b;
|
||||
text-decoration: none; }
|
||||
|
||||
/* Set padding to keep content from hitting the edges */
|
||||
.body-content {
|
||||
padding-left: 15px;
|
||||
padding-right: 15px; }
|
||||
|
||||
.btn.btn-default.prayer-item-edit-submit {
|
||||
background: #dcecf7;
|
||||
padding-left: 40px;
|
||||
padding-right: 40px;
|
||||
margin-top: 20px;
|
||||
float: left; }
|
||||
|
||||
.btn.btn-default.prayer-item-edit-cancel {
|
||||
padding-left: 40px;
|
||||
padding-right: 40px;
|
||||
margin-top: 20px;
|
||||
float: left; }
|
||||
|
||||
/* Override the default bootstrap behavior where horizontal description lists
|
||||
will truncate terms that are too long to fit in the left column
|
||||
*/
|
||||
.dl-horizontal dt {
|
||||
white-space: normal; }
|
||||
|
||||
/* Set width on the form input elements since they're 100% wide by default */
|
||||
html, body {
|
||||
height: 100%; }
|
||||
|
||||
#wrap {
|
||||
min-height: 100%;
|
||||
padding-left: 15px;
|
||||
padding-right: 15px; }
|
||||
|
||||
#main {
|
||||
overflow: auto;
|
||||
padding-bottom: 40px;
|
||||
/* this needs to be bigger than footer height*/
|
||||
max-width: 940px;
|
||||
padding-top: 91px; }
|
||||
|
||||
.prayer-item-popup-container {
|
||||
max-width: 940px;
|
||||
margin-left: auto;
|
||||
margin-right: auto; }
|
||||
|
||||
@media (min-width: 1095px) {
|
||||
#main {
|
||||
padding-top: 0px; } }
|
||||
|
||||
.prayer-instructions {
|
||||
margin-bottom: 20px;
|
||||
margin-top: 0px;
|
||||
padding: 10px; }
|
||||
|
||||
.prayer-item-edit-instructions {
|
||||
margin-bottom: 10px;
|
||||
margin-top: 20px;
|
||||
padding: 10px; }
|
||||
|
||||
.footer {
|
||||
position: relative;
|
||||
margin-top: -40px;
|
||||
/* negative value of footer height */
|
||||
height: 40px;
|
||||
clear: both;
|
||||
padding-top: 30px;
|
||||
text-align: center; }
|
||||
|
||||
.enable-animation {
|
||||
-webkit-transition: .3s ease-in-out;
|
||||
-moz-transition: .3s ease-in-out;
|
||||
-o-transition: .3s ease-in-out;
|
||||
-ms-transition: .3s ease-in-out;
|
||||
transition: .3s ease-in-out; }
|
||||
|
||||
.transparent {
|
||||
opacity: 0;
|
||||
pointer-events: none; }
|
||||
|
||||
.page-top {
|
||||
position: fixed;
|
||||
bottom: 20px;
|
||||
right: 15px;
|
||||
width: 100px;
|
||||
height: 40px;
|
||||
line-height: 40px;
|
||||
text-align: center;
|
||||
background-color: rgba(91, 131, 165, 0.7);
|
||||
color: #fff !important;
|
||||
text-decoration: none !important;
|
||||
opacity: 0.0;
|
||||
z-index: 1000;
|
||||
pointer-events: none; }
|
||||
|
||||
.full-page-shim {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
background-color: rgba(0, 0, 0, 0.5);
|
||||
z-index: 1000; }
|
||||
|
||||
.page-top.page-top-visible {
|
||||
opacity: 1.0;
|
||||
pointer-events: all; }
|
||||
|
||||
.page-top.page-top-faded {
|
||||
opacity: 0.5; }
|
||||
|
||||
.page-top.page-top-faded:hover {
|
||||
opacity: 1.0; }
|
||||
|
||||
.prayer-item {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
min-height: 80px;
|
||||
border: 1px solid #d8e2e9;
|
||||
padding: 15px;
|
||||
padding-top: 8px;
|
||||
margin-bottom: 20px;
|
||||
margin-top: 10px;
|
||||
box-shadow: 0px 4px 4px #F3F6F9;
|
||||
background: white; }
|
||||
|
||||
.prayer-item-prayed div {
|
||||
display: inline-block;
|
||||
margin: 0; }
|
||||
|
||||
.prayer-item-sort {
|
||||
display: inline-block;
|
||||
margin-top: 10px;
|
||||
float: right; }
|
||||
|
||||
|
||||
.prayer-item-name-location{
|
||||
padding-right: 5px;
|
||||
display: inline-block;
|
||||
color: #1a346b; }
|
||||
|
||||
@media (max-width: 480px) {
|
||||
|
||||
.prayer-item-name-location{
|
||||
display: block; }
|
||||
|
||||
.prayer-item-sort {
|
||||
display: none; } }
|
||||
|
||||
.prayer-item-sort .selected {
|
||||
text-decoration: none !important;
|
||||
color: #1a346b;
|
||||
font-weight: bold; }
|
||||
|
||||
.prayer-item-new-actions {
|
||||
display: inline-block;
|
||||
float: left;
|
||||
margin-bottom: 5px; }
|
||||
|
||||
.prayer-item-new-add {
|
||||
background: #d8e2e9; }
|
||||
|
||||
.prayer-item-actions {
|
||||
display: inline;
|
||||
}
|
||||
|
||||
.prayer-item-content {
|
||||
margin-bottom: 20px;
|
||||
margin-top: 5px; }
|
||||
|
||||
.prayer-item-summary {
|
||||
font-size: 18px;
|
||||
margin-top: 10px;
|
||||
font-weight: bold;
|
||||
color: #1a346b; }
|
||||
|
||||
.prayer-item-submitted {
|
||||
display: inline-block;
|
||||
color: rgba(91, 131, 165, 0.7); }
|
||||
|
||||
.prayer-item-prayed {
|
||||
float: left;
|
||||
margin-right: 2px; }
|
||||
|
||||
.prayer-item-prayed .btn.btn-default {
|
||||
padding-left: 35px;
|
||||
padding-right: 35px; }
|
||||
|
||||
.prayer-item-prayed .btn {
|
||||
padding-left: 15px;
|
||||
padding-right: 15px; }
|
||||
|
||||
.prayer-item-prayed-count {
|
||||
font-weight: bold;
|
||||
font-size: 16px;
|
||||
margin-right: 1px; }
|
||||
|
||||
.prayer-item-flag, .prayer-item-edit, .prayer-item-sendnote {
|
||||
position: absolute;
|
||||
top: 70px;
|
||||
left: 0px;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
padding: 20px;
|
||||
background-color: #fff;
|
||||
z-index: 1001; }
|
||||
|
||||
.prayer-item-edit input[type=text],
|
||||
.prayer-item-edit textarea,
|
||||
.prayer-item-flag input[type=text],
|
||||
.prayer-item-flag textarea,
|
||||
.prayer-item-sendnote input[type=text],
|
||||
.prayer-item-sendnote textarea,
|
||||
.prayer-item-edit select {
|
||||
width: 100%;
|
||||
min-width: 100%;
|
||||
margin-bottom: 20px; }
|
||||
|
||||
.prayer-item-edit-cancel,
|
||||
.prayer-item-edit-submit,
|
||||
.prayer-item-flag-cancel,
|
||||
.prayer-item-flag-submit,
|
||||
.prayer-item-sendnote-cancel,
|
||||
.prayer-item-sendnote-submit {
|
||||
float: right;
|
||||
margin-left: 5px; }
|
||||
|
||||
.prayer-item-edit .checkbox {
|
||||
font-size: 13px; }
|
||||
|
||||
.prayer-item-prayer-stats {
|
||||
color: rgba(91, 131, 165, 0.7);
|
||||
float: right;
|
||||
margin: 10px;
|
||||
top: 0px;
|
||||
right: 10px;
|
||||
position: absolute; }
|
||||
|
||||
.prayer-item-logo{
|
||||
position: absolute;
|
||||
bottom: 15px;
|
||||
right: 10px;
|
||||
}
|
||||
|
||||
.navbar-inverse {
|
||||
background-color: #ffffff;
|
||||
border-color: #d8e2e9;
|
||||
font-family: 'Open Sans', sans-serif; }
|
||||
|
||||
.navbar-inverse .navbar-toggle .icon-bar {
|
||||
background-color: #1a346b; }
|
||||
|
||||
.navbar-inverse .navbar-brand {
|
||||
color: #1a346b;
|
||||
font-size: 22px;
|
||||
margin-right: 30px;
|
||||
padding-left: 25px;
|
||||
padding-right: 25px; }
|
||||
|
||||
.navbar-inverse .navbar-toggle {
|
||||
border-color: #d8e2e9; }
|
||||
|
||||
.navbar-toggle {
|
||||
position: relative;
|
||||
float: right;
|
||||
padding: 9px 10px;
|
||||
margin-top: 18px;
|
||||
margin-bottom: 8px;
|
||||
background-color: transparent;
|
||||
border: 1px solid transparent;
|
||||
border-radius: 0px;
|
||||
margin-right: 30px; }
|
||||
|
||||
.navbar {
|
||||
max-width: 940px;
|
||||
margin-right: auto !important;
|
||||
margin-left: auto !important;
|
||||
width: 100%; }
|
||||
|
||||
.navbar-inverse .navbar-collapse, .navbar-inverse .navbar-form {
|
||||
border-color: rgba(91, 131, 165, 0.7); }
|
||||
|
||||
.navbar-inverse .navbar-toggle:hover, .navbar-inverse .navbar-toggle:focus {
|
||||
background-color: #F3F6F9; }
|
||||
|
||||
.navbar-inverse .navbar-brand:hover, .navbar-inverse .navbar-brand:focus {
|
||||
color: #1a346b;
|
||||
background-color: #d8e2e9; }
|
||||
|
||||
.navbar-inverse .navbar-nav > li > a {
|
||||
font-size: 18px;
|
||||
color: #1a346b; }
|
||||
|
||||
.navbar-nav > li > a {
|
||||
padding-top: 10px;
|
||||
padding-bottom: 10px;
|
||||
margin-bottom: 10px;
|
||||
margin-top: 15px;
|
||||
margin-right: 10px; }
|
||||
|
||||
@media (min-width: 768px) {
|
||||
.navbar-nav > li > a.selected,
|
||||
.navbar-nav > li > a:active {
|
||||
border-bottom: 2px solid #1a346b;
|
||||
margin-right: 10px; }
|
||||
.navbar-nav {
|
||||
margin-left: 40px; }
|
||||
.navbar-inverse .navbar-nav > li > a:hover, .navbar-inverse .navbar-nav > li > a:focus {
|
||||
color: #1a346b;
|
||||
background-color: #F3F6F9;
|
||||
border-bottom: 2px solid rgba(91, 131, 165, 0.7); } }
|
||||
|
||||
.navbar-inverse .navbar-nav > li > a:hover, .navbar-inverse .navbar-nav > li > a:focus {
|
||||
color: #1a346b;
|
||||
background-color: #F3F6F9; }
|
||||
|
||||
.container > .navbar-header, .container > .navbar-collapse {
|
||||
margin-left: 0px; }
|
||||
|
||||
.affiliate-logo-link {
|
||||
float: right; }
|
||||
|
||||
.affiliate-logo {
|
||||
height: 50px;
|
||||
margin: 10px; }
|
||||
|
||||
.btn {
|
||||
display: inline-block;
|
||||
margin-bottom: 0;
|
||||
text-align: center;
|
||||
white-space: nowrap;
|
||||
vertical-align: middle;
|
||||
cursor: pointer;
|
||||
border-radius: 0px;
|
||||
-webkit-user-select: none;
|
||||
-moz-user-select: none;
|
||||
-ms-user-select: none;
|
||||
-o-user-select: none;
|
||||
user-select: none;
|
||||
font-family: "Source Sans Pro", sans-serif;
|
||||
border: none;
|
||||
color: #1a346b;
|
||||
text-align: center;
|
||||
text-decoration: none;
|
||||
display: inline-block;
|
||||
font-size: 15px;
|
||||
border: 1px solid #d8e2e9;
|
||||
background: #F3F6F9; }
|
||||
|
||||
.btn:hover {
|
||||
border: 1px solid rgba(91, 131, 165, 0.7);
|
||||
background: white; }
|
||||
|
||||
.fa {
|
||||
color: #1a346b; }
|
||||
|
||||
.lefticon {
|
||||
margin-right: 10px; }
|
||||
|
||||
.actions-collapse {
|
||||
top: 0px;
|
||||
left: 0px;
|
||||
width: 100%;
|
||||
z-index: 1000;
|
||||
margin-bottom: 35px;
|
||||
clear: both; }
|
||||
|
||||
.actions-expaned-btn {
|
||||
margin-bottom: 0;
|
||||
text-align: center;
|
||||
white-space: nowrap;
|
||||
vertical-align: middle;
|
||||
cursor: pointer;
|
||||
border-radius: 0px;
|
||||
-webkit-user-select: none;
|
||||
-moz-user-select: none;
|
||||
-ms-user-select: none;
|
||||
-o-user-select: none;
|
||||
user-select: none;
|
||||
font-family: "Source Sans Pro", sans-serif;
|
||||
border: none;
|
||||
color: #1a346b;
|
||||
text-align: left;
|
||||
text-decoration: none;
|
||||
display: block;
|
||||
font-size: 15px;
|
||||
border: 1px solid #d8e2e9;
|
||||
background: #F3F6F9;
|
||||
padding-left: 20px;
|
||||
padding-top: 10px;
|
||||
padding-bottom: 10px; }
|
||||
|
||||
.actions-toggle-btn {
|
||||
background: transparent;
|
||||
border: 1px solid transparent; }
|
||||
|
||||
.back-nav-link {
|
||||
font-size: 16px; }
|
||||
|
||||
.backnav {
|
||||
margin-right: 6px; }
|
||||
|
||||
.prayer-item-submitted.detail {
|
||||
margin-top: 20px; }
|
||||
|
||||
.form-horizontal .form-group, .row {
|
||||
margin-left: 0 !important;
|
||||
margin-right: 0 !important; }
|
||||
|
||||
.form-control {
|
||||
border-radius: 4px; }
|
||||
|
||||
label {
|
||||
display: inline-block;
|
||||
margin-bottom: 5px;
|
||||
font-weight: bold;
|
||||
color: #1a346b; }
|
||||
|
||||
.copyright {
|
||||
color: rgba(91, 131, 165, 0.7); }
|
||||
|
||||
@media (min-width: 768px) {
|
||||
.container {
|
||||
max-width: none; } }
|
||||
|
||||
@media (min-width: 992px) {
|
||||
.container {
|
||||
max-width: none; } }
|
||||
|
||||
.affiliate-select {
|
||||
list-style-type: none;
|
||||
margin: 0px;
|
||||
padding: 0px; }
|
||||
|
||||
.affiliate-select li {
|
||||
margin: 5px; }
|
||||
|
||||
.affiliate-select li a {
|
||||
width: 100%;
|
||||
clear: both;
|
||||
float: left;
|
||||
border: 1px solid #d8e2e9; }
|
||||
|
||||
.affiliate-select li a:hover {
|
||||
background: #F3F6F9;
|
||||
border: 1px solid #1a346b;
|
||||
text-decoration: none; }
|
||||
|
||||
.select-header {
|
||||
color: #1a346b; }
|
||||
|
||||
.moretoggle::after {
|
||||
content: "more";
|
||||
margin-left: 6px;
|
||||
margin-right: 6px;
|
||||
font-family: "Source Sans Pro", sans-serif; }
|
||||
|
||||
.lesstoggle::after {
|
||||
content: "less";
|
||||
margin-left: 6px;
|
||||
margin-right: 6px;
|
||||
font-family: "Source Sans Pro", sans-serif; }
|
||||
|
||||
.moretoggle::before {
|
||||
content: "\f107";
|
||||
margin-left: 6px;
|
||||
display: inline-block;
|
||||
font: normal normal normal 14px/1 FontAwesome;
|
||||
font-size: inherit;
|
||||
text-rendering: auto;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale; }
|
||||
|
||||
.lesstoggle::before {
|
||||
content: "\f106";
|
||||
margin-left: 6px;
|
||||
display: inline-block;
|
||||
font: normal normal normal 14px/1 FontAwesome;
|
||||
font-size: inherit;
|
||||
text-rendering: auto;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale; }
|
||||
|
||||
@media all and (orientation: landscape) {
|
||||
.navbar-fixed-top, .navbar-fixed-bottom {
|
||||
position: relative; }
|
||||
#main {
|
||||
padding-top: 0px; } }
|
||||
|
||||
.full-page-shim {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
background-color: white;
|
||||
z-index: 1000; }
|
||||
|
||||
.radio label, .checkbox label {
|
||||
display: inline;
|
||||
margin-bottom: 5px;
|
||||
font-weight: normal;
|
||||
cursor: pointer; }
|
||||
|
||||
.fixedContainer {
|
||||
position: fixed; }
|
||||
|
||||
.relativeContainer {
|
||||
position: relative; }
|
||||
|
||||
.dl-horizontal dt, .dl-horizontal dd {
|
||||
text-align: left;
|
||||
margin-bottom: 20px;
|
||||
border-top: 1px solid rgba(91, 131, 165, 0.3);
|
||||
padding: 10px; }
|
||||
|
||||
.dl-horizontal dd {
|
||||
background: #F3F6F9;
|
||||
box-shadow: inset 0px 0px 5px rgba(91, 131, 165, 0.3);
|
||||
color: rgba(91, 131, 165, 0.7); }
|
||||
|
||||
@media (min-width: 768px) {
|
||||
.form-horizontal .control-label {
|
||||
text-align: left; } }
|
||||
|
||||
.form-control {
|
||||
border-radius: 0px;
|
||||
margin-top: 10px; }
|
||||
|
||||
.form-group {
|
||||
margin-bottom: 25px;
|
||||
border-top: 1px solid #e4e4e4; }
|
||||
|
||||
.text-right {
|
||||
text-align: right;
|
||||
margin-bottom: 20px;
|
||||
margin-top: 15px; }
|
||||
|
||||
.in-iframe #main {
|
||||
padding-top: 0px; }
|
||||
|
||||
.in-iframe .navbar {
|
||||
display: none; }
|
||||
|
||||
.poweredbycontainer {
|
||||
width: 100%;
|
||||
text-align: center; }
|
||||
|
||||
.poweredby {
|
||||
margin-top: 40px;
|
||||
margin-right: auto;
|
||||
margin-left: auto; }
|
724
Amen/Content/Site.scss
Normal file
@ -0,0 +1,724 @@
|
||||
$LargeScreenSiteWidth: 940px;
|
||||
$SiteFontFamily: 'Source Sans Pro', sans-serif;
|
||||
|
||||
|
||||
$SiteLightColor: #F3F6F9;
|
||||
$SiteMediumShadowColor: rgba(91, 131, 165, 0.3);
|
||||
$SiteMediumColor: rgba(91, 131, 165, 0.7);
|
||||
$SiteDarkColor: #1a346b;
|
||||
$SiteForeground: #ffffff;
|
||||
$SiteForegroundHover: #DCEDF1;
|
||||
$SiteBorder: #d8e2e9;
|
||||
$SiteButtonHilight: #dcecf7;
|
||||
|
||||
/*
|
||||
$SiteLightColor: #FDEFEF;
|
||||
$SiteMediumColor: rgba(172, 25, 25, 0.5);
|
||||
$SiteDarkColor: #741111;
|
||||
$SiteForeground: #ffffff;
|
||||
$SiteForegroundHover: #F9D4D4;
|
||||
$SiteBorder: #F7CACA;
|
||||
$SiteButtonHilight: #F9D9D9;
|
||||
|
||||
*/
|
||||
|
||||
|
||||
body {
|
||||
padding-top: 0px;
|
||||
padding-bottom: 20px;
|
||||
font-family: $SiteFontFamily;
|
||||
font-size:15px;
|
||||
}
|
||||
.container {
|
||||
padding-right: 0px;
|
||||
padding-left: 0px;
|
||||
margin-right: auto;
|
||||
margin-left: auto;
|
||||
|
||||
}
|
||||
|
||||
h2 {
|
||||
color: $SiteDarkColor;
|
||||
font-weight: 200;
|
||||
}
|
||||
|
||||
a {
|
||||
color: $SiteDarkColor;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
|
||||
/* Set padding to keep content from hitting the edges */
|
||||
.body-content {
|
||||
padding-left: 15px;
|
||||
padding-right: 15px;
|
||||
}
|
||||
|
||||
.btn.btn-default.prayer-item-edit-submit
|
||||
{
|
||||
background: $SiteButtonHilight;
|
||||
padding-left:40px;
|
||||
padding-right:40px;
|
||||
margin-top:20px;
|
||||
float:left;
|
||||
}
|
||||
.btn.btn-default.prayer-item-edit-cancel
|
||||
{
|
||||
padding-left:40px;
|
||||
padding-right:40px;
|
||||
margin-top:20px;
|
||||
float:left;
|
||||
}
|
||||
|
||||
/* Override the default bootstrap behavior where horizontal description lists
|
||||
will truncate terms that are too long to fit in the left column
|
||||
*/
|
||||
.dl-horizontal dt {
|
||||
white-space: normal;
|
||||
}
|
||||
|
||||
/* Set width on the form input elements since they're 100% wide by default */
|
||||
input,
|
||||
select,
|
||||
textarea {
|
||||
|
||||
}
|
||||
|
||||
html, body {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
#wrap {
|
||||
min-height: 100%;
|
||||
padding-left: 15px;
|
||||
padding-right: 15px;
|
||||
|
||||
}
|
||||
|
||||
#main {
|
||||
overflow: auto;
|
||||
padding-bottom: 40px; /* this needs to be bigger than footer height*/
|
||||
max-width: $LargeScreenSiteWidth;
|
||||
padding-top: 91px;
|
||||
}
|
||||
.prayer-item-popup-container {
|
||||
max-width: $LargeScreenSiteWidth;
|
||||
margin-left:auto;
|
||||
margin-right:auto;
|
||||
}
|
||||
|
||||
@media (min-width: 1095px){
|
||||
#main {
|
||||
padding-top: 0px;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
.prayer-instructions {
|
||||
margin-bottom: 20px;
|
||||
margin-top: 0px;
|
||||
padding: 10px;
|
||||
|
||||
}
|
||||
|
||||
.prayer-item-edit-instructions {
|
||||
margin-bottom: 10px;
|
||||
margin-top: 20px;
|
||||
padding: 10px;
|
||||
|
||||
}
|
||||
|
||||
.footer {
|
||||
position: relative;
|
||||
margin-top: -40px; /* negative value of footer height */
|
||||
height: 40px;
|
||||
clear: both;
|
||||
padding-top: 30px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.enable-animation {
|
||||
-webkit-transition: .3s ease-in-out;
|
||||
-moz-transition: .3s ease-in-out;
|
||||
-o-transition: .3s ease-in-out;
|
||||
-ms-transition: .3s ease-in-out;
|
||||
transition: .3s ease-in-out;
|
||||
}
|
||||
|
||||
.transparent{
|
||||
opacity: 0;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.page-top {
|
||||
position: fixed;
|
||||
bottom: 20px;
|
||||
right: 15px;
|
||||
width: 100px;
|
||||
height: 40px;
|
||||
line-height: 40px;
|
||||
text-align: center;
|
||||
background-color: $SiteMediumColor;
|
||||
color: #fff !important;
|
||||
text-decoration: none !important;
|
||||
opacity: 0.0;
|
||||
z-index: 1000;
|
||||
pointer-events: none;
|
||||
}
|
||||
.full-page-shim{
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
background-color: rgba(0,0,0,0.5);
|
||||
z-index: 1000;
|
||||
}
|
||||
|
||||
.page-top.page-top-visible {
|
||||
opacity: 1.0;
|
||||
pointer-events: all;
|
||||
}
|
||||
|
||||
.page-top.page-top-faded {
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
.page-top.page-top-faded:hover {
|
||||
opacity: 1.0;
|
||||
}
|
||||
|
||||
.prayer-item {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
min-height: 80px;
|
||||
border: 1px solid $SiteBorder;
|
||||
padding: 15px;
|
||||
padding-top:8px;
|
||||
margin-bottom: 20px;
|
||||
margin-top: 10px;
|
||||
box-shadow: 0px 4px 4px $SiteLightColor;
|
||||
background: white;
|
||||
}
|
||||
|
||||
.prayer-item-prayed div {
|
||||
display: inline-block;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.prayer-item-sort{
|
||||
display: inline-block;
|
||||
margin-top: 10px;
|
||||
float:right;
|
||||
}
|
||||
|
||||
.prayer-item-name-location{
|
||||
padding-right: 5px;
|
||||
display: inline-block;
|
||||
color: $SiteDarkColor;
|
||||
}
|
||||
|
||||
@media (max-width: 480px) {
|
||||
.prayer-item-name-location{
|
||||
display: block;
|
||||
}
|
||||
|
||||
.prayer-item-sort {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
.prayer-item-sort .selected {
|
||||
text-decoration: none !important;
|
||||
color: $SiteDarkColor;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.prayer-item-new-actions{
|
||||
display: inline-block;
|
||||
float: left;
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
|
||||
.prayer-item-new-add{
|
||||
background: $SiteBorder;
|
||||
}
|
||||
|
||||
.prayer-item-actions {
|
||||
display:inline;
|
||||
}
|
||||
|
||||
.prayer-item-content {
|
||||
margin-bottom:20px;
|
||||
margin-top:5px;
|
||||
}
|
||||
|
||||
.prayer-item-summary {
|
||||
font-size: 18px;
|
||||
margin-top:10px;
|
||||
font-weight: bold;
|
||||
color: $SiteDarkColor;
|
||||
}
|
||||
|
||||
.prayer-item-submitted {
|
||||
|
||||
display: inline-block;
|
||||
color: $SiteMediumColor;
|
||||
|
||||
}
|
||||
|
||||
.prayer-item-prayed {
|
||||
float:left;
|
||||
margin-right:2px;
|
||||
}
|
||||
|
||||
.prayer-item-prayed .btn.btn-default {
|
||||
padding-left:35px;
|
||||
padding-right:35px;
|
||||
}
|
||||
.prayer-item-prayed .btn{
|
||||
padding-left:15px;
|
||||
padding-right:15px;
|
||||
}
|
||||
.prayer-item-prayed-count{
|
||||
font-weight: bold;
|
||||
font-size: 16px;
|
||||
margin-right: 1px;
|
||||
|
||||
}
|
||||
|
||||
|
||||
.prayer-item-flag, .prayer-item-edit, .prayer-item-sendnote {
|
||||
position: absolute;
|
||||
top: 70px;
|
||||
left: 0px;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
padding: 20px;
|
||||
background-color: #fff;
|
||||
z-index: 1001;
|
||||
}
|
||||
|
||||
.prayer-item-edit input[type=text],
|
||||
.prayer-item-edit textarea,
|
||||
.prayer-item-flag input[type=text],
|
||||
.prayer-item-flag textarea,
|
||||
.prayer-item-sendnote input[type=text],
|
||||
.prayer-item-sendnote textarea,
|
||||
.prayer-item-edit select
|
||||
{
|
||||
width: 100%;
|
||||
min-width: 100%;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.prayer-item-edit-cancel,
|
||||
.prayer-item-edit-submit,
|
||||
|
||||
.prayer-item-flag-cancel,
|
||||
.prayer-item-flag-submit,
|
||||
|
||||
.prayer-item-sendnote-cancel,
|
||||
.prayer-item-sendnote-submit{
|
||||
float: right;
|
||||
margin-left: 5px;
|
||||
}
|
||||
|
||||
|
||||
.prayer-item-edit .checkbox{
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
.prayer-item-prayer-stats{
|
||||
color:$SiteMediumColor;
|
||||
float: right;
|
||||
margin: 10px;
|
||||
top: 0px;
|
||||
right: 10px;
|
||||
position: absolute;
|
||||
}
|
||||
|
||||
.prayer-item-logo{
|
||||
position: absolute;
|
||||
bottom: 15px;
|
||||
right: 10px;
|
||||
}
|
||||
|
||||
.navbar-inverse {
|
||||
background-color: $SiteForeground;
|
||||
border-color: $SiteBorder;
|
||||
font-family: 'Open Sans', sans-serif;
|
||||
}
|
||||
|
||||
.navbar-inverse .navbar-toggle .icon-bar {
|
||||
background-color: $SiteDarkColor;
|
||||
}
|
||||
|
||||
.navbar-inverse .navbar-brand {
|
||||
color:$SiteDarkColor;
|
||||
font-size:22px;
|
||||
margin-right:30px;
|
||||
padding-left:25px;
|
||||
padding-right: 25px;
|
||||
}
|
||||
|
||||
.navbar-inverse .navbar-toggle {
|
||||
border-color: $SiteBorder;
|
||||
}
|
||||
|
||||
.navbar-toggle {
|
||||
position: relative;
|
||||
float: right;
|
||||
padding: 9px 10px;
|
||||
margin-top: 18px;
|
||||
margin-bottom: 8px;
|
||||
background-color: transparent;
|
||||
border: 1px solid transparent;
|
||||
border-radius: 0px;
|
||||
margin-right:30px;
|
||||
}
|
||||
|
||||
.navbar {
|
||||
max-width: $LargeScreenSiteWidth;
|
||||
margin-right: auto !important;
|
||||
margin-left: auto !important;
|
||||
width: 100%;
|
||||
|
||||
}
|
||||
|
||||
.navbar-inverse .navbar-collapse, .navbar-inverse .navbar-form {
|
||||
border-color: $SiteMediumColor;
|
||||
}
|
||||
|
||||
|
||||
.navbar-inverse .navbar-toggle:hover, .navbar-inverse .navbar-toggle:focus {
|
||||
background-color: $SiteLightColor;
|
||||
}
|
||||
|
||||
.navbar-inverse .navbar-brand:hover, .navbar-inverse .navbar-brand:focus {
|
||||
color:$SiteDarkColor;
|
||||
background-color: $SiteBorder;
|
||||
}
|
||||
|
||||
.navbar-inverse .navbar-nav > li > a {
|
||||
font-size:18px;
|
||||
color:$SiteDarkColor;
|
||||
}
|
||||
|
||||
.navbar-nav > li > a {
|
||||
padding-top: 10px;
|
||||
padding-bottom: 10px;
|
||||
margin-bottom:10px;
|
||||
margin-top:15px;
|
||||
margin-right: 10px;
|
||||
|
||||
}
|
||||
@media (min-width: 768px){
|
||||
.navbar-nav > li > a.selected,
|
||||
.navbar-nav > li > a:active {
|
||||
border-bottom: 2px solid $SiteDarkColor;
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
.navbar-nav {
|
||||
margin-left:40px;
|
||||
}
|
||||
|
||||
|
||||
.navbar-inverse .navbar-nav > li > a:hover, .navbar-inverse .navbar-nav > li > a:focus {
|
||||
color:$SiteDarkColor;
|
||||
background-color: $SiteLightColor;
|
||||
border-bottom: 2px solid $SiteMediumColor;
|
||||
}
|
||||
}
|
||||
.navbar-inverse .navbar-nav > li > a:hover, .navbar-inverse .navbar-nav > li > a:focus {
|
||||
color:$SiteDarkColor;
|
||||
background-color: $SiteLightColor;
|
||||
}
|
||||
|
||||
.container > .navbar-header, .container > .navbar-collapse {
|
||||
margin-left: 0px;
|
||||
}
|
||||
|
||||
|
||||
.affiliate-logo-link{
|
||||
float:right;
|
||||
}
|
||||
|
||||
.affiliate-logo{
|
||||
height:50px;
|
||||
margin:10px;
|
||||
}
|
||||
|
||||
.btn {
|
||||
display: inline-block;
|
||||
margin-bottom: 0;
|
||||
text-align: center;
|
||||
white-space: nowrap;
|
||||
vertical-align: middle;
|
||||
cursor: pointer;
|
||||
border-radius: 0px;
|
||||
-webkit-user-select: none;
|
||||
-moz-user-select: none;
|
||||
-ms-user-select: none;
|
||||
-o-user-select: none;
|
||||
user-select: none;
|
||||
font-family: $SiteFontFamily;
|
||||
border: none;
|
||||
color: $SiteDarkColor;
|
||||
text-align: center;
|
||||
text-decoration: none;
|
||||
display: inline-block;
|
||||
font-size: 15px;
|
||||
border: 1px solid $SiteBorder;
|
||||
background: $SiteLightColor;
|
||||
}
|
||||
.btn:hover {
|
||||
border:1px solid $SiteMediumColor;
|
||||
background: white;
|
||||
}
|
||||
|
||||
.fa {
|
||||
color: $SiteDarkColor;
|
||||
}
|
||||
|
||||
.lefticon {
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
.actions-collapse
|
||||
{
|
||||
top: 0px;
|
||||
left:0px;
|
||||
width: 100%;
|
||||
z-index: 1000;
|
||||
margin-bottom: 35px;
|
||||
clear:both;
|
||||
}
|
||||
|
||||
.actions-expaned-btn
|
||||
{
|
||||
margin-bottom: 0;
|
||||
text-align: center;
|
||||
white-space: nowrap;
|
||||
vertical-align: middle;
|
||||
cursor: pointer;
|
||||
border-radius: 0px;
|
||||
-webkit-user-select: none;
|
||||
-moz-user-select: none;
|
||||
-ms-user-select: none;
|
||||
-o-user-select: none;
|
||||
user-select: none;
|
||||
font-family: $SiteFontFamily;
|
||||
border: none;
|
||||
color: $SiteDarkColor;
|
||||
text-align: left;
|
||||
text-decoration: none;
|
||||
display: block;
|
||||
font-size: 15px;
|
||||
border: 1px solid $SiteBorder;
|
||||
background: $SiteLightColor;
|
||||
padding-left: 20px;
|
||||
padding-top:10px;
|
||||
padding-bottom:10px;
|
||||
}
|
||||
.actions-toggle-btn {
|
||||
background: transparent;
|
||||
border: 1px solid transparent;
|
||||
}
|
||||
|
||||
.back-nav-link
|
||||
{
|
||||
font-size:16px;
|
||||
}
|
||||
.backnav
|
||||
{
|
||||
margin-right:6px;
|
||||
}
|
||||
|
||||
.prayer-item-submitted.detail
|
||||
{
|
||||
margin-top:20px;
|
||||
}
|
||||
|
||||
.form-horizontal .form-group, .row{
|
||||
margin-left: 0 !important;
|
||||
margin-right: 0 !important;
|
||||
}
|
||||
|
||||
.form-control {
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
label {
|
||||
display: inline-block;
|
||||
margin-bottom: 5px;
|
||||
font-weight: bold;
|
||||
color: $SiteDarkColor;
|
||||
}
|
||||
|
||||
.copyright
|
||||
{
|
||||
color:$SiteMediumColor;
|
||||
}
|
||||
|
||||
|
||||
@media (min-width: 768px){
|
||||
.container {
|
||||
max-width: none;
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: 992px){
|
||||
.container {
|
||||
max-width: none;
|
||||
}
|
||||
|
||||
}
|
||||
.affiliate-select{
|
||||
list-style-type: none;
|
||||
margin:0px;
|
||||
padding:0px;
|
||||
}
|
||||
.affiliate-select li{
|
||||
margin: 5px;
|
||||
}
|
||||
.affiliate-select li a{
|
||||
width: 100%;
|
||||
clear:both;
|
||||
float:left;
|
||||
border: 1px solid $SiteBorder;
|
||||
}
|
||||
.affiliate-select li a:hover{
|
||||
background: $SiteLightColor;
|
||||
border: 1px solid $SiteDarkColor;
|
||||
text-decoration: none;
|
||||
|
||||
}
|
||||
.select-header{
|
||||
color: $SiteDarkColor;
|
||||
}
|
||||
|
||||
.moretoggle::after {
|
||||
content: "more";
|
||||
margin-left:6px;
|
||||
margin-right:6px;
|
||||
font-family: $SiteFontFamily;
|
||||
}
|
||||
.lesstoggle::after {
|
||||
content: "less";
|
||||
margin-left:6px;
|
||||
margin-right:6px;
|
||||
font-family: $SiteFontFamily;
|
||||
}
|
||||
|
||||
.moretoggle::before {
|
||||
content: "\f107";
|
||||
margin-left:6px;
|
||||
display: inline-block;
|
||||
font: normal normal normal 14px/1 FontAwesome;
|
||||
font-size: inherit;
|
||||
text-rendering: auto;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
}
|
||||
.lesstoggle::before {
|
||||
content: "\f106";
|
||||
margin-left:6px;
|
||||
display: inline-block;
|
||||
font: normal normal normal 14px/1 FontAwesome;
|
||||
font-size: inherit;
|
||||
text-rendering: auto;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
}
|
||||
|
||||
|
||||
@media all and (orientation:landscape) {
|
||||
.navbar-fixed-top, .navbar-fixed-bottom {
|
||||
position: relative;
|
||||
}
|
||||
#main {
|
||||
padding-top: 0px;
|
||||
}
|
||||
}
|
||||
|
||||
.full-page-shim {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
background-color:white;
|
||||
z-index: 1000;
|
||||
}
|
||||
|
||||
.radio label, .checkbox label {
|
||||
display: inline;
|
||||
margin-bottom: 5px;
|
||||
font-weight: normal;
|
||||
cursor: pointer;
|
||||
}
|
||||
.fixedContainer{
|
||||
position:fixed;
|
||||
}
|
||||
.relativeContainer{
|
||||
position: relative;
|
||||
}
|
||||
.dl-horizontal dt, .dl-horizontal dd, {
|
||||
text-align: left;
|
||||
margin-bottom: 20px;
|
||||
border-top: 1px solid $SiteMediumShadowColor;
|
||||
padding:10px;
|
||||
|
||||
|
||||
}
|
||||
.dl-horizontal dd {
|
||||
background: $SiteLightColor;
|
||||
box-shadow: inset 0px 0px 5px $SiteMediumShadowColor;
|
||||
color: $SiteMediumColor;
|
||||
}
|
||||
|
||||
@media (min-width: 768px){
|
||||
.form-horizontal .control-label {
|
||||
text-align: left;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
.form-control {
|
||||
border-radius: 0px;
|
||||
margin-top:10px;
|
||||
}
|
||||
.form-group {
|
||||
margin-bottom: 25px;
|
||||
border-top: 1px solid #e4e4e4;
|
||||
|
||||
|
||||
}
|
||||
.text-right {
|
||||
text-align: right;
|
||||
margin-bottom: 20px;
|
||||
margin-top: 15px;
|
||||
}
|
||||
|
||||
.in-iframe #main {
|
||||
padding-top:0px;
|
||||
}
|
||||
|
||||
.in-iframe .navbar {
|
||||
display:none;
|
||||
}
|
||||
|
||||
.poweredbycontainer
|
||||
{
|
||||
width:100%;
|
||||
text-align: center;
|
||||
}
|
||||
.poweredby
|
||||
{
|
||||
margin-top: 40px;
|
||||
margin-right: auto;
|
||||
margin-left:auto;
|
||||
}
|
187
Amen/Content/SiteCustom.css
Normal file
@ -0,0 +1,187 @@
|
||||
|
||||
|
||||
|
||||
/* background behind prayers */
|
||||
body
|
||||
{
|
||||
background: rgba(255, 0, 0, 0.05);
|
||||
}
|
||||
|
||||
/* all hyperlinks */
|
||||
a
|
||||
{
|
||||
color: red;
|
||||
}
|
||||
|
||||
/* all hyperlinks hover state */
|
||||
a:hover
|
||||
{
|
||||
color: red;
|
||||
}
|
||||
|
||||
/* box arond each prayer item */
|
||||
.prayer-item
|
||||
{
|
||||
border: 1px solid rgba(255, 0, 0, 0.2);
|
||||
box-shadow: 0px 4px 4px rgba(255, 0, 0, 0.05);
|
||||
background: white;
|
||||
}
|
||||
|
||||
/* title of each prayer */
|
||||
.prayer-title {
|
||||
color: red;
|
||||
}
|
||||
|
||||
/* title of each prayer */
|
||||
.prayer-title:hover {
|
||||
color: red;
|
||||
}
|
||||
|
||||
/* date of each prayer */
|
||||
.prayer-item-submitted
|
||||
{
|
||||
color:red;
|
||||
}
|
||||
|
||||
/* number of prayers of each prayer */
|
||||
.prayer-item-prayer-stats
|
||||
{
|
||||
color:red;
|
||||
}
|
||||
|
||||
/* action buttons on each prayer*/
|
||||
.btn
|
||||
{
|
||||
color: red;
|
||||
border: 1px solid rgba(255, 0, 0, 0.3);
|
||||
background: rgba(255, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
/* action buttons hover state on each prayer*/
|
||||
.btn:hover
|
||||
{
|
||||
color: red;
|
||||
border: 1px solid rgba(255, 0, 0, 0.7);
|
||||
background: white;
|
||||
}
|
||||
|
||||
/* icons */
|
||||
.fa
|
||||
{
|
||||
color:red;
|
||||
}
|
||||
|
||||
/* ************* */
|
||||
/* site elements */
|
||||
/* ************* */
|
||||
|
||||
/* message at the top of the prayers list */
|
||||
.prayer-instructions {
|
||||
margin-bottom: 20px;
|
||||
margin-top: 0px;
|
||||
padding: 10px;
|
||||
box-shadow: 0px 4px 4px rgba(255, 0, 0, 0.05);
|
||||
background-color: rgba(177, 183, 249, 0.12);
|
||||
border: solid 1px #6666cc;
|
||||
}
|
||||
|
||||
|
||||
/* message above button on submit a prayer page*/
|
||||
.prayer-item-edit-instructions {
|
||||
margin-bottom: 10px;
|
||||
margin-top: 20px;
|
||||
padding: 10px;
|
||||
box-shadow: 0px 4px 4px rgba(255, 0, 0, 0.05);
|
||||
background-color: rgba(177, 183, 249, 0.12);
|
||||
border: solid 1px #6666cc;
|
||||
}
|
||||
|
||||
/* sort UI at top of prayers selected state */
|
||||
.prayer-item-sort .selected
|
||||
{
|
||||
color: red;
|
||||
}
|
||||
|
||||
/* draws the bottom border on the navbar in full width */
|
||||
.navbar
|
||||
{
|
||||
border-bottom: 1px solid red;
|
||||
}
|
||||
|
||||
/* nav bar menu item */
|
||||
.navbar-inverse .navbar-nav > li > a {
|
||||
color: red;
|
||||
}
|
||||
|
||||
/* nav bar menu item hover state */
|
||||
.navbar-inverse .navbar-nav > li > a:hover {
|
||||
background: rgba(255, 0, 0, 0.1);
|
||||
color: red;
|
||||
}
|
||||
|
||||
/* button at bottom that navigates back to top*/
|
||||
.page-top
|
||||
{
|
||||
background: rgba(255, 0, 0, 0.7);
|
||||
}
|
||||
|
||||
/* copyright at bottom of page */
|
||||
.copyright
|
||||
{
|
||||
color:red;
|
||||
}
|
||||
|
||||
/* collapsed navbar border color */
|
||||
.navbar-inverse .navbar-collapse, .navbar-inverse .navbar-form {
|
||||
border-color: red;
|
||||
}
|
||||
|
||||
/* toggle button at top of page */
|
||||
.navbar-toggle.collapsed
|
||||
{
|
||||
color: red;
|
||||
border: 1px solid rgba(255, 0, 0, 0.3);
|
||||
background: rgba(255, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
.navbar-toggle.collapsed:hover
|
||||
{
|
||||
color: red;
|
||||
border: 1px solid rgba(255, 0, 0, 0.3);
|
||||
background: rgba(255, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
.navbar-toggle
|
||||
{
|
||||
color: red;
|
||||
border: 1px solid rgba(255, 0, 0, 0.3);
|
||||
background: rgba(255, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
.navbar-inverse .navbar-toggle:hover, .navbar-inverse .navbar-toggle:focus
|
||||
{
|
||||
background-color: rgba(255, 0, 0, 0.1);
|
||||
border: 1px solid rgba(255, 0, 0, 0.7);
|
||||
}
|
||||
|
||||
.navbar-inverse .navbar-toggle .icon-bar
|
||||
{
|
||||
background-color: red;
|
||||
}
|
||||
|
||||
.navbar-nav > li > a.selected, .navbar-nav > li > a:active
|
||||
{
|
||||
border-bottom: 2px solid red;
|
||||
}
|
||||
|
||||
.navbar-nav > li > a.selected, .navbar-nav > li > a:hover
|
||||
{
|
||||
border-bottom: 2px solid red;
|
||||
}
|
||||
|
||||
.navbar-inverse .navbar-nav > li > a:hover, .navbar-inverse .navbar-nav > li > a:focus
|
||||
{
|
||||
border-bottom: 2px solid red;
|
||||
}
|
||||
|
||||
|
54
Amen/Content/bootstrap-tagsinput-typeahead.css
vendored
Normal file
@ -0,0 +1,54 @@
|
||||
/*
|
||||
* bootstrap-tagsinput v0.8.0
|
||||
*
|
||||
*/
|
||||
|
||||
.twitter-typeahead .tt-query,
|
||||
.twitter-typeahead .tt-hint {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.twitter-typeahead .tt-hint
|
||||
{
|
||||
display: none;
|
||||
}
|
||||
|
||||
.tt-menu {
|
||||
position: absolute;
|
||||
top: 100%;
|
||||
left: 0;
|
||||
z-index: 1000;
|
||||
display: none;
|
||||
float: left;
|
||||
min-width: 160px;
|
||||
padding: 5px 0;
|
||||
margin: 2px 0 0;
|
||||
list-style: none;
|
||||
font-size: 14px;
|
||||
background-color: #ffffff;
|
||||
border: 1px solid #cccccc;
|
||||
border: 1px solid rgba(0, 0, 0, 0.15);
|
||||
border-radius: 4px;
|
||||
-webkit-box-shadow: 0 6px 12px rgba(0, 0, 0, 0.175);
|
||||
box-shadow: 0 6px 12px rgba(0, 0, 0, 0.175);
|
||||
background-clip: padding-box;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.tt-suggestion {
|
||||
display: block;
|
||||
padding: 3px 20px;
|
||||
clear: both;
|
||||
font-weight: normal;
|
||||
line-height: 1.428571429;
|
||||
color: #333333;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.tt-suggestion:hover,
|
||||
.tt-suggestion:focus {
|
||||
color: #ffffff;
|
||||
text-decoration: none;
|
||||
outline: 0;
|
||||
background-color: #428bca;
|
||||
}
|
60
Amen/Content/bootstrap-tagsinput.css
vendored
Normal file
@ -0,0 +1,60 @@
|
||||
/*
|
||||
* bootstrap-tagsinput v0.8.0
|
||||
*
|
||||
*/
|
||||
|
||||
.bootstrap-tagsinput {
|
||||
background-color: #fff;
|
||||
border: 1px solid #ccc;
|
||||
box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);
|
||||
display: inline-block;
|
||||
padding: 4px 6px;
|
||||
color: #555;
|
||||
vertical-align: middle;
|
||||
border-radius: 4px;
|
||||
max-width: 100%;
|
||||
line-height: 22px;
|
||||
cursor: text;
|
||||
}
|
||||
.bootstrap-tagsinput input {
|
||||
border: none;
|
||||
box-shadow: none;
|
||||
outline: none;
|
||||
background-color: transparent;
|
||||
padding: 0 6px;
|
||||
margin: 0;
|
||||
width: auto;
|
||||
max-width: inherit;
|
||||
}
|
||||
.bootstrap-tagsinput.form-control input::-moz-placeholder {
|
||||
color: #777;
|
||||
opacity: 1;
|
||||
}
|
||||
.bootstrap-tagsinput.form-control input:-ms-input-placeholder {
|
||||
color: #777;
|
||||
}
|
||||
.bootstrap-tagsinput.form-control input::-webkit-input-placeholder {
|
||||
color: #777;
|
||||
}
|
||||
.bootstrap-tagsinput input:focus {
|
||||
border: none;
|
||||
box-shadow: none;
|
||||
}
|
||||
.bootstrap-tagsinput .tag {
|
||||
margin-right: 2px;
|
||||
color: white;
|
||||
}
|
||||
.bootstrap-tagsinput .tag [data-role="remove"] {
|
||||
margin-left: 8px;
|
||||
cursor: pointer;
|
||||
}
|
||||
.bootstrap-tagsinput .tag [data-role="remove"]:after {
|
||||
content: "x";
|
||||
padding: 0px 2px;
|
||||
}
|
||||
.bootstrap-tagsinput .tag [data-role="remove"]:hover {
|
||||
box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05);
|
||||
}
|
||||
.bootstrap-tagsinput .tag [data-role="remove"]:hover:active {
|
||||
box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);
|
||||
}
|
50
Amen/Content/bootstrap-tagsinput.less
vendored
Normal file
@ -0,0 +1,50 @@
|
||||
.bootstrap-tagsinput {
|
||||
background-color: #fff;
|
||||
border: 1px solid #ccc;
|
||||
box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);
|
||||
display: inline-block;
|
||||
padding: 4px 6px;
|
||||
margin-bottom: 10px;
|
||||
color: #555;
|
||||
vertical-align: middle;
|
||||
border-radius: 4px;
|
||||
max-width: 100%;
|
||||
line-height: 22px;
|
||||
cursor: text;
|
||||
|
||||
input {
|
||||
border: none;
|
||||
box-shadow: none;
|
||||
outline: none;
|
||||
background-color: transparent;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
width: auto !important;
|
||||
max-width: inherit;
|
||||
|
||||
&:focus {
|
||||
border: none;
|
||||
box-shadow: none;
|
||||
}
|
||||
}
|
||||
|
||||
.tag {
|
||||
margin-right: 2px;
|
||||
color: white;
|
||||
|
||||
[data-role="remove"] {
|
||||
margin-left:8px;
|
||||
cursor:pointer;
|
||||
&:after{
|
||||
content: "x";
|
||||
padding:0px 2px;
|
||||
}
|
||||
&:hover {
|
||||
box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05);
|
||||
&:active {
|
||||
box-shadow: inset 0 3px 5px rgba(0,0,0,0.125);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
6816
Amen/Content/bootstrap.css
vendored
Normal file
20
Amen/Content/bootstrap.min.css
vendored
Normal file
139
Amen/Controllers/APIController.cs
Normal file
@ -0,0 +1,139 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Web.Mvc;
|
||||
|
||||
namespace Amen.Controllers
|
||||
{
|
||||
public class APIController : BaseController
|
||||
{
|
||||
/* Previous totals before initial reset
|
||||
229,412 prayers prayed before reset and 5,762,657 prayers by KTIS affiliates before migration
|
||||
13,082 prayer requests before reset and 364,224 requests by KTIS affiliates before migration
|
||||
6,211 notes sent before reset and 72,923 notes by KTIS affiliates before migration
|
||||
*/
|
||||
public const int CONST_PreviousPrayedCount = 229412 + 5762657;
|
||||
public const int CONST_PreviousPrayerCount = 13082 + 364224;
|
||||
public const int CONST_PreviousNotesSent = 6211 + 72923;
|
||||
|
||||
// GET: API/Index
|
||||
public JsonResult Index()
|
||||
{
|
||||
return Json("", JsonRequestBehavior.AllowGet);
|
||||
}
|
||||
|
||||
public JsonResult PraiseCount(string affiliatekey, string includeAll = "false")
|
||||
{
|
||||
return PrayerCount(affiliatekey, includeAll, bool.TrueString);
|
||||
}
|
||||
|
||||
// GET: API/PrayerCount
|
||||
public JsonResult PrayerCount(string affiliatekey, string includeAll = "false", string isPraise = "false")
|
||||
{
|
||||
var isPraiseBool = StringToBool(isPraise);
|
||||
var includeAllBool = StringToBool(includeAll);
|
||||
|
||||
var affiliate = controllerHelper.GetAffiliate(affiliatekey);
|
||||
|
||||
var totalCount = controllerHelper
|
||||
.db.Prayers
|
||||
.Count(i => (i.AffiliateId == affiliate.Id
|
||||
|| includeAllBool
|
||||
)
|
||||
&& !i.IsDeleted
|
||||
&& i.IsPraise == isPraiseBool);
|
||||
|
||||
if (includeAllBool && !isPraiseBool)
|
||||
{
|
||||
totalCount += CONST_PreviousPrayerCount;
|
||||
}
|
||||
|
||||
var data = new
|
||||
{
|
||||
count = totalCount,
|
||||
display = totalCount.ToString("N0")
|
||||
};
|
||||
|
||||
return Json(data, JsonRequestBehavior.AllowGet);
|
||||
}
|
||||
|
||||
// GET: API/PrayedCount
|
||||
public JsonResult PrayedCount(string affiliatekey, string includeAll = "false")
|
||||
{
|
||||
var includeAllBool = StringToBool(includeAll);
|
||||
|
||||
var affiliate = controllerHelper.GetAffiliate(affiliatekey);
|
||||
|
||||
var totalCount = controllerHelper
|
||||
.db.Prayers
|
||||
.Where(i => (i.AffiliateId == affiliate.Id
|
||||
&& !i.IsDeleted
|
||||
&& !i.IsPraise
|
||||
)
|
||||
|| includeAllBool
|
||||
)
|
||||
.Select(i => i.CountPrayed).DefaultIfEmpty(0).Sum();
|
||||
|
||||
|
||||
if (includeAllBool)
|
||||
{
|
||||
totalCount += CONST_PreviousPrayedCount;
|
||||
}
|
||||
|
||||
var data = new
|
||||
{
|
||||
count = totalCount,
|
||||
display = totalCount.ToString("N0")
|
||||
};
|
||||
|
||||
return Json(data, JsonRequestBehavior.AllowGet);
|
||||
}
|
||||
|
||||
// GET: API/PrayedCount
|
||||
public JsonResult NotesCount(string affiliatekey, string includeAll = "false")
|
||||
{
|
||||
var includeAllBool = StringToBool(includeAll);
|
||||
|
||||
var affiliate = controllerHelper.GetAffiliate(affiliatekey);
|
||||
|
||||
var totalCount = controllerHelper
|
||||
.db.PrayerNotes
|
||||
.Include("Prayer")
|
||||
.Where(i => (i.Prayer.AffiliateId == affiliate.Id
|
||||
|| includeAllBool
|
||||
)
|
||||
&& !i.Prayer.IsDeleted
|
||||
&& !i.Prayer.IsPraise)
|
||||
.Count();
|
||||
|
||||
|
||||
if (includeAllBool)
|
||||
{
|
||||
totalCount += CONST_PreviousNotesSent;
|
||||
}
|
||||
|
||||
|
||||
var data = new
|
||||
{
|
||||
count = totalCount,
|
||||
display = totalCount.ToString("N0")
|
||||
};
|
||||
|
||||
return Json(data, JsonRequestBehavior.AllowGet);
|
||||
}
|
||||
|
||||
public static bool StringToBool(string boolString)
|
||||
{
|
||||
if (boolString.Equals("1", StringComparison.InvariantCultureIgnoreCase)
|
||||
|| boolString.Equals("yes", StringComparison.InvariantCultureIgnoreCase))
|
||||
{
|
||||
boolString = bool.TrueString;
|
||||
}
|
||||
|
||||
var boolValue = false;
|
||||
bool.TryParse(boolString, out boolValue);
|
||||
|
||||
return boolValue;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
600
Amen/Controllers/AccountController.cs
Normal file
@ -0,0 +1,600 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using System.Web;
|
||||
using System.Web.Mvc;
|
||||
using Microsoft.AspNet.Identity;
|
||||
using Microsoft.AspNet.Identity.Owin;
|
||||
using Microsoft.Owin.Security;
|
||||
using Amen.Models;
|
||||
using Facebook;
|
||||
using System.Data.Entity;
|
||||
|
||||
namespace Amen.Controllers
|
||||
{
|
||||
[Authorize]
|
||||
public class AccountController : BaseController
|
||||
{
|
||||
private ApplicationSignInManager _signInManager;
|
||||
private ApplicationUserManager _userManager;
|
||||
|
||||
public AccountController()
|
||||
{
|
||||
}
|
||||
|
||||
public AccountController(ApplicationUserManager userManager, ApplicationSignInManager signInManager )
|
||||
{
|
||||
UserManager = userManager;
|
||||
SignInManager = signInManager;
|
||||
}
|
||||
|
||||
public ApplicationSignInManager SignInManager
|
||||
{
|
||||
get
|
||||
{
|
||||
return _signInManager ?? HttpContext.GetOwinContext().Get<ApplicationSignInManager>();
|
||||
}
|
||||
private set
|
||||
{
|
||||
_signInManager = value;
|
||||
}
|
||||
}
|
||||
|
||||
public ApplicationUserManager UserManager
|
||||
{
|
||||
get
|
||||
{
|
||||
return _userManager ?? HttpContext.GetOwinContext().GetUserManager<ApplicationUserManager>();
|
||||
}
|
||||
private set
|
||||
{
|
||||
_userManager = value;
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// GET: /Account/Login
|
||||
[AllowAnonymous]
|
||||
public ActionResult Login(string returnUrl, string affiliatekey)
|
||||
{
|
||||
ViewBag.ReturnUrl = returnUrl;
|
||||
return View();
|
||||
}
|
||||
|
||||
//
|
||||
// POST: /Account/Login
|
||||
[HttpPost]
|
||||
[AllowAnonymous]
|
||||
[ValidateAntiForgeryToken]
|
||||
public async Task<ActionResult> Login(LoginViewModel model, string returnUrl, string affiliatekey)
|
||||
{
|
||||
if (!ModelState.IsValid)
|
||||
{
|
||||
return View(model);
|
||||
}
|
||||
|
||||
// This doesn't count login failures towards account lockout
|
||||
// To enable password failures to trigger account lockout, change to shouldLockout: true
|
||||
var result = await SignInManager.PasswordSignInAsync(model.Email, model.Password, model.RememberMe, shouldLockout: true);
|
||||
switch (result)
|
||||
{
|
||||
case SignInStatus.Success:
|
||||
var user = controllerHelper.db.Users.Include("Affiliate").FirstOrDefault(i => i.Email == model.Email);
|
||||
|
||||
if (user != null)
|
||||
{
|
||||
user.LastLoginDateUtc = DateTime.UtcNow;
|
||||
controllerHelper.db.SaveChanges();
|
||||
affiliatekey = user.Affiliate.Key;
|
||||
}
|
||||
|
||||
return RedirectToLocal(returnUrl, affiliatekey);
|
||||
case SignInStatus.LockedOut:
|
||||
return View("Lockout");
|
||||
case SignInStatus.RequiresVerification:
|
||||
return RedirectToAction("SendCode", new { ReturnUrl = returnUrl, RememberMe = model.RememberMe });
|
||||
case SignInStatus.Failure:
|
||||
default:
|
||||
ModelState.AddModelError("", "Invalid login attempt.");
|
||||
return View(model);
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// GET: /Account/VerifyCode
|
||||
[AllowAnonymous]
|
||||
public async Task<ActionResult> VerifyCode(string provider, string returnUrl, bool rememberMe, string affiliatekey)
|
||||
{
|
||||
// Require that the user has already logged in via username/password or external login
|
||||
if (!await SignInManager.HasBeenVerifiedAsync())
|
||||
{
|
||||
return View("Error");
|
||||
}
|
||||
return View(new VerifyCodeViewModel { Provider = provider, ReturnUrl = returnUrl, RememberMe = rememberMe });
|
||||
}
|
||||
|
||||
//
|
||||
// POST: /Account/VerifyCode
|
||||
[HttpPost]
|
||||
[AllowAnonymous]
|
||||
[ValidateAntiForgeryToken]
|
||||
public async Task<ActionResult> VerifyCode(VerifyCodeViewModel model, string affiliatekey)
|
||||
{
|
||||
if (!ModelState.IsValid)
|
||||
{
|
||||
return View(model);
|
||||
}
|
||||
|
||||
// The following code protects for brute force attacks against the two factor codes.
|
||||
// If a user enters incorrect codes for a specified amount of time then the user account
|
||||
// will be locked out for a specified amount of time.
|
||||
// You can configure the account lockout settings in IdentityConfig
|
||||
var result = await SignInManager.TwoFactorSignInAsync(model.Provider, model.Code, isPersistent: model.RememberMe, rememberBrowser: model.RememberBrowser);
|
||||
switch (result)
|
||||
{
|
||||
case SignInStatus.Success:
|
||||
return RedirectToLocal(model.ReturnUrl, affiliatekey);
|
||||
case SignInStatus.LockedOut:
|
||||
return View("Lockout");
|
||||
case SignInStatus.Failure:
|
||||
default:
|
||||
ModelState.AddModelError("", "Invalid code.");
|
||||
return View(model);
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// GET: /Account/Register
|
||||
[AllowAnonymous]
|
||||
public ActionResult Register(string affiliatekey)
|
||||
{
|
||||
var affiliate = new ControllerHelper().GetAffiliate(affiliatekey);
|
||||
var model = new RegisterViewModel()
|
||||
{
|
||||
EnableSmsNotifications = true,
|
||||
EnableEmailNotifications = true,
|
||||
AffiliateEnableShowLocation = affiliate.EnableShowLocation,
|
||||
AffiliateEnableShowName = affiliate.EnableShowName,
|
||||
AffiliateIsSmsCapable = affiliate.IsSmsCapable
|
||||
};
|
||||
return View(model);
|
||||
}
|
||||
|
||||
//
|
||||
// POST: /Account/Register
|
||||
[HttpPost]
|
||||
[AllowAnonymous]
|
||||
[ValidateAntiForgeryToken]
|
||||
public async Task<ActionResult> Register(RegisterViewModel model, string affiliatekey)
|
||||
{
|
||||
if (ModelState.IsValid)
|
||||
{
|
||||
var affiliate = new ControllerHelper().GetAffiliate(affiliatekey);
|
||||
|
||||
var user = new ApplicationUser { FullName = model.FullName, UserName = model.Email, Email = model.Email, AffiliateId = affiliate.Id, LastLoginDateUtc = DateTime.UtcNow, EnableSmsNotifications = model.EnableSmsNotifications, EnableEmailNotifications = model.EnableEmailNotifications, Location = model.Location, ShouldShowLocation = model.ShouldShowLocation, ShouldShowName = model.ShouldShowName };
|
||||
//return View(model);
|
||||
|
||||
var result = await UserManager.CreateAsync(user, model.Password);
|
||||
|
||||
if (result.Succeeded)
|
||||
{
|
||||
await SignInManager.SignInAsync(user, isPersistent: false, rememberBrowser: false);
|
||||
|
||||
// For more information on how to enable account confirmation and password reset please visit http://go.microsoft.com/fwlink/?LinkID=320771
|
||||
// Send an email with this link
|
||||
//string code = await UserManager.GenerateEmailConfirmationTokenAsync(user.Id);
|
||||
//var callbackUrl = Url.Action("ConfirmEmail", "Account", new { userId = user.Id, code = code, affiliatekey = affiliatekey }, protocol: Request.Url.Scheme);
|
||||
//await UserManager.SendEmailAsync(user.Id, "Confirm your account", "Please confirm your account by clicking <a href=\"" + callbackUrl + "\">here</a>");
|
||||
|
||||
//TODO: redirect to note indicating confirmation email was sent
|
||||
return RedirectToAction("Index", "Prayer", new { affiliatekey = affiliatekey });
|
||||
}
|
||||
|
||||
//AddErrors(result);
|
||||
//hack to not show the "Name [emailaddress] is already taken." error
|
||||
foreach (var error in result.Errors)
|
||||
{
|
||||
if (error.StartsWith("Name") && error.EndsWith("is already taken."))
|
||||
continue;
|
||||
|
||||
ModelState.AddModelError("", error);
|
||||
}
|
||||
|
||||
if (result.Errors.Count(i => i.StartsWith("Email") && i.EndsWith("is already taken.")) > 0)
|
||||
ViewBag.ShowResetPassword = true;
|
||||
}
|
||||
|
||||
// If we got this far, something failed, redisplay form
|
||||
return View(model);
|
||||
}
|
||||
|
||||
//
|
||||
// GET: /Account/ConfirmEmail
|
||||
[AllowAnonymous]
|
||||
public async Task<ActionResult> ConfirmEmail(string userId, string code, string affiliatekey)
|
||||
{
|
||||
if (userId == null || code == null)
|
||||
{
|
||||
return View("Error");
|
||||
}
|
||||
var result = await UserManager.ConfirmEmailAsync(userId, code);
|
||||
return View(result.Succeeded ? "ConfirmEmail" : "Error");
|
||||
}
|
||||
|
||||
//
|
||||
// GET: /Account/ForgotPassword
|
||||
[AllowAnonymous]
|
||||
public ActionResult ForgotPassword(string affiliatekey)
|
||||
{
|
||||
return View();
|
||||
}
|
||||
|
||||
//
|
||||
// POST: /Account/ForgotPassword
|
||||
[HttpPost]
|
||||
[AllowAnonymous]
|
||||
[ValidateAntiForgeryToken]
|
||||
public async Task<ActionResult> ForgotPassword(ForgotPasswordViewModel model, string affiliatekey)
|
||||
{
|
||||
if (ModelState.IsValid)
|
||||
{
|
||||
var user = await UserManager.FindByNameAsync(model.Email);
|
||||
//TODO: determine if we only send forgot password requests to confirmed users
|
||||
if (user == null) // || !(await UserManager.IsEmailConfirmedAsync(user.Id)))
|
||||
{
|
||||
// Don't reveal that the user does not exist or is not confirmed
|
||||
return View("ForgotPasswordConfirmation");
|
||||
}
|
||||
|
||||
// For more information on how to enable account confirmation and password reset please visit http://go.microsoft.com/fwlink/?LinkID=320771
|
||||
// Send an email with this link
|
||||
string code = await UserManager.GeneratePasswordResetTokenAsync(user.Id);
|
||||
var callbackUrl = Url.Action("ResetPassword", "Account", new { userId = user.Id, code = code }, protocol: Request.Url.Scheme);
|
||||
await UserManager.SendEmailAsync(user.Id, "Reset Password", "Please reset your password by clicking <a href=\"" + callbackUrl + "\">here</a>");
|
||||
return RedirectToAction("ForgotPasswordConfirmation", "Account");
|
||||
}
|
||||
|
||||
// If we got this far, something failed, redisplay form
|
||||
return View(model);
|
||||
}
|
||||
|
||||
//
|
||||
// GET: /Account/ForgotPasswordConfirmation
|
||||
[AllowAnonymous]
|
||||
public ActionResult ForgotPasswordConfirmation(string affiliatekey)
|
||||
{
|
||||
return View();
|
||||
}
|
||||
|
||||
//
|
||||
// GET: /Account/ResetPassword
|
||||
[AllowAnonymous]
|
||||
public ActionResult ResetPassword(string code, string affiliatekey)
|
||||
{
|
||||
return code == null ? View("Error") : View();
|
||||
}
|
||||
|
||||
//
|
||||
// POST: /Account/ResetPassword
|
||||
[HttpPost]
|
||||
[AllowAnonymous]
|
||||
[ValidateAntiForgeryToken]
|
||||
public async Task<ActionResult> ResetPassword(ResetPasswordViewModel model, string affiliatekey)
|
||||
{
|
||||
if (!ModelState.IsValid)
|
||||
{
|
||||
return View(model);
|
||||
}
|
||||
var user = await UserManager.FindByNameAsync(model.Email);
|
||||
if (user == null)
|
||||
{
|
||||
// Don't reveal that the user does not exist
|
||||
return RedirectToAction("ResetPasswordConfirmation", "Account");
|
||||
}
|
||||
var result = await UserManager.ResetPasswordAsync(user.Id, model.Code, model.Password);
|
||||
if (result.Succeeded)
|
||||
{
|
||||
return RedirectToAction("ResetPasswordConfirmation", "Account");
|
||||
}
|
||||
AddErrors(result);
|
||||
return View();
|
||||
}
|
||||
|
||||
//
|
||||
// GET: /Account/ResetPasswordConfirmation
|
||||
[AllowAnonymous]
|
||||
public ActionResult ResetPasswordConfirmation(string affiliatekey)
|
||||
{
|
||||
return View();
|
||||
}
|
||||
|
||||
//
|
||||
// POST: /Account/ExternalLogin
|
||||
[HttpPost]
|
||||
[AllowAnonymous]
|
||||
[ValidateAntiForgeryToken]
|
||||
public ActionResult ExternalLogin(string provider, string returnUrl, string affiliatekey)
|
||||
{
|
||||
|
||||
|
||||
// Request a redirect to the external login provider
|
||||
return new ChallengeResult(provider, Url.Action("ExternalLoginCallback", "Account", new { ReturnUrl = returnUrl, affiliatekey = (ViewBag.AffiliateKey ?? ControllerHelper.DefaultAffiliateKey) }));
|
||||
}
|
||||
|
||||
//
|
||||
// GET: /Account/SendCode
|
||||
[AllowAnonymous]
|
||||
public async Task<ActionResult> SendCode(string returnUrl, bool rememberMe, string affiliatekey)
|
||||
{
|
||||
var userId = await SignInManager.GetVerifiedUserIdAsync();
|
||||
if (userId == null)
|
||||
{
|
||||
return View("Error");
|
||||
}
|
||||
var userFactors = await UserManager.GetValidTwoFactorProvidersAsync(userId);
|
||||
var factorOptions = userFactors.Select(purpose => new SelectListItem { Text = purpose, Value = purpose }).ToList();
|
||||
return View(new SendCodeViewModel { Providers = factorOptions, ReturnUrl = returnUrl, RememberMe = rememberMe });
|
||||
}
|
||||
|
||||
//
|
||||
// POST: /Account/SendCode
|
||||
[HttpPost]
|
||||
[AllowAnonymous]
|
||||
[ValidateAntiForgeryToken]
|
||||
public async Task<ActionResult> SendCode(SendCodeViewModel model, string affiliatekey)
|
||||
{
|
||||
if (!ModelState.IsValid)
|
||||
{
|
||||
return View();
|
||||
}
|
||||
|
||||
// Generate the token and send it
|
||||
if (!await SignInManager.SendTwoFactorCodeAsync(model.SelectedProvider))
|
||||
{
|
||||
return View("Error");
|
||||
}
|
||||
return RedirectToAction("VerifyCode", new { Provider = model.SelectedProvider, ReturnUrl = model.ReturnUrl, RememberMe = model.RememberMe });
|
||||
}
|
||||
|
||||
//
|
||||
// GET: /Account/ExternalLoginCallback
|
||||
[AllowAnonymous]
|
||||
public async Task<ActionResult> ExternalLoginCallback(string returnUrl, string affiliatekey)
|
||||
{
|
||||
var loginInfo = await AuthenticationManager.GetExternalLoginInfoAsync();
|
||||
if (loginInfo == null)
|
||||
{
|
||||
return RedirectToAction("Login");
|
||||
}
|
||||
// added the following lines
|
||||
if (loginInfo.Login.LoginProvider == "Facebook")
|
||||
{
|
||||
var identity = AuthenticationManager.GetExternalIdentity(DefaultAuthenticationTypes.ExternalCookie);
|
||||
var access_token = identity.FindFirstValue("FacebookAccessToken");
|
||||
var fb = new FacebookClient(access_token);
|
||||
dynamic myInfo = fb.Get("/me?fields=email"); // specify the email field
|
||||
loginInfo.Email = myInfo.email;
|
||||
loginInfo.DefaultUserName = identity.Name;
|
||||
}
|
||||
|
||||
// Sign in the user with this external login provider if the user already has a login
|
||||
var result = await SignInManager.ExternalSignInAsync(loginInfo, isPersistent: false);
|
||||
switch (result)
|
||||
{
|
||||
case SignInStatus.Success:
|
||||
|
||||
var user = controllerHelper.db.Users.Include("Affiliate").Where(i => i.Logins.Count(l => l.ProviderKey.Equals(loginInfo.Login.ProviderKey)) > 0).FirstOrDefault();
|
||||
if (user != null)
|
||||
{
|
||||
user.LastLoginDateUtc = DateTime.UtcNow;
|
||||
controllerHelper.db.SaveChanges();
|
||||
affiliatekey = user.Affiliate.Key;
|
||||
}
|
||||
|
||||
return RedirectToLocal(returnUrl, affiliatekey);
|
||||
case SignInStatus.LockedOut:
|
||||
return View("Lockout");
|
||||
case SignInStatus.RequiresVerification:
|
||||
return RedirectToAction("SendCode", new { ReturnUrl = returnUrl, RememberMe = false });
|
||||
case SignInStatus.Failure:
|
||||
default:
|
||||
if (await TryCreateOrAssocaiateUser(loginInfo, affiliatekey))
|
||||
{
|
||||
var user2 = controllerHelper.db.Users.Include("Affiliate").FirstOrDefault(i => i.Email == loginInfo.Email);
|
||||
if (user2 != null)
|
||||
{
|
||||
affiliatekey = user2.Affiliate.Key;
|
||||
}
|
||||
|
||||
return RedirectToLocal(returnUrl, affiliatekey);
|
||||
}
|
||||
|
||||
// If the user does not have an account, then prompt the user to create an account
|
||||
ViewBag.ReturnUrl = returnUrl;
|
||||
ViewBag.LoginProvider = loginInfo.Login.LoginProvider;
|
||||
return View("ExternalLoginConfirmation", new ExternalLoginConfirmationViewModel { Email = loginInfo.Email, FullName = loginInfo.DefaultUserName });
|
||||
}
|
||||
}
|
||||
|
||||
private async Task<bool> TryCreateOrAssocaiateUser( ExternalLoginInfo info, string affiliatekey)
|
||||
{
|
||||
var affiliate = new ControllerHelper().GetAffiliate(affiliatekey);
|
||||
|
||||
var user = controllerHelper.db.Users.FirstOrDefault(i => i.Email.Equals(info.Email));
|
||||
var result = new IdentityResult();
|
||||
|
||||
if (user == null)
|
||||
{
|
||||
user = new ApplicationUser { UserName = info.Email, FullName = info.DefaultUserName, Email = info.Email, AffiliateId = affiliate.Id, EmailConfirmed = true, LastLoginDateUtc = DateTime.UtcNow, EnableEmailNotifications = true, EnableSmsNotifications = true };
|
||||
result = await UserManager.CreateAsync(user);
|
||||
}
|
||||
|
||||
if (result.Succeeded || result.Errors.Count() == 0)
|
||||
{
|
||||
result = await UserManager.AddLoginAsync(user.Id, info.Login);
|
||||
if (result.Succeeded)
|
||||
{
|
||||
await SignInManager.SignInAsync(user, isPersistent: false, rememberBrowser: false);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//
|
||||
// POST: /Account/ExternalLoginConfirmation
|
||||
[HttpPost]
|
||||
[AllowAnonymous]
|
||||
[ValidateAntiForgeryToken]
|
||||
public async Task<ActionResult> ExternalLoginConfirmation(ExternalLoginConfirmationViewModel model, string returnUrl, string affiliatekey)
|
||||
{
|
||||
if (User.Identity.IsAuthenticated)
|
||||
{
|
||||
return RedirectToAction("Index", "Manage");
|
||||
}
|
||||
|
||||
if (ModelState.IsValid)
|
||||
{
|
||||
// Get the information about the user from the external login provider
|
||||
var info = await AuthenticationManager.GetExternalLoginInfoAsync();
|
||||
if (info == null)
|
||||
{
|
||||
return View("ExternalLoginFailure");
|
||||
}
|
||||
|
||||
var affiliate = new ControllerHelper().GetAffiliate(affiliatekey);
|
||||
|
||||
var user = controllerHelper.db.Users.FirstOrDefault(i => i.Email.Equals(model.Email));
|
||||
var result = new IdentityResult();
|
||||
|
||||
if (user == null)
|
||||
{
|
||||
user = new ApplicationUser { UserName = model.Email, FullName = model.FullName, Email = model.Email, AffiliateId = affiliate.Id, LastLoginDateUtc = DateTime.UtcNow, EnableSmsNotifications = true, EnableEmailNotifications = true };
|
||||
result = await UserManager.CreateAsync(user);
|
||||
}
|
||||
|
||||
if (result.Succeeded || result.Errors.Count() == 0)
|
||||
{
|
||||
result = await UserManager.AddLoginAsync(user.Id, info.Login);
|
||||
if (result.Succeeded)
|
||||
{
|
||||
await SignInManager.SignInAsync(user, isPersistent: false, rememberBrowser: false);
|
||||
return RedirectToLocal(returnUrl, affiliatekey);
|
||||
}
|
||||
}
|
||||
AddErrors(result);
|
||||
}
|
||||
|
||||
ViewBag.ReturnUrl = returnUrl;
|
||||
return View(model);
|
||||
}
|
||||
|
||||
//
|
||||
// POST: /Account/LogOff
|
||||
[HttpPost]
|
||||
[ValidateAntiForgeryToken]
|
||||
public ActionResult LogOff(string affiliatekey)
|
||||
{
|
||||
AuthenticationManager.SignOut();
|
||||
return RedirectToAction("Index", "Prayer", new { affiliatekey = affiliatekey });
|
||||
}
|
||||
|
||||
//
|
||||
// GET: /Account/ExternalLoginFailure
|
||||
[AllowAnonymous]
|
||||
public ActionResult ExternalLoginFailure(string affiliatekey)
|
||||
{
|
||||
return View();
|
||||
}
|
||||
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing)
|
||||
{
|
||||
if (_userManager != null)
|
||||
{
|
||||
_userManager.Dispose();
|
||||
_userManager = null;
|
||||
}
|
||||
|
||||
if (_signInManager != null)
|
||||
{
|
||||
_signInManager.Dispose();
|
||||
_signInManager = null;
|
||||
}
|
||||
}
|
||||
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
|
||||
#region Helpers
|
||||
// Used for XSRF protection when adding external logins
|
||||
private const string XsrfKey = "XsrfId";
|
||||
|
||||
private IAuthenticationManager AuthenticationManager
|
||||
{
|
||||
get
|
||||
{
|
||||
return HttpContext.GetOwinContext().Authentication;
|
||||
}
|
||||
}
|
||||
|
||||
private void AddErrors(IdentityResult result)
|
||||
{
|
||||
foreach (var error in result.Errors)
|
||||
{
|
||||
ModelState.AddModelError("", error);
|
||||
}
|
||||
}
|
||||
|
||||
private ActionResult RedirectToLocal(string returnUrl, string affiliatekey)
|
||||
{
|
||||
if (Url.IsLocalUrl(returnUrl))
|
||||
{
|
||||
return Redirect(returnUrl);
|
||||
}
|
||||
return RedirectToAction("Index", "Prayer", new { affiliatekey = affiliatekey });
|
||||
}
|
||||
|
||||
internal class ChallengeResult : HttpUnauthorizedResult
|
||||
{
|
||||
public ChallengeResult(string provider, string redirectUri)
|
||||
: this(provider, redirectUri, null)
|
||||
{
|
||||
}
|
||||
|
||||
public ChallengeResult(string provider, string redirectUri, string userId)
|
||||
{
|
||||
LoginProvider = provider;
|
||||
RedirectUri = redirectUri;
|
||||
UserId = userId;
|
||||
}
|
||||
|
||||
public string LoginProvider { get; set; }
|
||||
public string RedirectUri { get; set; }
|
||||
public string UserId { get; set; }
|
||||
|
||||
public override void ExecuteResult(ControllerContext context)
|
||||
{
|
||||
|
||||
//context.HttpContext.Session["WAKEUP"] = "NOW!";
|
||||
//context.HttpContext.Session.RemoveAll();
|
||||
|
||||
//// this line fixed the problem with returing null
|
||||
//context.RequestContext.HttpContext.Response.SuppressFormsAuthenticationRedirect = true;
|
||||
|
||||
var properties = new AuthenticationProperties { RedirectUri = RedirectUri };
|
||||
if (UserId != null)
|
||||
{
|
||||
properties.Dictionary[XsrfKey] = UserId;
|
||||
}
|
||||
context.HttpContext.GetOwinContext().Authentication.Challenge(properties, LoginProvider);
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
}
|
816
Amen/Controllers/AffiliateController.Extended.cs
Normal file
@ -0,0 +1,816 @@
|
||||
using Amen.Models;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Web.Mvc;
|
||||
using Microsoft.AspNet.Identity;
|
||||
using System.Configuration;
|
||||
using System.Text;
|
||||
using System.Data.Entity;
|
||||
using OfficeOpenXml;
|
||||
using System.IO;
|
||||
using PagedList;
|
||||
|
||||
namespace Amen.Controllers
|
||||
{
|
||||
[Authorize(Roles = ControllerHelper.Role_Administrator + "," + ControllerHelper.Role_AffiliateAdministrator)]
|
||||
public partial class AffiliateController : BaseController
|
||||
{
|
||||
[AllowAnonymous]
|
||||
public ActionResult Select(string affiliatekey)
|
||||
{
|
||||
var prayerSource = PrayerSource.DeterminePrayerSource(this.Request.UserAgent);
|
||||
|
||||
var model = controllerHelper.db
|
||||
.Affiliates
|
||||
.Where(i => i.IsActive && i.SubscriptionTypeId != (int)SubscriptionTypeEnum.Demo)
|
||||
.OrderByDescending(i => i.Key == ControllerHelper.DefaultAffiliateKey)
|
||||
.ThenBy(i => i.Name)
|
||||
.Select(i => new AffiliateSelectViewModel()
|
||||
{
|
||||
Name = i.Name,
|
||||
Key = i.Key,
|
||||
UrlLogo = i.UrlLogo,
|
||||
SubscriptionTypeId = i.SubscriptionTypeId
|
||||
})
|
||||
.ToList();
|
||||
|
||||
if (prayerSource == (int)PrayerSourceEnum.iOS)
|
||||
{
|
||||
model = model.Where(i => i.Key == ControllerHelper.DefaultAffiliateKey || i.SubscriptionTypeId == (int)SubscriptionTypeEnum.BasicPlus).ToList();
|
||||
}
|
||||
|
||||
foreach (var item in model)
|
||||
{
|
||||
item.NavigateUrl = Url.Action("Index", "Prayer", new { affiliatekey = item.Key }, null);
|
||||
}
|
||||
|
||||
return View(model);
|
||||
}
|
||||
|
||||
|
||||
[AllowAnonymous]
|
||||
public ActionResult NavigateToWebsite(string affiliatekey)
|
||||
{
|
||||
var affiliate = controllerHelper.GetAffiliate(affiliatekey);
|
||||
if (affiliate != null && !string.IsNullOrEmpty(affiliate.UrlWebsite))
|
||||
return Redirect(affiliate.UrlWebsite);
|
||||
|
||||
return Redirect(Url.Action("Index", "Prayer", new { affiliatekey = affiliate.Key }));
|
||||
}
|
||||
|
||||
bool ValidateAccess(string affiliatekey)
|
||||
{
|
||||
if (User.IsInRole(ControllerHelper.Role_Administrator))
|
||||
return true;
|
||||
|
||||
if (User.IsInRole(ControllerHelper.Role_AffiliateAdministrator))
|
||||
{
|
||||
var appUserId = User.Identity.GetUserId();
|
||||
return controllerHelper.db.AffiliateAdmins.Include("Affiliate").Count(i => i.Affiliate.Key.Equals(affiliatekey) && i.ApplicationUserId == appUserId) > 0;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public ActionResult Users(int id, string affiliatekey)
|
||||
{
|
||||
Affiliate affiliate = db.Affiliates.Find(id);
|
||||
if (!ValidateAccess(affiliate.Key))
|
||||
return new EmptyResult();
|
||||
|
||||
var adminRoles = db.Roles.Where(i => i.Name == ControllerHelper.Role_Administrator || i.Name == ControllerHelper.Role_AffiliateAdministrator).Select(i => i.Id).ToList();
|
||||
var admins = db.Users.Where(i => i.AffiliateId == id && i.Roles.Count(r => adminRoles.Contains(r.RoleId)) > 0).Select(i => i.Id).ToList();
|
||||
|
||||
var offset = controllerHelper.GetTimeZoneOffsetFromClient();
|
||||
|
||||
//TODO: add case where user does not have default affiliate of current affiliate, but is an admin for the affiliate (when 1 person is an admin for multiple affiliates)
|
||||
var model = new AffiliateUsersViewModel();
|
||||
model.Id = id;
|
||||
model.Users = controllerHelper.db.Users
|
||||
.Include("Affiliate")
|
||||
.Where(i => i.AffiliateId == id)
|
||||
.Select(i => new AffiliateUsersViewModel.AffiliateUserViewModel()
|
||||
{
|
||||
Id = i.Id,
|
||||
FullName = i.FullName,
|
||||
Email = i.Email,
|
||||
//LastLoginDate = i.LastLoginDateUtc,
|
||||
OffsetMinutes = offset,
|
||||
IsAdmin = i.Roles.Count(r => admins.Contains(r.UserId)) > 0
|
||||
})
|
||||
.OrderByDescending(i => i.IsAdmin)
|
||||
.ThenBy(i => i.FullName)
|
||||
.ToList();
|
||||
|
||||
return View(model);
|
||||
}
|
||||
|
||||
[Authorize(Roles = ControllerHelper.Role_Administrator)]
|
||||
public ActionResult UserMakeAdmin(int id, string userId)
|
||||
{
|
||||
Affiliate affiliate = db.Affiliates.Find(id);
|
||||
if (!ValidateAccess(affiliate.Key))
|
||||
return new EmptyResult();
|
||||
|
||||
var adminRoleId = db.Roles.First(i => i.Name == ControllerHelper.Role_AffiliateAdministrator).Id;
|
||||
var user = db.Users.Include("Roles").FirstOrDefault(i => i.Id == userId);
|
||||
if (user != null)
|
||||
{
|
||||
if (user.Roles.Count(i => i.RoleId == adminRoleId) == 0)
|
||||
{
|
||||
user.Roles.Add(new Microsoft.AspNet.Identity.EntityFramework.IdentityUserRole() { RoleId = adminRoleId, UserId = user.Id });
|
||||
db.SaveChanges();
|
||||
}
|
||||
|
||||
if (db.AffiliateAdmins.Count(i => i.ApplicationUserId == userId && i.AffiliateId == id) == 0)
|
||||
{
|
||||
db.AffiliateAdmins.Add(new AffiliateAdmin()
|
||||
{
|
||||
AffiliateId = id,
|
||||
ApplicationUserId = userId,
|
||||
CreatedUTC = DateTime.UtcNow
|
||||
|
||||
});
|
||||
db.SaveChanges();
|
||||
}
|
||||
}
|
||||
|
||||
return RedirectToAction("Users", new { id = id, affiliatekey = ViewBag.AffiliateKey ?? Amen.Controllers.ControllerHelper.DefaultAffiliateKey });
|
||||
}
|
||||
|
||||
[Authorize(Roles = ControllerHelper.Role_Administrator)]
|
||||
public ActionResult UserRemoveAdmin(int id, string userId)
|
||||
{
|
||||
Affiliate affiliate = db.Affiliates.Find(id);
|
||||
if (!ValidateAccess(affiliate.Key))
|
||||
return new EmptyResult();
|
||||
|
||||
var adminRoleId = db.Roles.First(i => i.Name == ControllerHelper.Role_AffiliateAdministrator).Id;
|
||||
var user = db.Users.Include("Roles").FirstOrDefault(i => i.Id == userId);
|
||||
if (user != null)
|
||||
{
|
||||
var role = user.Roles.FirstOrDefault(i => i.RoleId == adminRoleId);
|
||||
if (role != null)
|
||||
{
|
||||
user.Roles.Remove(role);
|
||||
db.SaveChanges();
|
||||
}
|
||||
|
||||
var affAdmin = db.AffiliateAdmins.FirstOrDefault(i => i.ApplicationUserId == userId && i.AffiliateId == id);
|
||||
if (affAdmin != null)
|
||||
{
|
||||
db.AffiliateAdmins.Remove(affAdmin);
|
||||
db.SaveChanges();
|
||||
}
|
||||
}
|
||||
|
||||
return RedirectToAction("Users", new { id = id, affiliatekey = ViewBag.AffiliateKey ?? Amen.Controllers.ControllerHelper.DefaultAffiliateKey });
|
||||
}
|
||||
|
||||
public ActionResult Prayers(int id, string affiliatekey, int page = 1)
|
||||
{
|
||||
Affiliate affiliate = db.Affiliates.Find(id);
|
||||
if (!ValidateAccess(affiliate.Key))
|
||||
return new EmptyResult();
|
||||
|
||||
var pageSize = 100;
|
||||
|
||||
var model = new AffiliatePrayersViewModel() { Id = id, PageSize = pageSize, Page = page };
|
||||
model.Prayers = controllerHelper.db
|
||||
.Prayers
|
||||
.Include("ApplicationUser")
|
||||
.Where(i => i.AffiliateId == id
|
||||
&& !i.IsPraise
|
||||
&& !i.IsDeleted)
|
||||
.OrderByDescending(i => i.CreatedUTC)
|
||||
.ToPagedList(page, pageSize);
|
||||
|
||||
return View(model);
|
||||
}
|
||||
|
||||
public ActionResult Praise(int id, string affiliatekey, int page = 1)
|
||||
{
|
||||
Affiliate affiliate = db.Affiliates.Find(id);
|
||||
if (!ValidateAccess(affiliate.Key))
|
||||
return new EmptyResult();
|
||||
|
||||
var pageSize = 100;
|
||||
|
||||
var model = new AffiliatePrayersViewModel() { Id = id, PageSize = pageSize, Page = page };
|
||||
model.Prayers = controllerHelper.db
|
||||
.Prayers
|
||||
.Include("ApplicationUser")
|
||||
.Where(i => i.AffiliateId == id
|
||||
&& i.IsPraise
|
||||
&& !i.IsDeleted)
|
||||
.OrderByDescending(i => i.CreatedUTC)
|
||||
.ToPagedList(page, pageSize);
|
||||
|
||||
return View(model);
|
||||
}
|
||||
|
||||
public void ExportPrayers(int id, string affiliatekey, int days = 0)
|
||||
{
|
||||
Affiliate affiliate = db.Affiliates.Find(id);
|
||||
if (!ValidateAccess(affiliate.Key))
|
||||
return;
|
||||
|
||||
if (days <= 0)
|
||||
{
|
||||
days = 20 * 365;
|
||||
}
|
||||
|
||||
var startDate = DateTime.UtcNow.AddDays(-days);
|
||||
|
||||
var data = controllerHelper.db
|
||||
.Prayers
|
||||
.Include("ApplicationUser")
|
||||
.Include("PrayerSource")
|
||||
.Where(i => i.AffiliateId == id
|
||||
&& !i.IsPraise
|
||||
&& !i.IsDeleted
|
||||
&& i.CreatedUTC >= startDate)
|
||||
.OrderByDescending(i => i.Id)
|
||||
//.OrderByDescending(i => i.CreatedUTC)
|
||||
.ToList();
|
||||
|
||||
ExcelPackage excel = new ExcelPackage();
|
||||
var workSheet = excel.Workbook.Worksheets.Add("Prayers");
|
||||
var filename = string.Format("{0}-Prayers", affiliatekey);
|
||||
|
||||
var row = 1;
|
||||
var col = 1;
|
||||
//headers first
|
||||
workSheet.Cells[row, col++].Value = "Id";
|
||||
workSheet.Cells[row, col++].Value = "IsActive";
|
||||
workSheet.Cells[row, col++].Value = "Title";
|
||||
workSheet.Cells[row, col++].Value = "Content";
|
||||
workSheet.Cells[row, col++].Value = "CountPrayed";
|
||||
workSheet.Cells[row, col++].Value = "CountFlagged";
|
||||
workSheet.Cells[row, col++].Value = "EnableEmailNote";
|
||||
workSheet.Cells[row, col++].Value = "EnableEmailNotification";
|
||||
workSheet.Cells[row, col++].Value = "EnableTextNotification";
|
||||
workSheet.Cells[row, col++].Value = "FullName";
|
||||
workSheet.Cells[row, col++].Value = "Email";
|
||||
workSheet.Cells[row, col++].Value = "IPAddress";
|
||||
workSheet.Cells[row, col++].Value = "UserAgent";
|
||||
workSheet.Cells[row, col++].Value = "Source";
|
||||
workSheet.Cells[row, col++].Value = "CreatedUTC";
|
||||
workSheet.Column(col - 1).Style.Numberformat.Format = "m/d/yyyy HH:mm";
|
||||
|
||||
foreach (var item in data)
|
||||
{
|
||||
col = 1;
|
||||
row++;
|
||||
workSheet.Cells[row, col++].Value = item.Id;
|
||||
workSheet.Cells[row, col++].Value = item.IsActive;
|
||||
workSheet.Cells[row, col++].Value = item.Summary;
|
||||
workSheet.Cells[row, col++].Value = item.Content;
|
||||
workSheet.Cells[row, col++].Value = item.CountPrayed;
|
||||
workSheet.Cells[row, col++].Value = item.CountFlagged;
|
||||
workSheet.Cells[row, col++].Value = item.EnableEmailNote;
|
||||
workSheet.Cells[row, col++].Value = item.EnableEmailNotification;
|
||||
workSheet.Cells[row, col++].Value = item.EnableTextNotification;
|
||||
|
||||
if (item.ApplicationUser != null)
|
||||
{
|
||||
workSheet.Cells[row, col++].Value = item.ApplicationUser.FullName;
|
||||
workSheet.Cells[row, col++].Value = item.ApplicationUser.Email;
|
||||
}
|
||||
else
|
||||
{
|
||||
workSheet.Cells[row, col++].Value = item.AnonymousName;
|
||||
workSheet.Cells[row, col++].Value = item.AnonymousEmail;
|
||||
}
|
||||
|
||||
workSheet.Cells[row, col++].Value = item.AnonymousPhone;
|
||||
workSheet.Cells[row, col++].Value = item.IPAddress;
|
||||
workSheet.Cells[row, col++].Value = item.UserAgent;
|
||||
workSheet.Cells[row, col++].Value = item.PrayerSource.EnumValue.ToString();
|
||||
workSheet.Cells[row, col++].Value = item.CreatedUTC;
|
||||
|
||||
}
|
||||
|
||||
for (int i = 1; i <= workSheet.Dimension.End.Column; i++)
|
||||
{
|
||||
workSheet.Column(i).AutoFit(0, 300);
|
||||
}
|
||||
|
||||
using (var memoryStream = new MemoryStream())
|
||||
{
|
||||
Response.ContentType = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
|
||||
Response.AddHeader("content-disposition", "attachment; filename=" + filename + ".xlsx");
|
||||
excel.SaveAs(memoryStream);
|
||||
memoryStream.WriteTo(Response.OutputStream);
|
||||
Response.Flush();
|
||||
Response.End();
|
||||
}
|
||||
}
|
||||
|
||||
public void ExportPraise(int id, string affiliatekey, int days = 0)
|
||||
{
|
||||
Affiliate affiliate = db.Affiliates.Find(id);
|
||||
if (!ValidateAccess(affiliate.Key))
|
||||
return;
|
||||
|
||||
if (days <= 0)
|
||||
{
|
||||
days = 20 * 365;
|
||||
}
|
||||
|
||||
var startDate = DateTime.UtcNow.AddDays(-days);
|
||||
|
||||
var data = controllerHelper.db
|
||||
.Prayers
|
||||
.Include("ApplicationUser")
|
||||
.Include("PrayerSource")
|
||||
.Where(i => i.AffiliateId == id
|
||||
&& i.IsPraise
|
||||
&& !i.IsDeleted
|
||||
&& i.CreatedUTC >= startDate)
|
||||
.OrderByDescending(i => i.Id)
|
||||
//.OrderByDescending(i => i.CreatedUTC)
|
||||
.ToList();
|
||||
|
||||
ExcelPackage excel = new ExcelPackage();
|
||||
var workSheet = excel.Workbook.Worksheets.Add("Praise");
|
||||
var filename = string.Format("{0}-Praise", affiliatekey);
|
||||
|
||||
var row = 1;
|
||||
var col = 1;
|
||||
//headers first
|
||||
workSheet.Cells[row, col++].Value = "Id";
|
||||
workSheet.Cells[row, col++].Value = "IsActive";
|
||||
workSheet.Cells[row, col++].Value = "Title";
|
||||
workSheet.Cells[row, col++].Value = "Content";
|
||||
workSheet.Cells[row, col++].Value = "CountFlagged";
|
||||
workSheet.Cells[row, col++].Value = "FullName";
|
||||
workSheet.Cells[row, col++].Value = "Email";
|
||||
workSheet.Cells[row, col++].Value = "IPAddress";
|
||||
workSheet.Cells[row, col++].Value = "UserAgent";
|
||||
workSheet.Cells[row, col++].Value = "Source";
|
||||
workSheet.Cells[row, col++].Value = "CreatedUTC";
|
||||
workSheet.Column(col - 1).Style.Numberformat.Format = "m/d/yyyy HH:mm";
|
||||
|
||||
foreach (var item in data)
|
||||
{
|
||||
col = 1;
|
||||
row++;
|
||||
workSheet.Cells[row, col++].Value = item.Id;
|
||||
workSheet.Cells[row, col++].Value = item.IsActive;
|
||||
workSheet.Cells[row, col++].Value = item.Summary;
|
||||
workSheet.Cells[row, col++].Value = item.Content;
|
||||
workSheet.Cells[row, col++].Value = item.CountFlagged;
|
||||
|
||||
if (item.ApplicationUser != null)
|
||||
{
|
||||
workSheet.Cells[row, col++].Value = item.ApplicationUser.FullName;
|
||||
workSheet.Cells[row, col++].Value = item.ApplicationUser.Email;
|
||||
}
|
||||
else
|
||||
{
|
||||
workSheet.Cells[row, col++].Value = item.AnonymousName;
|
||||
workSheet.Cells[row, col++].Value = item.AnonymousEmail;
|
||||
}
|
||||
|
||||
workSheet.Cells[row, col++].Value = item.IPAddress;
|
||||
workSheet.Cells[row, col++].Value = item.UserAgent;
|
||||
workSheet.Cells[row, col++].Value = item.PrayerSource.EnumValue.ToString();
|
||||
workSheet.Cells[row, col++].Value = item.CreatedUTC;
|
||||
|
||||
}
|
||||
|
||||
for (int i = 1; i <= workSheet.Dimension.End.Column; i++)
|
||||
{
|
||||
workSheet.Column(i).AutoFit(0, 300);
|
||||
}
|
||||
|
||||
using (var memoryStream = new MemoryStream())
|
||||
{
|
||||
Response.ContentType = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
|
||||
Response.AddHeader("content-disposition", "attachment; filename=" + filename + ".xlsx");
|
||||
excel.SaveAs(memoryStream);
|
||||
memoryStream.WriteTo(Response.OutputStream);
|
||||
Response.Flush();
|
||||
Response.End();
|
||||
}
|
||||
}
|
||||
|
||||
public ActionResult PrayerEdit(int id, string affiliatekey)
|
||||
{
|
||||
var prayer = db.Prayers.Include("Affiliate").FirstOrDefault(i => i.Id == id);
|
||||
if (!ValidateAccess(prayer.Affiliate.Key))
|
||||
return new EmptyResult();
|
||||
|
||||
var model = controllerHelper.db.Prayers
|
||||
.Include("ApplicationUser")
|
||||
.FirstOrDefault(i => i.Id == id && !i.IsDeleted);
|
||||
|
||||
ViewBag.PrayerSourceId = new SelectList(db.PrayerSources, "Id", "Label", model.PrayerSourceId);
|
||||
|
||||
return View(model);
|
||||
}
|
||||
|
||||
[HttpPost]
|
||||
[ValidateAntiForgeryToken]
|
||||
public ActionResult PrayerEdit([Bind(Include = "Id,PWId,AffiliateId,ApplicationUserId,IsActive,IsDeleted,EnableTextNotification,EnableEmailNotification,EnableEmailNote,Summary,Content,IsPraise,AnonymousName,AnonymousEmail,AnonymousPhone,AgreeTermsOfUse,IPAddress,UserAgent,ModifiedUTC,CreatedUTC,CountPrayed,CountFlagged,PrayerSourceId")] Prayer prayer, string affiliatekey)
|
||||
//public ActionResult PrayerEdit([Bind(Include = "Id,IsActive,EnableTextNotification")] Prayer prayer, string affiliatekey)
|
||||
{
|
||||
Affiliate affiliate = db.Affiliates.Find(prayer.AffiliateId);
|
||||
if (!ValidateAccess(affiliate.Key))
|
||||
return new EmptyResult();
|
||||
|
||||
if (ModelState.IsValid)
|
||||
{
|
||||
prayer.ModifiedUTC = DateTime.UtcNow;
|
||||
db.Entry(prayer).State = EntityState.Modified;
|
||||
db.SaveChanges();
|
||||
|
||||
if (prayer.IsPraise)
|
||||
return RedirectToAction("Praise", new { id = prayer.AffiliateId, affiliatekey = affiliatekey });
|
||||
else
|
||||
return RedirectToAction("Prayers", new { id = prayer.AffiliateId, affiliatekey = affiliatekey });
|
||||
}
|
||||
|
||||
ViewBag.PrayerSourceId = new SelectList(db.PrayerSources, "Id", "Label", prayer.PrayerSourceId);
|
||||
return View(prayer);
|
||||
}
|
||||
|
||||
public ActionResult PrayerDelete(int id, string affiliatekey)
|
||||
{
|
||||
var prayer = controllerHelper.db.Prayers.Include("Affiliate").FirstOrDefault(i => i.Id == id);
|
||||
if (!ValidateAccess(prayer.Affiliate.Key))
|
||||
return new EmptyResult();
|
||||
|
||||
prayer.IsDeleted = true;
|
||||
prayer.ModifiedUTC = DateTime.UtcNow;
|
||||
controllerHelper.db.SaveChanges();
|
||||
|
||||
if (prayer.IsPraise)
|
||||
return RedirectToAction("Praise", new { id = prayer.AffiliateId, affiliatekey = affiliatekey });
|
||||
else
|
||||
return RedirectToAction("Prayers", new { id = prayer.AffiliateId, affiliatekey = affiliatekey });
|
||||
}
|
||||
|
||||
public ActionResult PrayerActivate(int id, string affiliatekey)
|
||||
{
|
||||
var prayer = controllerHelper.db.Prayers.Include("Affiliate").FirstOrDefault(i => i.Id == id);
|
||||
if (!ValidateAccess(prayer.Affiliate.Key))
|
||||
return new EmptyResult();
|
||||
|
||||
prayer.IsActive = true;
|
||||
prayer.ModifiedUTC = DateTime.UtcNow;
|
||||
controllerHelper.db.SaveChanges();
|
||||
|
||||
if (prayer.IsPraise)
|
||||
return RedirectToAction("Praise", new { id = prayer.AffiliateId, affiliatekey = affiliatekey });
|
||||
else
|
||||
return RedirectToAction("Prayers", new { id = prayer.AffiliateId, affiliatekey = affiliatekey });
|
||||
}
|
||||
|
||||
// GET: Affiliate
|
||||
public ActionResult Index()
|
||||
{
|
||||
var affiliates = new List<Affiliate>();
|
||||
if (!User.IsInRole(ControllerHelper.Role_Administrator))
|
||||
{
|
||||
var appUserId = User.Identity.GetUserId() ?? "none";
|
||||
affiliates = db.AffiliateAdmins
|
||||
.Include("Affiliate")
|
||||
.Include("Affiliate.SubscriptionType")
|
||||
.Where(i => i.ApplicationUserId == appUserId)
|
||||
.Select(i => i.Affiliate)
|
||||
.ToList();
|
||||
|
||||
if (affiliates.Count == 1)
|
||||
return RedirectToAction("Details", new { id = affiliates.First().Id, affiliatekey = affiliates.First().Key });
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
affiliates = db.Affiliates
|
||||
.Include("SubscriptionType")
|
||||
.ToList();
|
||||
}
|
||||
|
||||
affiliates = affiliates
|
||||
.OrderByDescending(i => i.Key == ControllerHelper.DefaultAffiliateKey)
|
||||
.ThenByDescending(i => i.IsActive)
|
||||
.ThenBy(i => i.Name)
|
||||
.ToList();
|
||||
|
||||
return View(affiliates);
|
||||
}
|
||||
|
||||
public ActionResult Stats(int id, string affiliatekey)
|
||||
{
|
||||
Affiliate affiliate = db.Affiliates.Find(id);
|
||||
if (!ValidateAccess(affiliate.Key))
|
||||
return new EmptyResult();
|
||||
|
||||
var model = new AffiliateStatsViewModel();
|
||||
model.Id = id;
|
||||
|
||||
var recentStart = DateTime.UtcNow.AddDays(-30);
|
||||
|
||||
model.TotalRequests = db.Prayers.Count(i => i.AffiliateId == id && !i.IsDeleted && !i.IsPraise);
|
||||
model.RecentRequests = db.Prayers.Count(i => i.AffiliateId == id && !i.IsDeleted && !i.IsPraise && i.CreatedUTC > recentStart);
|
||||
|
||||
model.TotalPraise = db.Prayers.Count(i => i.AffiliateId == id && !i.IsDeleted && i.IsPraise);
|
||||
model.RecentPraise = db.Prayers.Count(i => i.AffiliateId == id && !i.IsDeleted && i.IsPraise && i.CreatedUTC > recentStart);
|
||||
|
||||
model.TotalNotesSent = db.PrayerNotes.Include("Prayer").Count(i => i.Prayer.AffiliateId == id && !i.Prayer.IsDeleted);
|
||||
model.RecentNotesSent = db.PrayerNotes.Include("Prayer").Count(i => i.Prayer.AffiliateId == id && !i.Prayer.IsDeleted && i.CreatedUTC > recentStart);
|
||||
|
||||
//TODO look at prayer rather than PrayerItems
|
||||
//model.TotalPrayersPrayed = db.PrayerItems.Include("Prayer").Count(i => i.Prayer.AffiliateId == id && !i.Prayer.IsDeleted);
|
||||
//model.RecentPrayersPrayed = db.PrayerItems.Include("Prayer").Count(i => i.Prayer.AffiliateId == id && !i.Prayer.IsDeleted && i.CreatedUTC > recentStart);
|
||||
model.TotalPrayersPrayed = db.Prayers.Where(i => !i.IsDeleted && i.AffiliateId == id).Select(i => i.CountPrayed).DefaultIfEmpty(0).Sum();
|
||||
model.RecentPrayersPrayed = db.Prayers.Where(i => !i.IsDeleted && i.AffiliateId == id && i.CreatedUTC > recentStart).Select(i => i.CountPrayed).DefaultIfEmpty(0).Sum();
|
||||
|
||||
//TODO look at prayer.CountFlagged rather than PrayerFlags
|
||||
//model.TotalFlagsIndicated = db.PrayerFlags.Include("Prayer").Count(i => i.Prayer.AffiliateId == id && !i.Prayer.IsDeleted);
|
||||
//model.RecentFlagsIndicated = db.PrayerFlags.Include("Prayer").Count(i => i.Prayer.AffiliateId == id && !i.Prayer.IsDeleted && i.CreatedUTC > recentStart);
|
||||
model.TotalFlagsIndicated = db.Prayers.Where(i => !i.IsDeleted && i.AffiliateId == id).Select(i => i.CountFlagged).DefaultIfEmpty(0).Sum();
|
||||
model.RecentFlagsIndicated = db.Prayers.Where(i => !i.IsDeleted && i.AffiliateId == id && i.CreatedUTC > recentStart).Select(i => i.CountFlagged).DefaultIfEmpty(0).Sum();
|
||||
|
||||
return View(model);
|
||||
}
|
||||
|
||||
public string UploadImage(string affiliatekey)
|
||||
{
|
||||
if (!ValidateAccess(affiliatekey))
|
||||
return string.Empty;
|
||||
|
||||
var returnImage = "";
|
||||
|
||||
if (this.Request.Files.AllKeys.Any())
|
||||
{
|
||||
// Get the uploaded image from the Files collection
|
||||
var httpPostedFile = this.Request.Files["UploadedImage"];
|
||||
|
||||
var fileName = httpPostedFile.FileName;
|
||||
var contentType = httpPostedFile.ContentType;
|
||||
var fileExtension = fileName.Substring(fileName.LastIndexOf('.') + 1);
|
||||
fileName = fileName.Substring(0, fileName.LastIndexOf('.'));
|
||||
|
||||
var imageName = string.Format("{0}-{1}-{2}.{3}", affiliatekey, fileName, DateTime.UtcNow.Ticks, fileExtension).ToLower();
|
||||
|
||||
foreach (char c in System.IO.Path.GetInvalidFileNameChars())
|
||||
{
|
||||
imageName = imageName.Replace(c, '-');
|
||||
}
|
||||
|
||||
var azureFolder = ConfigurationManager.AppSettings["AzureBlobStorageLogoFolder"];
|
||||
|
||||
if (httpPostedFile != null)
|
||||
{
|
||||
returnImage = ControllerHelper.ResizeAndSaveStreamToBlobStorage(httpPostedFile.InputStream, azureFolder, imageName, contentType, new ImageResizer.ResizeSettings(200, 200, ImageResizer.FitMode.Max, fileExtension));
|
||||
|
||||
//httpPostedFile.InputStream.Position = 0;
|
||||
//returnImage = BlobStorageHelper.SaveToBlobStorage(azureFolder, imageName, contentType, httpPostedFile.InputStream);
|
||||
}
|
||||
}
|
||||
return returnImage;
|
||||
}
|
||||
|
||||
public ActionResult Style(int id, string affiliatekey)
|
||||
{
|
||||
Affiliate affiliate = db.Affiliates.Find(id);
|
||||
if (!ValidateAccess(affiliate.Key))
|
||||
return new EmptyResult();
|
||||
|
||||
var builder = new StringBuilder();
|
||||
var styles = controllerHelper.db.AffiliateStyles.Where(i => i.AffiliateId == id).Select(i => i.StyleSheet);
|
||||
foreach (var style in styles)
|
||||
{
|
||||
builder.Append(style);
|
||||
builder.AppendLine();
|
||||
}
|
||||
|
||||
var template = System.IO.File.ReadAllText(Server.MapPath(@"~/Content/SiteCustom.css")).Trim();
|
||||
var model = new AffiliateStyleViewModel()
|
||||
{
|
||||
Id = id,
|
||||
Template = template,
|
||||
StyleContent = builder.ToString(),
|
||||
Key = affiliatekey
|
||||
};
|
||||
|
||||
return View(model);
|
||||
}
|
||||
|
||||
[HttpPost]
|
||||
[ValidateAntiForgeryToken]
|
||||
public ActionResult Style(AffiliateStyleViewModel affiliateStyle, string affiliatekey)
|
||||
{
|
||||
if (!ValidateAccess(affiliateStyle.Key))
|
||||
return new EmptyResult();
|
||||
|
||||
if (ModelState.IsValid)
|
||||
{
|
||||
var styleItem = db.AffiliateStyles.FirstOrDefault(i => i.AffiliateId == affiliateStyle.Id);
|
||||
var hasNewContent = !string.IsNullOrWhiteSpace(affiliateStyle.StyleContent);
|
||||
var hasExistingStyle = styleItem != null;
|
||||
|
||||
if (!hasNewContent && hasExistingStyle)//need to clear out style
|
||||
{
|
||||
db.AffiliateStyles.Remove(styleItem);
|
||||
}
|
||||
else if (hasNewContent && !hasExistingStyle) // need to add new style
|
||||
{
|
||||
db.AffiliateStyles.Add(new AffiliateStyle()
|
||||
{
|
||||
AffiliateId = affiliateStyle.Id,
|
||||
StyleSheet = affiliateStyle.StyleContent.Trim(),
|
||||
CreatedUTC = DateTime.UtcNow
|
||||
});
|
||||
}
|
||||
else if (hasNewContent && hasExistingStyle) // need to update existing style
|
||||
{
|
||||
styleItem.StyleSheet = affiliateStyle.StyleContent.Trim();
|
||||
}
|
||||
|
||||
db.SaveChanges();
|
||||
|
||||
}
|
||||
|
||||
return View(affiliateStyle);
|
||||
}
|
||||
|
||||
|
||||
public ActionResult FlagWords(int id, string affiliatekey)
|
||||
{
|
||||
Affiliate affiliate = db.Affiliates.Include("AutoFlagItems").FirstOrDefault(i => i.Id == id);
|
||||
if (!ValidateAccess(affiliate.Key))
|
||||
return new EmptyResult();
|
||||
|
||||
var model = new AffiliateFlagItemsViewModel()
|
||||
{
|
||||
Id = id,
|
||||
Key = affiliatekey,
|
||||
FlagItems = string.Join(",", affiliate.AutoFlagItems.Select(i => i.Text).ToArray())
|
||||
};
|
||||
|
||||
return View(model);
|
||||
}
|
||||
|
||||
|
||||
[HttpPost]
|
||||
[ValidateAntiForgeryToken]
|
||||
public ActionResult FlagWords(AffiliateFlagItemsViewModel model, string affiliatekey)
|
||||
{
|
||||
if (!ValidateAccess(model.Key))
|
||||
return new EmptyResult();
|
||||
|
||||
if (ModelState.IsValid)
|
||||
{
|
||||
var affiliate = db.Affiliates.Include("AutoFlagItems").FirstOrDefault(i => i.Key.Equals(model.Key));
|
||||
|
||||
var newList = (model.FlagItems ?? "").Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries).Select(i => i.Trim()).ToList();
|
||||
var existingList = affiliate.AutoFlagItems.Select(i => i.Text.Trim()).ToList();
|
||||
|
||||
var added = newList.Except(existingList);
|
||||
var deleted = existingList.Except(newList);
|
||||
|
||||
foreach (var item in added)
|
||||
{
|
||||
db.AutoFlagItems.Add(new AutoFlagItem()
|
||||
{
|
||||
AffiliateId = affiliate.Id,
|
||||
Text = item
|
||||
});
|
||||
}
|
||||
|
||||
var dbItems = affiliate.AutoFlagItems.ToList();
|
||||
foreach (var item in dbItems)
|
||||
{
|
||||
if (deleted.Contains(item.Text))
|
||||
db.AutoFlagItems.Remove(item);
|
||||
}
|
||||
|
||||
db.SaveChanges();
|
||||
|
||||
}
|
||||
|
||||
return View(model);
|
||||
}
|
||||
|
||||
|
||||
public ActionResult FlagIPs(int id, string affiliatekey)
|
||||
{
|
||||
Affiliate affiliate = db.Affiliates.Include("BlacklistIPs").FirstOrDefault(i => i.Id == id);
|
||||
if (!ValidateAccess(affiliate.Key))
|
||||
return new EmptyResult();
|
||||
|
||||
var model = new AffiliateFlagItemsViewModel()
|
||||
{
|
||||
Id = id,
|
||||
Key = affiliatekey,
|
||||
FlagItems = string.Join(",", affiliate.BlacklistIPs.Select(i => i.IP).ToArray())
|
||||
};
|
||||
|
||||
return View(model);
|
||||
}
|
||||
|
||||
|
||||
[HttpPost]
|
||||
[ValidateAntiForgeryToken]
|
||||
public ActionResult FlagIPs(AffiliateFlagItemsViewModel model, string affiliatekey)
|
||||
{
|
||||
if (!ValidateAccess(model.Key))
|
||||
return new EmptyResult();
|
||||
|
||||
if (ModelState.IsValid)
|
||||
{
|
||||
var affiliate = db.Affiliates.Include("BlacklistIPs").FirstOrDefault(i => i.Key.Equals(model.Key));
|
||||
|
||||
var newList = (model.FlagItems ?? "").Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries).Select(i => i.Trim()).ToList();
|
||||
var existingList = affiliate.BlacklistIPs.Select(i => i.IP.Trim()).ToList();
|
||||
|
||||
var added = newList.Except(existingList);
|
||||
var deleted = existingList.Except(newList);
|
||||
|
||||
foreach (var item in added)
|
||||
{
|
||||
db.BlacklistIPs.Add(new BlacklistIP()
|
||||
{
|
||||
AffiliateId = affiliate.Id,
|
||||
IP = item
|
||||
});
|
||||
}
|
||||
|
||||
var dbItems = affiliate.BlacklistIPs.ToList();
|
||||
foreach (var item in dbItems)
|
||||
{
|
||||
if (deleted.Contains(item.IP))
|
||||
db.BlacklistIPs.Remove(item);
|
||||
}
|
||||
|
||||
db.SaveChanges();
|
||||
|
||||
}
|
||||
|
||||
return View(model);
|
||||
}
|
||||
|
||||
|
||||
public ActionResult FlagEmails(int id, string affiliatekey)
|
||||
{
|
||||
Affiliate affiliate = db.Affiliates.Include("BlacklistEmails").FirstOrDefault(i => i.Id == id);
|
||||
if (!ValidateAccess(affiliate.Key))
|
||||
return new EmptyResult();
|
||||
|
||||
var model = new AffiliateFlagItemsViewModel()
|
||||
{
|
||||
Id = id,
|
||||
Key = affiliatekey,
|
||||
FlagItems = string.Join(",", affiliate.BlacklistEmails.Select(i => i.Email).ToArray())
|
||||
};
|
||||
|
||||
return View(model);
|
||||
}
|
||||
|
||||
|
||||
[HttpPost]
|
||||
[ValidateAntiForgeryToken]
|
||||
public ActionResult FlagEmails(AffiliateFlagItemsViewModel model, string affiliatekey)
|
||||
{
|
||||
if (!ValidateAccess(model.Key))
|
||||
return new EmptyResult();
|
||||
|
||||
if (ModelState.IsValid)
|
||||
{
|
||||
var affiliate = db.Affiliates.Include("BlacklistEmails").FirstOrDefault(i => i.Key.Equals(model.Key));
|
||||
|
||||
var newList = (model.FlagItems ?? "").Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries).Select(i => i.Trim()).ToList();
|
||||
var existingList = affiliate.BlacklistEmails.Select(i => i.Email.Trim()).ToList();
|
||||
|
||||
var added = newList.Except(existingList);
|
||||
var deleted = existingList.Except(newList);
|
||||
|
||||
foreach (var item in added)
|
||||
{
|
||||
db.BlacklistEmails.Add(new BlacklistEmail()
|
||||
{
|
||||
AffiliateId = affiliate.Id,
|
||||
Email = item
|
||||
});
|
||||
}
|
||||
|
||||
var dbItems = affiliate.BlacklistEmails.ToList();
|
||||
foreach (var item in dbItems)
|
||||
{
|
||||
if (deleted.Contains(item.Email))
|
||||
db.BlacklistEmails.Remove(item);
|
||||
}
|
||||
|
||||
db.SaveChanges();
|
||||
|
||||
}
|
||||
|
||||
return View(model);
|
||||
}
|
||||
}
|
||||
}
|
146
Amen/Controllers/AffiliateController.cs
Normal file
@ -0,0 +1,146 @@
|
||||
using System.Data.Entity;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Web.Mvc;
|
||||
using Amen.Models;
|
||||
|
||||
namespace Amen.Controllers
|
||||
{
|
||||
public partial class AffiliateController : BaseController
|
||||
{
|
||||
private ApplicationDbContext db = new ApplicationDbContext();
|
||||
|
||||
|
||||
// GET: Affiliate/Details/5
|
||||
public ActionResult Details(int? id, string affiliatekey)
|
||||
{
|
||||
if (id == null)
|
||||
{
|
||||
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
|
||||
}
|
||||
|
||||
Affiliate affiliate = db.Affiliates.Find(id);
|
||||
|
||||
if (!ValidateAccess(affiliate.Key))
|
||||
return new EmptyResult();
|
||||
|
||||
affiliate = db.Affiliates.Include("SubscriptionType").FirstOrDefault(i => i.Id == id);
|
||||
if (affiliate == null)
|
||||
{
|
||||
return HttpNotFound();
|
||||
}
|
||||
return View(affiliate);
|
||||
}
|
||||
|
||||
// GET: Affiliate/Create
|
||||
[Authorize(Roles = ControllerHelper.Role_Administrator)]
|
||||
public ActionResult Create()
|
||||
{
|
||||
ViewBag.SubscriptionTypeId = new SelectList(db.SubscriptionTypes, "Id", "Label");
|
||||
return View();
|
||||
}
|
||||
|
||||
// POST: Affiliate/Create
|
||||
// To protect from overposting attacks, please enable the specific properties you want to bind to, for
|
||||
// more details see http://go.microsoft.com/fwlink/?LinkId=317598.
|
||||
[HttpPost]
|
||||
[ValidateAntiForgeryToken]
|
||||
[Authorize(Roles = ControllerHelper.Role_Administrator)]
|
||||
public ActionResult Create([Bind(Include = "Id,PWId,Key,IncludeInUniversal,IsActive,Name,Instructions,InstructionsAddPrayer,UrlWebsite,UrlLogo,EmailAdmin,EmailBilling,EmailFlag,SendMessagePrayed,SendMessageNote,PrayerDaysThreshold,FlagThreshold,TwilioSID,TwilioAuthToken,TwilioPhoneNumber,ShouldSendPrayerNotificationAdmin,ShouldSendPraiseNotificationAdmin,EnableNotes,RequireModeration,SubscriptionTypeId,RequireLoginForNoticiations,EnableShowLocation,EnableShowName")] Affiliate affiliate)
|
||||
{
|
||||
if (ModelState.IsValid)
|
||||
{
|
||||
db.Affiliates.Add(affiliate);
|
||||
db.SaveChanges();
|
||||
return RedirectToAction("Details", new { id = affiliate.Id, affiliatekey = ViewBag.AffiliateKey ?? Amen.Controllers.ControllerHelper.DefaultAffiliateKey });
|
||||
}
|
||||
|
||||
ViewBag.SubscriptionTypeId = new SelectList(db.SubscriptionTypes, "Id", "Label", affiliate.SubscriptionTypeId);
|
||||
return View(affiliate);
|
||||
}
|
||||
|
||||
// GET: Affiliate/Edit/5
|
||||
public ActionResult Edit(int? id)
|
||||
{
|
||||
if (id == null)
|
||||
{
|
||||
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
|
||||
}
|
||||
Affiliate affiliate = db.Affiliates.Find(id);
|
||||
if (affiliate == null)
|
||||
{
|
||||
return HttpNotFound();
|
||||
}
|
||||
|
||||
if (!ValidateAccess(affiliate.Key))
|
||||
return new EmptyResult();
|
||||
|
||||
ViewBag.SubscriptionTypeId = new SelectList(db.SubscriptionTypes, "Id", "Label", affiliate.SubscriptionTypeId);
|
||||
return View(affiliate);
|
||||
}
|
||||
|
||||
// POST: Affiliate/Edit/5
|
||||
// To protect from overposting attacks, please enable the specific properties you want to bind to, for
|
||||
// more details see http://go.microsoft.com/fwlink/?LinkId=317598.
|
||||
[HttpPost]
|
||||
[ValidateAntiForgeryToken]
|
||||
public ActionResult Edit([Bind(Include = "Id,PWId,Key,IncludeInUniversal,IsActive,Name,Instructions,InstructionsPraise,InstructionsAddPrayer,InstructionsAddPraise,InstructionsNote,UrlWebsite,UrlLogo,EmailAdmin,EmailBilling,EmailFlag,SendMessagePrayed,SendMessageNote,PrayerDaysThreshold,FlagThreshold,TwilioSID,TwilioAuthToken,TwilioPhoneNumber,ShouldSendPrayerNotificationAdmin,ShouldSendPraiseNotificationAdmin,EnableNotes,RequireModeration,SubscriptionTypeId,RequireLoginForNoticiations,EnableShowLocation,EnableShowName")] Affiliate affiliate)
|
||||
{
|
||||
if (!ValidateAccess(affiliate.Key))
|
||||
return new EmptyResult();
|
||||
|
||||
var extraValid = true;
|
||||
if (affiliate.PrayerDaysThreshold <= 0 || affiliate.FlagThreshold <= 0)
|
||||
{
|
||||
extraValid = false;
|
||||
}
|
||||
|
||||
if (ModelState.IsValid && extraValid)
|
||||
{
|
||||
db.Entry(affiliate).State = EntityState.Modified;
|
||||
db.SaveChanges();
|
||||
return RedirectToAction("Details", new { id = affiliate.Id, affiliatekey = ViewBag.AffiliateKey ?? Amen.Controllers.ControllerHelper.DefaultAffiliateKey });
|
||||
}
|
||||
|
||||
ViewBag.SubscriptionTypeId = new SelectList(db.SubscriptionTypes, "Id", "Label", affiliate.SubscriptionTypeId);
|
||||
return View(affiliate);
|
||||
}
|
||||
|
||||
// GET: Affiliate/Delete/5
|
||||
[Authorize(Roles = ControllerHelper.Role_Administrator)]
|
||||
public ActionResult Delete(int? id)
|
||||
{
|
||||
if (id == null)
|
||||
{
|
||||
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
|
||||
}
|
||||
Affiliate affiliate = db.Affiliates.Find(id);
|
||||
if (affiliate == null)
|
||||
{
|
||||
return HttpNotFound();
|
||||
}
|
||||
return View(affiliate);
|
||||
}
|
||||
|
||||
// POST: Affiliate/Delete/5
|
||||
[HttpPost, ActionName("Delete")]
|
||||
[ValidateAntiForgeryToken]
|
||||
[Authorize(Roles = ControllerHelper.Role_Administrator)]
|
||||
public ActionResult DeleteConfirmed(int id)
|
||||
{
|
||||
Affiliate affiliate = db.Affiliates.Find(id);
|
||||
db.Affiliates.Remove(affiliate);
|
||||
db.SaveChanges();
|
||||
return RedirectToAction("Index", new { affiliatekey = ViewBag.AffiliateKey ?? Amen.Controllers.ControllerHelper.DefaultAffiliateKey });
|
||||
}
|
||||
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing)
|
||||
{
|
||||
db.Dispose();
|
||||
}
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
}
|
||||
}
|
46
Amen/Controllers/BaseController.cs
Normal file
@ -0,0 +1,46 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Configuration;
|
||||
using System.Web.Mvc;
|
||||
using System.Web.Routing;
|
||||
|
||||
namespace Amen.Controllers
|
||||
{
|
||||
public class BaseController : Controller
|
||||
{
|
||||
public ControllerHelper controllerHelper = new ControllerHelper();
|
||||
|
||||
protected override void OnActionExecuting(ActionExecutingContext filterContext)
|
||||
{
|
||||
//ViewBag.AffiliateKey = filterContext.ActionParameters["affiliatekey"];
|
||||
|
||||
ViewBag.AffiliateKey = filterContext.RouteData.Values["affiliatekey"];
|
||||
var isAdmin = filterContext.HttpContext.User.IsInRole(ControllerHelper.Role_Administrator);
|
||||
ViewBag.IsAdministrator = isAdmin;
|
||||
|
||||
string controller = (filterContext.RouteData.Values["controller"] as string ?? "").ToLower();
|
||||
string action = (filterContext.RouteData.Values["action"] as string ?? "").ToLower();
|
||||
var isUpgrade = false;
|
||||
bool.TryParse(ConfigurationManager.AppSettings["IsUpgradeInProgress"], out isUpgrade);
|
||||
|
||||
var allowControllers = new List<string>() { "account", "css" };
|
||||
var allowActions = new List<string>() { "upgradeinprogress" };
|
||||
|
||||
ViewBag.IsUpgradeInProgress = isUpgrade;
|
||||
|
||||
if (isUpgrade
|
||||
&& !isAdmin
|
||||
&& !allowControllers.Contains(controller)
|
||||
&& !allowActions.Contains(action))
|
||||
{
|
||||
filterContext.Result = new RedirectToRouteResult(
|
||||
new RouteValueDictionary {
|
||||
{ "controller", "Home" },
|
||||
{ "action", "UpgradeInProgress" },
|
||||
{ "affiliatekey", ViewBag.AffiliateKey }
|
||||
});
|
||||
}
|
||||
|
||||
base.OnActionExecuting(filterContext);
|
||||
}
|
||||
}
|
||||
}
|
36
Amen/Controllers/CSSController.cs
Normal file
@ -0,0 +1,36 @@
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Web.Mvc;
|
||||
|
||||
namespace Amen.Controllers
|
||||
{
|
||||
public class CssController : BaseController
|
||||
{
|
||||
public ContentResult GetTheme(string affiliatekey)
|
||||
{
|
||||
var builder = new StringBuilder();
|
||||
|
||||
var affiliate = controllerHelper.GetAffiliate(affiliatekey);
|
||||
var styles = controllerHelper.db.AffiliateStyles.Where(i => i.AffiliateId == affiliate.Id).Select(i => i.StyleSheet);
|
||||
|
||||
foreach (var style in styles)
|
||||
{
|
||||
builder.Append(style);
|
||||
builder.AppendLine();
|
||||
}
|
||||
|
||||
return Content(builder.ToString(), "text/css");
|
||||
}
|
||||
|
||||
public ActionResult AffiliateLogo(string affiliatekey)
|
||||
{
|
||||
var path = controllerHelper.Absolute(Url, Url.Content("~/Content/Images/Blank.png"));
|
||||
|
||||
var affiliate = controllerHelper.GetAffiliate(affiliatekey);
|
||||
if (affiliate != null && !string.IsNullOrEmpty(affiliate.UrlLogo))
|
||||
path = affiliate.UrlLogo;
|
||||
|
||||
return Redirect(path);
|
||||
}
|
||||
}
|
||||
}
|
195
Amen/Controllers/ControllerHelper.cs
Normal file
@ -0,0 +1,195 @@
|
||||
using Amen.Models;
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Web;
|
||||
using Microsoft.AspNet.Identity;
|
||||
using System.Web.Mvc;
|
||||
using System.IO;
|
||||
using System.Web.Routing;
|
||||
using System.Data.Entity;
|
||||
using Amen.Helpers;
|
||||
using Microsoft.Crm.Sdk.Messages;
|
||||
|
||||
namespace Amen.Controllers
|
||||
{
|
||||
public class ControllerHelper
|
||||
{
|
||||
public const string DefaultAffiliateKey = "Amen";
|
||||
public const string Role_SuperAdministrator = "Super Administrator";
|
||||
public const string Role_Administrator = "Administrator";
|
||||
public const string Role_AffiliateAdministrator = "Affiliate Administrator";
|
||||
|
||||
public ApplicationDbContext db = new ApplicationDbContext();
|
||||
|
||||
public static string ToAbsolute(HttpContext context, string relativeUrl)
|
||||
{
|
||||
var request = context.Request;
|
||||
|
||||
return string.Format("{0}://{1}{2}",
|
||||
(request.IsSecureConnection) ? "https" : "http",
|
||||
request.Headers["Host"],
|
||||
VirtualPathUtility.ToAbsolute(relativeUrl));
|
||||
}
|
||||
|
||||
public string Absolute(UrlHelper url, string relativeUrl)
|
||||
{
|
||||
var request = url.RequestContext.HttpContext.Request;
|
||||
|
||||
return string.Format("{0}://{1}{2}",
|
||||
(request.IsSecureConnection) ? "https" : "http",
|
||||
request.Headers["Host"],
|
||||
VirtualPathUtility.ToAbsolute(relativeUrl));
|
||||
}
|
||||
|
||||
private Affiliate _currentAffiliate;
|
||||
public Affiliate GetAffiliate(string key, bool returnInactive = false)
|
||||
{
|
||||
if (_currentAffiliate != null)
|
||||
return _currentAffiliate;
|
||||
|
||||
var aff = db.Affiliates.FirstOrDefault(i => i.Key == key);
|
||||
|
||||
if (aff != null && !aff.IsActive && returnInactive)
|
||||
{
|
||||
return aff;
|
||||
}
|
||||
|
||||
if (aff == null || !aff.IsActive)
|
||||
{
|
||||
aff = db.Affiliates.FirstOrDefault(i => i.Key.Equals(DefaultAffiliateKey, StringComparison.InvariantCultureIgnoreCase));
|
||||
}
|
||||
|
||||
_currentAffiliate = aff;
|
||||
|
||||
return _currentAffiliate;
|
||||
}
|
||||
|
||||
public ApplicationUser GetLoggedInUser()
|
||||
{
|
||||
if (HttpContext.Current == null || !HttpContext.Current.User.Identity.IsAuthenticated)
|
||||
return null;
|
||||
|
||||
var userIdentity = HttpContext.Current.User.Identity.GetUserId();
|
||||
return db.Users.Include("Affiliate").FirstOrDefault(i => i.Id.Equals(userIdentity));
|
||||
}
|
||||
|
||||
public int GetTimeZoneOffsetFromClient()
|
||||
{
|
||||
var cookieVal = GetCookieValue("TZOffset");
|
||||
var offset = 0;
|
||||
int.TryParse(cookieVal, out offset);
|
||||
|
||||
return offset;
|
||||
}
|
||||
|
||||
|
||||
private void SetCookie(string cName, string cValue)
|
||||
{
|
||||
HttpCookie cookie = new HttpCookie(cName);
|
||||
cookie.Value = cValue;
|
||||
cookie.Path = "/";
|
||||
HttpContext.Current.Response.Cookies.Add(cookie);
|
||||
}
|
||||
|
||||
private string GetCookieValue(string cName)
|
||||
{
|
||||
var cookie = HttpContext.Current.Request.Cookies.Get(cName);
|
||||
return cookie == null ? "" : cookie.Value;
|
||||
}
|
||||
|
||||
private void RemoveCookie(string cName)
|
||||
{
|
||||
var cookie = HttpContext.Current.Request.Cookies.Get(cName);
|
||||
|
||||
if (cookie == null)
|
||||
return;
|
||||
|
||||
HttpContext.Current.Response.Cookies.Remove(cookie.Name);
|
||||
|
||||
cookie.Expires = DateTime.Now.AddDays(-1);
|
||||
cookie.Value = null;
|
||||
cookie.Path = "/";
|
||||
|
||||
HttpContext.Current.Response.Cookies.Set(cookie);
|
||||
}
|
||||
|
||||
public static string RenderViewToString(ControllerContext context,
|
||||
string viewPath,
|
||||
object model = null,
|
||||
bool partial = false)
|
||||
{
|
||||
// first find the ViewEngine for this view
|
||||
ViewEngineResult viewEngineResult = null;
|
||||
if (partial)
|
||||
viewEngineResult = ViewEngines.Engines.FindPartialView(context, viewPath);
|
||||
else
|
||||
viewEngineResult = ViewEngines.Engines.FindView(context, viewPath, null);
|
||||
|
||||
if (viewEngineResult == null)
|
||||
throw new FileNotFoundException("View cannot be found.");
|
||||
|
||||
// get the view and attach the model to view data
|
||||
var view = viewEngineResult.View;
|
||||
context.Controller.ViewData.Model = model;
|
||||
|
||||
string result = null;
|
||||
|
||||
using (var sw = new StringWriter())
|
||||
{
|
||||
var ctx = new ViewContext(context, view,
|
||||
context.Controller.ViewData,
|
||||
context.Controller.TempData,
|
||||
sw);
|
||||
view.Render(ctx, sw);
|
||||
result = sw.ToString();
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public static T CreateController<T>(RouteData routeData = null)
|
||||
where T : Controller, new()
|
||||
{
|
||||
// create a disconnected controller instance
|
||||
T controller = new T();
|
||||
|
||||
// get context wrapper from HttpContext if available
|
||||
HttpContextBase wrapper;
|
||||
if (System.Web.HttpContext.Current != null)
|
||||
wrapper = new HttpContextWrapper(System.Web.HttpContext.Current);
|
||||
else
|
||||
throw new InvalidOperationException(
|
||||
"Can't create Controller Context if no " +
|
||||
"active HttpContext instance is available.");
|
||||
|
||||
if (routeData == null)
|
||||
routeData = new RouteData();
|
||||
|
||||
// add the controller routing if not existing
|
||||
if (!routeData.Values.ContainsKey("controller") &&
|
||||
!routeData.Values.ContainsKey("Controller"))
|
||||
routeData.Values.Add("controller",
|
||||
controller.GetType()
|
||||
.Name.ToLower().Replace("controller", ""));
|
||||
|
||||
controller.ControllerContext = new ControllerContext(wrapper, routeData, controller);
|
||||
return controller;
|
||||
}
|
||||
|
||||
static internal string ResizeAndSaveStreamToBlobStorage(Stream inputStream, string azureFolder, string fileName, string contentType, ImageResizer.ResizeSettings settings)
|
||||
{
|
||||
using (var outstream = new MemoryStream())
|
||||
{
|
||||
inputStream.Position = 0;
|
||||
|
||||
//resize with settings
|
||||
ImageResizer.ImageBuilder.Current.Build(inputStream, outstream, settings, false);
|
||||
|
||||
//reset the outstream back to the initial position
|
||||
outstream.Position = 0;
|
||||
|
||||
return BlobStorageHelper.SaveToBlobStorage(azureFolder, fileName, contentType, outstream);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
12
Amen/Controllers/HomeController.cs
Normal file
@ -0,0 +1,12 @@
|
||||
using System.Web.Mvc;
|
||||
|
||||
namespace Amen.Controllers
|
||||
{
|
||||
public class HomeController : Controller
|
||||
{
|
||||
public ActionResult UpgradeInProgress()
|
||||
{
|
||||
return View();
|
||||
}
|
||||
}
|
||||
}
|
425
Amen/Controllers/ManageController.cs
Normal file
@ -0,0 +1,425 @@
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using System.Web;
|
||||
using System.Web.Mvc;
|
||||
using Microsoft.AspNet.Identity;
|
||||
using Microsoft.AspNet.Identity.Owin;
|
||||
using Microsoft.Owin.Security;
|
||||
using Amen.Models;
|
||||
using System.Net;
|
||||
|
||||
namespace Amen.Controllers
|
||||
{
|
||||
[Authorize]
|
||||
public class ManageController : BaseController
|
||||
{
|
||||
private ApplicationSignInManager _signInManager;
|
||||
private ApplicationUserManager _userManager;
|
||||
|
||||
public ManageController()
|
||||
{
|
||||
}
|
||||
|
||||
public ManageController(ApplicationUserManager userManager, ApplicationSignInManager signInManager)
|
||||
{
|
||||
UserManager = userManager;
|
||||
SignInManager = signInManager;
|
||||
}
|
||||
|
||||
public ApplicationSignInManager SignInManager
|
||||
{
|
||||
get
|
||||
{
|
||||
return _signInManager ?? HttpContext.GetOwinContext().Get<ApplicationSignInManager>();
|
||||
}
|
||||
private set
|
||||
{
|
||||
_signInManager = value;
|
||||
}
|
||||
}
|
||||
|
||||
public ApplicationUserManager UserManager
|
||||
{
|
||||
get
|
||||
{
|
||||
return _userManager ?? HttpContext.GetOwinContext().GetUserManager<ApplicationUserManager>();
|
||||
}
|
||||
private set
|
||||
{
|
||||
_userManager = value;
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// GET: /Manage/Index
|
||||
public async Task<ActionResult> Index(ManageMessageId? message, string affiliatekey)
|
||||
{
|
||||
ViewBag.StatusMessage =
|
||||
message == ManageMessageId.ChangePasswordSuccess ? "Your password has been changed."
|
||||
: message == ManageMessageId.SetPasswordSuccess ? "Your password has been set."
|
||||
: message == ManageMessageId.SetTwoFactorSuccess ? "Your two-factor authentication provider has been set."
|
||||
: message == ManageMessageId.Error ? "An error has occurred."
|
||||
: message == ManageMessageId.AddPhoneSuccess ? "Your phone number was added."
|
||||
: message == ManageMessageId.RemovePhoneSuccess ? "Your phone number was removed."
|
||||
: "";
|
||||
|
||||
var userId = User.Identity.GetUserId();
|
||||
var user = controllerHelper.GetLoggedInUser();
|
||||
var model = new IndexViewModel
|
||||
{
|
||||
FullName = user.FullName,
|
||||
EnableEmailNotifications = user.EnableEmailNotifications,
|
||||
EnableSmsNotifications = user.EnableSmsNotifications,
|
||||
HasPassword = HasPassword(),
|
||||
PhoneNumber = await UserManager.GetPhoneNumberAsync(userId),
|
||||
TwoFactor = await UserManager.GetTwoFactorEnabledAsync(userId),
|
||||
Logins = await UserManager.GetLoginsAsync(userId),
|
||||
BrowserRemembered = await AuthenticationManager.TwoFactorBrowserRememberedAsync(userId),
|
||||
AffiliateSmsCapable = user.Affiliate.IsSmsCapable,
|
||||
AffiliateEnableShowLocation = user.Affiliate.EnableShowLocation,
|
||||
AffiliateEnableShowName = user.Affiliate.EnableShowName,
|
||||
ShouldShowLocation = user.ShouldShowLocation,
|
||||
ShouldShowName = user.ShouldShowName,
|
||||
Location = user.Location
|
||||
};
|
||||
return View(model);
|
||||
}
|
||||
|
||||
[HttpPost]
|
||||
public JsonResult SaveProfile(SaveProfileViewModel model, string affiliatekey)
|
||||
{
|
||||
if (!User.Identity.IsAuthenticated)
|
||||
return Json(false, JsonRequestBehavior.AllowGet);
|
||||
|
||||
var user = controllerHelper.GetLoggedInUser();
|
||||
user.FullName = model.FullName;
|
||||
user.Location = model.Location;
|
||||
user.EnableEmailNotifications = model.EnableEmailNotifications;
|
||||
user.EnableSmsNotifications = model.EnableSmsNotifications;
|
||||
user.ShouldShowName = model.ShouldShowName;
|
||||
user.ShouldShowLocation = model.ShouldShowLocation;
|
||||
|
||||
|
||||
controllerHelper.db.SaveChanges();
|
||||
|
||||
return Json(true, JsonRequestBehavior.AllowGet);
|
||||
}
|
||||
|
||||
//
|
||||
// POST: /Manage/RemoveLogin
|
||||
[HttpPost]
|
||||
[ValidateAntiForgeryToken]
|
||||
public async Task<ActionResult> RemoveLogin(string loginProvider, string providerKey, string affiliatekey)
|
||||
{
|
||||
ManageMessageId? message;
|
||||
var result = await UserManager.RemoveLoginAsync(User.Identity.GetUserId(), new UserLoginInfo(loginProvider, providerKey));
|
||||
if (result.Succeeded)
|
||||
{
|
||||
var user = await UserManager.FindByIdAsync(User.Identity.GetUserId());
|
||||
if (user != null)
|
||||
{
|
||||
await SignInManager.SignInAsync(user, isPersistent: false, rememberBrowser: false);
|
||||
}
|
||||
message = ManageMessageId.RemoveLoginSuccess;
|
||||
}
|
||||
else
|
||||
{
|
||||
message = ManageMessageId.Error;
|
||||
}
|
||||
return RedirectToAction("ManageLogins", new { Message = message, affiliatekey = affiliatekey });
|
||||
}
|
||||
|
||||
//
|
||||
// GET: /Manage/AddPhoneNumber
|
||||
public ActionResult AddPhoneNumber(string affiliatekey)
|
||||
{
|
||||
return View();
|
||||
}
|
||||
|
||||
//
|
||||
// POST: /Manage/AddPhoneNumber
|
||||
[HttpPost]
|
||||
[ValidateAntiForgeryToken]
|
||||
public async Task<ActionResult> AddPhoneNumber(AddPhoneNumberViewModel model, string affiliatekey)
|
||||
{
|
||||
if (!ModelState.IsValid)
|
||||
{
|
||||
return View(model);
|
||||
}
|
||||
// Generate the token and send it
|
||||
var code = await UserManager.GenerateChangePhoneNumberTokenAsync(User.Identity.GetUserId(), model.Number);
|
||||
if (UserManager.SmsService != null)
|
||||
{
|
||||
ServicePointManager.SecurityProtocol |= SecurityProtocolType.Tls11 | SecurityProtocolType.Tls12;
|
||||
var affiliate = controllerHelper.GetAffiliate(affiliatekey);
|
||||
var message = new SmsIdentityMessage
|
||||
{
|
||||
Destination = model.Number,
|
||||
Body = "Your security code is: " + code,
|
||||
TwilioSID = affiliate.TwilioSID,
|
||||
TwilioAuthToken = affiliate.TwilioAuthToken,
|
||||
TwilioPhoneNumber = affiliate.TwilioPhoneNumber
|
||||
};
|
||||
await UserManager.SmsService.SendAsync(message);
|
||||
}
|
||||
return RedirectToAction("VerifyPhoneNumber", new { PhoneNumber = model.Number, affiliatekey = affiliatekey });
|
||||
}
|
||||
|
||||
//
|
||||
// POST: /Manage/EnableTwoFactorAuthentication
|
||||
[HttpPost]
|
||||
[ValidateAntiForgeryToken]
|
||||
public async Task<ActionResult> EnableTwoFactorAuthentication(string affiliatekey)
|
||||
{
|
||||
await UserManager.SetTwoFactorEnabledAsync(User.Identity.GetUserId(), true);
|
||||
var user = await UserManager.FindByIdAsync(User.Identity.GetUserId());
|
||||
if (user != null)
|
||||
{
|
||||
await SignInManager.SignInAsync(user, isPersistent: false, rememberBrowser: false);
|
||||
}
|
||||
return RedirectToAction("Index", "Manage", new { affiliatekey = affiliatekey });
|
||||
}
|
||||
|
||||
//
|
||||
// POST: /Manage/DisableTwoFactorAuthentication
|
||||
[HttpPost]
|
||||
[ValidateAntiForgeryToken]
|
||||
public async Task<ActionResult> DisableTwoFactorAuthentication(string affiliatekey)
|
||||
{
|
||||
await UserManager.SetTwoFactorEnabledAsync(User.Identity.GetUserId(), false);
|
||||
var user = await UserManager.FindByIdAsync(User.Identity.GetUserId());
|
||||
if (user != null)
|
||||
{
|
||||
await SignInManager.SignInAsync(user, isPersistent: false, rememberBrowser: false);
|
||||
}
|
||||
return RedirectToAction("Index", "Manage", new {affiliatekey = affiliatekey });
|
||||
}
|
||||
|
||||
//
|
||||
// GET: /Manage/VerifyPhoneNumber
|
||||
public async Task<ActionResult> VerifyPhoneNumber(string phoneNumber, string affiliatekey)
|
||||
{
|
||||
var code = await UserManager.GenerateChangePhoneNumberTokenAsync(User.Identity.GetUserId(), phoneNumber);
|
||||
|
||||
// Send an SMS through the SMS provider to verify the phone number
|
||||
//controllerHelper.SendSmsMessage(affiliatekey, phoneNumber, code);
|
||||
|
||||
return phoneNumber == null ? View("Error") : View(new VerifyPhoneNumberViewModel { PhoneNumber = phoneNumber });
|
||||
}
|
||||
|
||||
//
|
||||
// POST: /Manage/VerifyPhoneNumber
|
||||
[HttpPost]
|
||||
[ValidateAntiForgeryToken]
|
||||
public async Task<ActionResult> VerifyPhoneNumber(VerifyPhoneNumberViewModel model, string affiliatekey)
|
||||
{
|
||||
if (!ModelState.IsValid)
|
||||
{
|
||||
return View(model);
|
||||
}
|
||||
var result = await UserManager.ChangePhoneNumberAsync(User.Identity.GetUserId(), model.PhoneNumber, model.Code);
|
||||
if (result.Succeeded)
|
||||
{
|
||||
var user = await UserManager.FindByIdAsync(User.Identity.GetUserId());
|
||||
if (user != null)
|
||||
{
|
||||
await SignInManager.SignInAsync(user, isPersistent: false, rememberBrowser: false);
|
||||
}
|
||||
return RedirectToAction("Index", new { Message = ManageMessageId.AddPhoneSuccess, affiliatekey = affiliatekey });
|
||||
}
|
||||
// If we got this far, something failed, redisplay form
|
||||
ModelState.AddModelError("", "Failed to verify phone");
|
||||
return View(model);
|
||||
}
|
||||
|
||||
//
|
||||
// GET: /Manage/RemovePhoneNumber
|
||||
public async Task<ActionResult> RemovePhoneNumber(string affiliatekey)
|
||||
{
|
||||
var result = await UserManager.SetPhoneNumberAsync(User.Identity.GetUserId(), null);
|
||||
if (!result.Succeeded)
|
||||
{
|
||||
return RedirectToAction("Index", new { Message = ManageMessageId.Error, affiliatekey = affiliatekey });
|
||||
}
|
||||
var user = await UserManager.FindByIdAsync(User.Identity.GetUserId());
|
||||
if (user != null)
|
||||
{
|
||||
await SignInManager.SignInAsync(user, isPersistent: false, rememberBrowser: false);
|
||||
}
|
||||
return RedirectToAction("Index", new { Message = ManageMessageId.RemovePhoneSuccess, affiliatekey = affiliatekey });
|
||||
}
|
||||
|
||||
//
|
||||
// GET: /Manage/ChangePassword
|
||||
public ActionResult ChangePassword(string affiliatekey)
|
||||
{
|
||||
return View();
|
||||
}
|
||||
|
||||
//
|
||||
// POST: /Manage/ChangePassword
|
||||
[HttpPost]
|
||||
[ValidateAntiForgeryToken]
|
||||
public async Task<ActionResult> ChangePassword(ChangePasswordViewModel model, string affiliatekey)
|
||||
{
|
||||
if (!ModelState.IsValid)
|
||||
{
|
||||
return View(model);
|
||||
}
|
||||
var result = await UserManager.ChangePasswordAsync(User.Identity.GetUserId(), model.OldPassword, model.NewPassword);
|
||||
if (result.Succeeded)
|
||||
{
|
||||
var user = await UserManager.FindByIdAsync(User.Identity.GetUserId());
|
||||
if (user != null)
|
||||
{
|
||||
await SignInManager.SignInAsync(user, isPersistent: false, rememberBrowser: false);
|
||||
}
|
||||
return RedirectToAction("Index", new { Message = ManageMessageId.ChangePasswordSuccess, affiliatekey = affiliatekey });
|
||||
}
|
||||
AddErrors(result);
|
||||
return View(model);
|
||||
}
|
||||
|
||||
//
|
||||
// GET: /Manage/SetPassword
|
||||
public ActionResult SetPassword(string affiliatekey)
|
||||
{
|
||||
return View();
|
||||
}
|
||||
|
||||
//
|
||||
// POST: /Manage/SetPassword
|
||||
[HttpPost]
|
||||
[ValidateAntiForgeryToken]
|
||||
public async Task<ActionResult> SetPassword(SetPasswordViewModel model, string affiliatekey)
|
||||
{
|
||||
if (ModelState.IsValid)
|
||||
{
|
||||
var result = await UserManager.AddPasswordAsync(User.Identity.GetUserId(), model.NewPassword);
|
||||
if (result.Succeeded)
|
||||
{
|
||||
var user = await UserManager.FindByIdAsync(User.Identity.GetUserId());
|
||||
if (user != null)
|
||||
{
|
||||
await SignInManager.SignInAsync(user, isPersistent: false, rememberBrowser: false);
|
||||
}
|
||||
return RedirectToAction("Index", new { Message = ManageMessageId.SetPasswordSuccess, affiliatekey = affiliatekey });
|
||||
}
|
||||
AddErrors(result);
|
||||
}
|
||||
|
||||
// If we got this far, something failed, redisplay form
|
||||
return View(model);
|
||||
}
|
||||
|
||||
//
|
||||
// GET: /Manage/ManageLogins
|
||||
public async Task<ActionResult> ManageLogins(ManageMessageId? message, string affiliatekey)
|
||||
{
|
||||
ViewBag.StatusMessage =
|
||||
message == ManageMessageId.RemoveLoginSuccess ? "The external login was removed."
|
||||
: message == ManageMessageId.Error ? "An error has occurred."
|
||||
: "";
|
||||
var user = await UserManager.FindByIdAsync(User.Identity.GetUserId());
|
||||
if (user == null)
|
||||
{
|
||||
return View("Error");
|
||||
}
|
||||
var userLogins = await UserManager.GetLoginsAsync(User.Identity.GetUserId());
|
||||
var otherLogins = AuthenticationManager.GetExternalAuthenticationTypes().Where(auth => userLogins.All(ul => auth.AuthenticationType != ul.LoginProvider)).ToList();
|
||||
ViewBag.ShowRemoveButton = user.PasswordHash != null || userLogins.Count > 1;
|
||||
return View(new ManageLoginsViewModel
|
||||
{
|
||||
CurrentLogins = userLogins,
|
||||
OtherLogins = otherLogins
|
||||
});
|
||||
}
|
||||
|
||||
//
|
||||
// POST: /Manage/LinkLogin
|
||||
[HttpPost]
|
||||
[ValidateAntiForgeryToken]
|
||||
public ActionResult LinkLogin(string provider, string affiliatekey)
|
||||
{
|
||||
// Request a redirect to the external login provider to link a login for the current user
|
||||
return new AccountController.ChallengeResult(provider, Url.Action("LinkLoginCallback", "Manage", new {affiliatekey = affiliatekey}), User.Identity.GetUserId());
|
||||
}
|
||||
|
||||
//
|
||||
// GET: /Manage/LinkLoginCallback
|
||||
public async Task<ActionResult> LinkLoginCallback(string affiliatekey)
|
||||
{
|
||||
var loginInfo = await AuthenticationManager.GetExternalLoginInfoAsync(XsrfKey, User.Identity.GetUserId());
|
||||
if (loginInfo == null)
|
||||
{
|
||||
return RedirectToAction("ManageLogins", new { Message = ManageMessageId.Error, affiliatekey = affiliatekey });
|
||||
}
|
||||
var result = await UserManager.AddLoginAsync(User.Identity.GetUserId(), loginInfo.Login);
|
||||
return result.Succeeded ? RedirectToAction("ManageLogins", new { affiliatekey = affiliatekey }) : RedirectToAction("ManageLogins", new { Message = ManageMessageId.Error, affiliatekey = affiliatekey });
|
||||
}
|
||||
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing && _userManager != null)
|
||||
{
|
||||
_userManager.Dispose();
|
||||
_userManager = null;
|
||||
}
|
||||
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
|
||||
#region Helpers
|
||||
// Used for XSRF protection when adding external logins
|
||||
private const string XsrfKey = "XsrfId";
|
||||
|
||||
private IAuthenticationManager AuthenticationManager
|
||||
{
|
||||
get
|
||||
{
|
||||
return HttpContext.GetOwinContext().Authentication;
|
||||
}
|
||||
}
|
||||
|
||||
private void AddErrors(IdentityResult result)
|
||||
{
|
||||
foreach (var error in result.Errors)
|
||||
{
|
||||
ModelState.AddModelError("", error);
|
||||
}
|
||||
}
|
||||
|
||||
private bool HasPassword()
|
||||
{
|
||||
var user = UserManager.FindById(User.Identity.GetUserId());
|
||||
if (user != null)
|
||||
{
|
||||
return user.PasswordHash != null;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private bool HasPhoneNumber()
|
||||
{
|
||||
var user = UserManager.FindById(User.Identity.GetUserId());
|
||||
if (user != null)
|
||||
{
|
||||
return user.PhoneNumber != null;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public enum ManageMessageId
|
||||
{
|
||||
AddPhoneSuccess,
|
||||
ChangePasswordSuccess,
|
||||
SetTwoFactorSuccess,
|
||||
SetPasswordSuccess,
|
||||
RemoveLoginSuccess,
|
||||
RemovePhoneSuccess,
|
||||
Error
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
366
Amen/Controllers/NotificationController.cs
Normal file
@ -0,0 +1,366 @@
|
||||
using Amen.Models;
|
||||
using System;
|
||||
using System.Configuration;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Net.Http;
|
||||
using System.Net.Mail;
|
||||
using System.Web.Mvc;
|
||||
using System.Web.Routing;
|
||||
using System.Xml;
|
||||
using Twilio;
|
||||
|
||||
namespace Amen.Controllers
|
||||
{
|
||||
public class NotificationController : BaseController
|
||||
{
|
||||
|
||||
public enum EmailSendType
|
||||
{
|
||||
Account,
|
||||
Notify
|
||||
}
|
||||
|
||||
public ActionResult PreviewPrayed(int id)
|
||||
{
|
||||
var prayer = controllerHelper.db.Prayers.Include("Affiliate").FirstOrDefault(i => i.Id == id);
|
||||
var model = new PrayerEmailViewModel()
|
||||
{
|
||||
To = "",
|
||||
Subject = "",
|
||||
Title = prayer.Summary,
|
||||
DetailUrl = controllerHelper.Absolute(this.Url, Url.Action("Detail", "Prayer", new { id = prayer.Id, affiliatekey = prayer.Affiliate.Key })),
|
||||
ManageUrl = controllerHelper.Absolute(this.Url, Url.Action("Index", "Manage", new { affiliatekey = prayer.Affiliate.Key }))
|
||||
};
|
||||
ViewBag.LogoUrl = controllerHelper.Absolute(this.Url, Url.Content("~/Content/Images/amen-logo-flyin.gif"));
|
||||
|
||||
return View("~/Views/Email/Prayed.cshtml", model);
|
||||
}
|
||||
|
||||
public ActionResult PreviewPrayerSubmitted(int id)
|
||||
{
|
||||
var prayer = controllerHelper.db.Prayers.Include("Affiliate").FirstOrDefault(i => i.Id == id);
|
||||
var model = new PrayerEmailViewModel()
|
||||
{
|
||||
To = "",
|
||||
Subject = "",
|
||||
Title = prayer.Summary,
|
||||
DetailUrl = controllerHelper.Absolute(this.Url, Url.Action("Detail", "Prayer", new { id = prayer.Id, affiliatekey = prayer.Affiliate.Key })),
|
||||
ManageUrl = controllerHelper.Absolute(this.Url, Url.Action("Index", "Manage", new { affiliatekey = prayer.Affiliate.Key }))
|
||||
};
|
||||
ViewBag.LogoUrl = controllerHelper.Absolute(this.Url, Url.Content("~/Content/Images/amen-logo-flyin.gif"));
|
||||
|
||||
return View("~/Views/Email/PrayerSubmitted.cshtml", model);
|
||||
}
|
||||
|
||||
|
||||
public ActionResult PreviewNoteSent(int id)
|
||||
{
|
||||
var prayer = controllerHelper.db.Prayers.Include("Affiliate").FirstOrDefault(i => i.Id == id);
|
||||
var model = new PrayerEmailViewModel()
|
||||
{
|
||||
To = "",
|
||||
Subject = "",
|
||||
Title = prayer.Summary,
|
||||
NoteText = "This is preview text for the note of encouragement",
|
||||
DetailUrl = controllerHelper.Absolute(this.Url, Url.Action("Detail", "Prayer", new { id = prayer.Id, affiliatekey = prayer.Affiliate.Key })),
|
||||
ManageUrl = controllerHelper.Absolute(this.Url, Url.Action("Index", "Manage", new { affiliatekey = prayer.Affiliate.Key }))
|
||||
};
|
||||
ViewBag.LogoUrl = controllerHelper.Absolute(this.Url, Url.Content("~/Content/Images/amen-logo-flyin.gif"));
|
||||
|
||||
return View("~/Views/Email/NoteSent.cshtml", model);
|
||||
}
|
||||
|
||||
|
||||
public ActionResult PreviewAdminNotification(int id)
|
||||
{
|
||||
var prayer = controllerHelper.db.Prayers.Include("Affiliate").FirstOrDefault(i => i.Id == id);
|
||||
var model = new AdminEmailViewModel()
|
||||
{
|
||||
To = "",
|
||||
Subject = "",
|
||||
PrayerTitle = prayer.Summary,
|
||||
PrayerContent = prayer.Content,
|
||||
DetailUrl = controllerHelper.Absolute(this.Url, Url.Action("Detail", "Prayer", new { id = prayer.Id, affiliatekey = prayer.Affiliate.Key, isPraise = prayer.IsPraise })),
|
||||
ManageUrl = controllerHelper.Absolute(this.Url, Url.Action("Index", "Group", new { affiliatekey = prayer.Affiliate.Key })),
|
||||
NotificationTypeMessage = string.Format("A new {0} has been submitted.", prayer.IsPraise ? "Praise" : "Prayer")
|
||||
};
|
||||
ViewBag.LogoUrl = controllerHelper.Absolute(this.Url, Url.Content("~/Content/Images/amen-logo-flyin.gif"));
|
||||
|
||||
return View("~/Views/Email/AdminNotification.cshtml", model);
|
||||
}
|
||||
|
||||
public static void SendSmsMessage(string twilioSID, string twilioAuthToken, string twilioPhoneNumber, string phoneNumber, string message)
|
||||
{
|
||||
var overrideToNumber = ConfigurationManager.AppSettings["SmsOverrideToNumber"];
|
||||
if (!string.IsNullOrEmpty(overrideToNumber))
|
||||
phoneNumber = overrideToNumber;
|
||||
|
||||
if (string.IsNullOrEmpty(twilioSID) || string.IsNullOrEmpty(twilioAuthToken) || string.IsNullOrEmpty(twilioPhoneNumber) || string.IsNullOrEmpty(phoneNumber) || string.IsNullOrEmpty(message))
|
||||
return;
|
||||
|
||||
try
|
||||
{
|
||||
ServicePointManager.SecurityProtocol |= SecurityProtocolType.Tls11 | SecurityProtocolType.Tls12;
|
||||
var twilio = new TwilioRestClient(twilioSID, twilioAuthToken);
|
||||
var msg = twilio.SendMessage(twilioPhoneNumber, phoneNumber, message);
|
||||
|
||||
//TODO: log success
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
//TODO: log failure
|
||||
}
|
||||
}
|
||||
|
||||
public static void SendEmailMessage(string to, string subject, string body, EmailSendType sendType = EmailSendType.Notify)
|
||||
{
|
||||
var overrideToAddress = ConfigurationManager.AppSettings["EmailOverrideToAddress"];
|
||||
if (!string.IsNullOrEmpty(overrideToAddress))
|
||||
to = overrideToAddress;
|
||||
|
||||
//sender info
|
||||
var from = ConfigurationManager.AppSettings[sendType.ToString() + "EmailFromAccount"];
|
||||
var fromName = ConfigurationManager.AppSettings[sendType.ToString() + "EmailFromAccountName"];
|
||||
//var password = ConfigurationManager.AppSettings[sendType.ToString() + "EmailFromPassword"];
|
||||
|
||||
//mail server
|
||||
var smtpServer = ConfigurationManager.AppSettings["EmailServer"];
|
||||
int smtpPort = 587;
|
||||
int.TryParse(ConfigurationManager.AppSettings["EmailServerPort"] ?? "587", out smtpPort);
|
||||
bool smtpEnableSsl = false;
|
||||
bool.TryParse(ConfigurationManager.AppSettings["EmailServerEnableSsl"], out smtpEnableSsl);
|
||||
var smtpUsername = ConfigurationManager.AppSettings["EmailServerUsername"];
|
||||
var smtpPassword = ConfigurationManager.AppSettings["EmailServerPassword"];
|
||||
|
||||
try
|
||||
{
|
||||
var client = new SmtpClient(smtpServer, smtpPort)
|
||||
{
|
||||
Credentials = new NetworkCredential(smtpUsername, smtpPassword),
|
||||
EnableSsl = smtpEnableSsl
|
||||
};
|
||||
var message = new MailMessage(from, to, subject, body);
|
||||
message.From = new MailAddress(from, fromName);
|
||||
message.IsBodyHtml = true;
|
||||
client.Send(message);
|
||||
|
||||
//TODO: log success
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
//TODO: log failure
|
||||
}
|
||||
}
|
||||
|
||||
static bool CanSendText(Affiliate affiliate, ApplicationUser appUser, Prayer prayer)
|
||||
{
|
||||
//if we don't have what we need then return
|
||||
if (affiliate == null || appUser == null || prayer == null)
|
||||
return false;
|
||||
|
||||
//if user opted not to recieve text notifications then return
|
||||
if (!appUser.IsSmsCapable || !prayer.EnableTextNotification || !affiliate.IsSmsCapable)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool CanSendEmail(Affiliate affiliate, ref ApplicationUser appUser, Prayer prayer, bool noteCheck = false, bool submitCheck = false)
|
||||
{
|
||||
//if we don't have what we need then return
|
||||
if (affiliate == null || prayer == null)
|
||||
return false;
|
||||
|
||||
if (appUser == null)
|
||||
{
|
||||
// log in is no longer required
|
||||
//if (!affiliate.RequireLoginForNoticiations)
|
||||
//{
|
||||
//if login not required, then set the user with anonymous email and name
|
||||
appUser = new ApplicationUser()
|
||||
{
|
||||
Email = prayer.AnonymousEmail,
|
||||
PhoneNumber = prayer.AnonymousPhone,
|
||||
FullName = prayer.AnonymousName,
|
||||
EnableEmailNotifications = true
|
||||
};
|
||||
//}
|
||||
//else
|
||||
//{
|
||||
// return false;
|
||||
//}
|
||||
}
|
||||
|
||||
//this indicates that someone submitted a prayer, so we should check if the user allows notifications, and then send them an email regarless of whether they sellected to allow prayed for notifications
|
||||
if (appUser.EnableEmailNotifications && submitCheck)
|
||||
return true;
|
||||
|
||||
//if doing a noteCheck, then ignore the prayer.EnableEmailNotification flag as they explicitly chose to allow notes of encouragement but not necessarily to be notified when someone prays.
|
||||
if (appUser.EnableEmailNotifications && noteCheck && prayer.EnableEmailNote)
|
||||
return true;
|
||||
|
||||
//if user opted not to recieve notifications then return
|
||||
if (!appUser.EnableEmailNotifications || !prayer.EnableEmailNotification)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static BaseController GetBaseController(Affiliate affiliate)
|
||||
{
|
||||
var routeData = new RouteData();
|
||||
routeData.Values.Add("affiliatekey", affiliate.Key);
|
||||
|
||||
return ControllerHelper.CreateController<BaseController>(routeData);
|
||||
}
|
||||
|
||||
public static void NotifyPrayerRequest(UrlHelper urlHelper, Affiliate affiliate, ApplicationUser appUser, Prayer prayer)
|
||||
{
|
||||
var controller = GetBaseController(affiliate);
|
||||
controller.ViewBag.LogoUrl = controller.controllerHelper.Absolute(urlHelper, urlHelper.Content("~/Content/Images/amen-logo-flyin.gif"));
|
||||
var model = new PrayerEmailViewModel();
|
||||
model.Title = prayer.Summary;
|
||||
model.Subject = "We are praying for you!";
|
||||
if (appUser != null)
|
||||
{
|
||||
model.To = appUser.Email;
|
||||
}
|
||||
else
|
||||
{
|
||||
model.To = prayer.AnonymousEmail;
|
||||
}
|
||||
model.DetailUrl = controller.controllerHelper.Absolute(urlHelper, urlHelper.Action("Detail", "Prayer", new { id = prayer.Id, affiliatekey = affiliate.Key }));
|
||||
model.ManageUrl = controller.controllerHelper.Absolute(urlHelper, urlHelper.Action("Index", "Manage", new { affiliatekey = affiliate.Key }));
|
||||
model.IsUserLoggedIn = !string.IsNullOrEmpty(prayer.ApplicationUserId);
|
||||
model.IsPraise = prayer.IsPraise;
|
||||
|
||||
if (CanSendEmail(affiliate, ref appUser, prayer, false, true))
|
||||
{
|
||||
if (prayer.ContactPreference == "email" || prayer.ContactPreference == "any")
|
||||
{
|
||||
var body = ControllerHelper.RenderViewToString(controller.ControllerContext, "~/Views/Email/PrayerSubmitted.cshtml", model);
|
||||
SendEmailMessage(model.To, model.Subject, body);
|
||||
}
|
||||
}
|
||||
|
||||
if (CanSendText(affiliate, appUser, prayer))
|
||||
{
|
||||
if (prayer.ContactPreference == "phone" || prayer.ContactPreference == "any")
|
||||
{
|
||||
SendSmsMessage(affiliate.TwilioSID, affiliate.TwilioAuthToken, affiliate.TwilioPhoneNumber, appUser.PhoneNumber, string.Format("We are praying for you! {0}", model.DetailUrl));
|
||||
}
|
||||
}
|
||||
|
||||
if (affiliate != null
|
||||
&& !string.IsNullOrEmpty(affiliate.EmailAdmin)
|
||||
&& (
|
||||
(affiliate.ShouldSendPrayerNotificationAdmin && !prayer.IsPraise)
|
||||
||
|
||||
(affiliate.ShouldSendPraiseNotificationAdmin && prayer.IsPraise)
|
||||
)
|
||||
)
|
||||
{
|
||||
var controller2 = GetBaseController(affiliate);
|
||||
controller2.ViewBag.LogoUrl = controller2.controllerHelper.Absolute(urlHelper, urlHelper.Content("~/Content/Images/amen-logo-flyin.gif"));
|
||||
|
||||
var adminModel = new AdminEmailViewModel();
|
||||
|
||||
adminModel.PrayerTitle = prayer.Summary;
|
||||
adminModel.PrayerContent = prayer.Content;
|
||||
adminModel.Subject = string.Format("Admin Notification: {0} Requested", prayer.IsPraise ? "Praise" : "Prayer");
|
||||
adminModel.To = affiliate.EmailAdmin;
|
||||
adminModel.NotificationTypeMessage = string.Format("A new {0} has been submitted.", prayer.IsPraise ? "Praise" : "Prayer");
|
||||
if (affiliate.RequireModeration)
|
||||
{
|
||||
adminModel.NotificationTypeMessage = "** MODERATION REQUIRED ** " + adminModel.NotificationTypeMessage;
|
||||
}
|
||||
adminModel.DetailUrl = controller2.controllerHelper.Absolute(urlHelper, urlHelper.Action("Detail", "Prayer", new { id = prayer.Id, affiliatekey = affiliate.Key, isPraise = prayer.IsPraise }));
|
||||
adminModel.ManageUrl = controller2.controllerHelper.Absolute(urlHelper, urlHelper.Action("Index", "Group"));
|
||||
|
||||
var body = ControllerHelper.RenderViewToString(controller2.ControllerContext, "~/Views/Email/AdminNotification.cshtml", adminModel);
|
||||
|
||||
SendEmailMessage(adminModel.To, adminModel.Subject, body);
|
||||
}
|
||||
}
|
||||
|
||||
public static void NotifyPrayed(UrlHelper urlHelper, Affiliate affiliate, ApplicationUser appUser, Prayer prayer)
|
||||
{
|
||||
var model = new PrayerEmailViewModel();
|
||||
var controller = GetBaseController(affiliate);
|
||||
model.DetailUrl = controller.controllerHelper.Absolute(urlHelper, urlHelper.Action("Detail", "Prayer", new { id = prayer.Id, affiliatekey = affiliate.Key }));
|
||||
model.ManageUrl = controller.controllerHelper.Absolute(urlHelper, urlHelper.Action("Index", "Manage", new { affiliatekey = affiliate.Key }));
|
||||
|
||||
if (CanSendText(affiliate, appUser, prayer))
|
||||
{
|
||||
if (prayer.ContactPreference == "phone" || prayer.ContactPreference == "any")
|
||||
{
|
||||
SendSmsMessage(affiliate.TwilioSID, affiliate.TwilioAuthToken, affiliate.TwilioPhoneNumber, appUser.PhoneNumber, string.Format("Someone just prayed for you! {0}", model.DetailUrl));
|
||||
}
|
||||
}
|
||||
|
||||
if (CanSendEmail(affiliate, ref appUser, prayer))
|
||||
{
|
||||
if (prayer.ContactPreference == "email" || prayer.ContactPreference == "any")
|
||||
{
|
||||
controller.ViewBag.LogoUrl = controller.controllerHelper.Absolute(urlHelper, urlHelper.Content("~/Content/Images/amen-logo-flyin.gif"));
|
||||
|
||||
model.Title = prayer.Summary;
|
||||
model.Subject = !string.IsNullOrEmpty(affiliate.SendMessagePrayed) ? affiliate.SendMessagePrayed : "Someone just prayed for you!";
|
||||
model.To = appUser.Email;
|
||||
|
||||
var body = ControllerHelper.RenderViewToString(controller.ControllerContext, "~/Views/Email/Prayed.cshtml", model);
|
||||
|
||||
SendEmailMessage(model.To, model.Subject, body);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void NotifyNoteSent(UrlHelper urlHelper, Affiliate affiliate, ApplicationUser appUser, Prayer prayer, PrayerNote note)
|
||||
{
|
||||
if (!CanSendEmail(affiliate, ref appUser, prayer, true) || !prayer.EnableEmailNote)
|
||||
return;
|
||||
|
||||
var controller = GetBaseController(affiliate);
|
||||
controller.ViewBag.LogoUrl = controller.controllerHelper.Absolute(urlHelper, urlHelper.Content("~/Content/Images/amen-logo-flyin.gif"));
|
||||
|
||||
var model = new PrayerEmailViewModel();
|
||||
model.Title = prayer.Summary;
|
||||
model.NoteText = note.NoteText;
|
||||
model.Subject = !string.IsNullOrEmpty(affiliate.SendMessagePrayed) ? affiliate.SendMessageNote : "A note from Amen";
|
||||
model.To = appUser.Email;
|
||||
model.DetailUrl = controller.controllerHelper.Absolute(urlHelper, urlHelper.Action("Detail", "Prayer", new { id = prayer.Id, affiliatekey = affiliate.Key }));
|
||||
model.ManageUrl = controller.controllerHelper.Absolute(urlHelper, urlHelper.Action("Index", "Manage", new { affiliatekey = affiliate.Key }));
|
||||
|
||||
var body = ControllerHelper.RenderViewToString(controller.ControllerContext, "~/Views/Email/NoteSent.cshtml", model);
|
||||
|
||||
SendEmailMessage(model.To, model.Subject, body);
|
||||
}
|
||||
|
||||
public static void NotifyPrayerFlagged(UrlHelper urlHelper, Affiliate affiliate, Prayer prayer, PrayerFlag flag)
|
||||
{
|
||||
if (affiliate != null && !string.IsNullOrEmpty(affiliate.EmailFlag))
|
||||
{
|
||||
var controller = GetBaseController(affiliate);
|
||||
controller.ViewBag.LogoUrl = controller.controllerHelper.Absolute(urlHelper, urlHelper.Content("~/Content/Images/amen-logo-flyin.gif"));
|
||||
|
||||
var model = new AdminEmailViewModel();
|
||||
model.NotificationTypeMessage = "Prayer Flagged";
|
||||
model.PrayerTitle = prayer.Summary;
|
||||
if (!string.IsNullOrEmpty(flag.Reason))
|
||||
{
|
||||
model.PrayerContent = "Has been flagged for the following reason: " + flag.Reason;
|
||||
}
|
||||
model.Subject = "An Amen Prayer Has Been Flagged";
|
||||
model.To = affiliate.EmailFlag;
|
||||
model.DetailUrl = controller.controllerHelper.Absolute(urlHelper, urlHelper.Action("Detail", "Prayer", new { id = prayer.Id, affiliatekey = affiliate.Key }));
|
||||
model.ManageUrl = controller.controllerHelper.Absolute(urlHelper, urlHelper.Action("Index", "Group", new { affiliatekey = affiliate.Key }));
|
||||
|
||||
var body = ControllerHelper.RenderViewToString(controller.ControllerContext, "~/Views/Email/AdminNotification.cshtml", model);
|
||||
|
||||
SendEmailMessage(model.To, model.Subject, body);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
682
Amen/Controllers/PrayerController.cs
Normal file
@ -0,0 +1,682 @@
|
||||
using Amen.Models;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Web.Mvc;
|
||||
using Microsoft.AspNet.Identity;
|
||||
using Amen.Helpers;
|
||||
using System.Data.SqlClient;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Net.Http;
|
||||
using System.Net.Http.Headers;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Amen.Controllers
|
||||
{
|
||||
public class PrayerController : BaseController
|
||||
{
|
||||
|
||||
// GET: Prayer
|
||||
public ActionResult Index(string affiliatekey, bool isPraise = false, string sort = "newest")
|
||||
{
|
||||
ViewBag.IsPraise = isPraise;
|
||||
var affiliate = controllerHelper.GetAffiliate(affiliatekey, true);
|
||||
if (!affiliate.IsActive)
|
||||
{
|
||||
ViewBag.ShowInactiveAffiliateMessage = true;
|
||||
affiliate = controllerHelper.GetAffiliate(affiliatekey);
|
||||
}
|
||||
|
||||
if(!affiliate.Key.Equals(affiliatekey, StringComparison.InvariantCultureIgnoreCase))
|
||||
{
|
||||
//TODO: Log this since a different affiliate was requested
|
||||
}
|
||||
|
||||
var user = controllerHelper.GetLoggedInUser();
|
||||
ViewBag.AffiliateKey = affiliate.Key;
|
||||
|
||||
ViewBag.Title = string.Format("{0} {1}", affiliate.Name, isPraise ? "Praise" : "Prayers");
|
||||
|
||||
var model = new PrayersViewModel();
|
||||
model.IsUserAuthenticated = User.Identity.IsAuthenticated;
|
||||
if (model.IsUserAuthenticated)
|
||||
{
|
||||
model.AuthenticatedUserEmail = user.Email;
|
||||
}
|
||||
model.EnableNotifications = true; //model.IsUserAuthenticated || !affiliate.RequireLoginForNoticiations;
|
||||
model.IsAffiliateNotesEnabled = affiliate.EnableNotes;
|
||||
model.IsAffiliateSmsCapable = affiliate.IsSmsCapable;
|
||||
model.IsUserSmsCapable = user != null && user.IsSmsCapable;
|
||||
model.IsPraise = isPraise;
|
||||
model.Prayers = FetchPrayerItems(affiliate.Id, affiliatekey, affiliate.PrayerDaysThreshold, isPraise, 0, sort);
|
||||
model.IsDetail = false;
|
||||
model.Instructions = affiliate.Instructions;
|
||||
model.InstructionsPraise = affiliate.InstructionsPraise;
|
||||
model.InstructionsAddPrayer = affiliate.InstructionsAddPrayer;
|
||||
model.InstructionsAddPraise = affiliate.InstructionsAddPraise;
|
||||
model.InstructionsNote = affiliate.InstructionsNote;
|
||||
|
||||
return View(model);
|
||||
}
|
||||
|
||||
public ActionResult Pray(string affiliatekey, bool isPraise = false, string sort = "newest")
|
||||
{
|
||||
ViewBag.IsPraise = isPraise;
|
||||
var affiliate = controllerHelper.GetAffiliate(affiliatekey);
|
||||
var user = controllerHelper.GetLoggedInUser();
|
||||
ViewBag.Title = string.Format("{0} {1}", affiliate.Name, isPraise ? "Praise" : "Prayers");
|
||||
ViewBag.ShowInactiveAffiliateMessage = !affiliate.Key.Equals(affiliatekey, StringComparison.InvariantCultureIgnoreCase);
|
||||
|
||||
var model = new PrayersViewModel();
|
||||
model.ShouldOpenSubmit = true;
|
||||
model.IsUserAuthenticated = User.Identity.IsAuthenticated;
|
||||
if (model.IsUserAuthenticated)
|
||||
{
|
||||
model.AuthenticatedUserEmail = user.Email;
|
||||
}
|
||||
model.EnableNotifications = true; //model.IsUserAuthenticated || !affiliate.RequireLoginForNoticiations;
|
||||
model.IsAffiliateNotesEnabled = affiliate.EnableNotes;
|
||||
model.IsAffiliateSmsCapable = affiliate.IsSmsCapable;
|
||||
model.IsUserSmsCapable = user != null && user.IsSmsCapable;
|
||||
model.IsPraise = isPraise;
|
||||
model.Prayers = FetchPrayerItems(affiliate.Id, affiliatekey, affiliate.PrayerDaysThreshold, isPraise, 0, sort);
|
||||
model.IsDetail = false;
|
||||
|
||||
return View("Index", model);
|
||||
}
|
||||
|
||||
public ActionResult Detail(int id, string affiliatekey, bool isPraise = false, bool returnToUserPage = false)
|
||||
{
|
||||
var affiliate = controllerHelper.GetAffiliate(affiliatekey);
|
||||
var user = controllerHelper.GetLoggedInUser();
|
||||
|
||||
var model = new PrayersViewModel();
|
||||
model.ShouldReturnToUserPage = returnToUserPage;
|
||||
model.IsDetail = true;
|
||||
model.IsUserAuthenticated = User.Identity.IsAuthenticated;
|
||||
if (model.IsUserAuthenticated)
|
||||
{
|
||||
model.AuthenticatedUserEmail = user.Email;
|
||||
}
|
||||
model.EnableNotifications = true; //model.IsUserAuthenticated || !affiliate.RequireLoginForNoticiations;
|
||||
model.IsAffiliateNotesEnabled = affiliate.EnableNotes;
|
||||
model.IsAffiliateSmsCapable = affiliate.IsSmsCapable;
|
||||
model.IsUserSmsCapable = user != null && user.IsSmsCapable;
|
||||
model.Prayers = FetchPrayerItems(affiliate.Id, affiliatekey, affiliate.PrayerDaysThreshold, isPraise, 0, null, 1, id);
|
||||
|
||||
if (model.Prayers.Count == 1)
|
||||
{
|
||||
model.IsPraise = model.Prayers.First().IsPraise;
|
||||
}
|
||||
else
|
||||
model.IsPraise = false;
|
||||
|
||||
ViewBag.Title = string.Format("{0} {1}", affiliate.Name, model.IsPraise ? "Praise" : "Prayers");
|
||||
|
||||
|
||||
return View("Index", model);
|
||||
}
|
||||
|
||||
public ActionResult PrayerItems(string affiliatekey, bool isPraise = false, int lastPrayerId = 0, string sort = "newest")
|
||||
{
|
||||
var affiliate = controllerHelper.GetAffiliate(affiliatekey);
|
||||
return PartialView("_PrayerItems", FetchPrayerItems(affiliate.Id, affiliatekey, affiliate.PrayerDaysThreshold, isPraise, lastPrayerId, sort));
|
||||
}
|
||||
|
||||
public PartialViewResult EditPrayer(string affiliatekey)
|
||||
{
|
||||
//Thread.Sleep(3000);
|
||||
|
||||
return PartialView("_EditPrayer");
|
||||
}
|
||||
|
||||
public PartialViewResult MyPrayerItems(string affiliatekey, bool isPraise = false, bool isSubmitted = false, bool isBookmarked = false, bool isPrayedFor = false)
|
||||
{
|
||||
var affiliate = controllerHelper.GetAffiliate(affiliatekey);
|
||||
|
||||
var threshold = affiliate.PrayerDaysThreshold;
|
||||
if (isSubmitted || isBookmarked)
|
||||
{
|
||||
threshold = 365;
|
||||
}
|
||||
|
||||
ViewBag.HideAction = true;
|
||||
return PartialView("_PrayerItems", FetchPrayerItems(affiliate.Id, affiliatekey, threshold, isPraise, lastPrayerId: 0, takeCount: int.MaxValue, isSubmitted: isSubmitted, isBookmarked: isBookmarked, isPrayedFor: isPrayedFor));
|
||||
}
|
||||
|
||||
private List<PrayerItemViewModel> FetchPrayerItems(int affiliateId, string affiliatekey, int includeDays, bool isPraise, int lastPrayerId, string sort = "newest", int takeCount = 10, int? prayerId = null, bool isSubmitted = false, bool isBookmarked = false, bool isPrayedFor = false)
|
||||
{
|
||||
//var universalAffiliateId = 1;
|
||||
var appUserId = User.Identity.GetUserId() ?? "none";
|
||||
var affiliate = controllerHelper.GetAffiliate(affiliatekey);
|
||||
|
||||
var offset = controllerHelper.GetTimeZoneOffsetFromClient();
|
||||
var now = DateTime.Now;
|
||||
var dateThreshold = now.AddDays(-includeDays);
|
||||
|
||||
var parms = new List<SqlParameter>();
|
||||
parms.Add(new SqlParameter()
|
||||
{
|
||||
ParameterName = "affiliateId",
|
||||
SqlDbType = System.Data.SqlDbType.Int,
|
||||
Value = affiliateId
|
||||
});
|
||||
parms.Add(new SqlParameter()
|
||||
{
|
||||
ParameterName = "fetchCount",
|
||||
SqlDbType = System.Data.SqlDbType.Int,
|
||||
Value = takeCount
|
||||
});
|
||||
parms.Add(new SqlParameter()
|
||||
{
|
||||
ParameterName = "skipCount",
|
||||
SqlDbType = System.Data.SqlDbType.Int,
|
||||
Value = 0
|
||||
});
|
||||
parms.Add(new SqlParameter()
|
||||
{
|
||||
ParameterName = "days",
|
||||
SqlDbType = System.Data.SqlDbType.Int,
|
||||
Value = includeDays
|
||||
});
|
||||
parms.Add(new SqlParameter()
|
||||
{
|
||||
ParameterName = "userId",
|
||||
SqlDbType = System.Data.SqlDbType.NVarChar,
|
||||
Size = 255,
|
||||
Value = appUserId
|
||||
});
|
||||
parms.Add(new SqlParameter()
|
||||
{
|
||||
ParameterName = "orderBy",
|
||||
SqlDbType = System.Data.SqlDbType.NVarChar,
|
||||
Size = 255,
|
||||
Value = sort ?? "newest"
|
||||
});
|
||||
parms.Add(new SqlParameter()
|
||||
{
|
||||
ParameterName = "skipToPrayerId",
|
||||
SqlDbType = System.Data.SqlDbType.Int,
|
||||
Value = lastPrayerId
|
||||
});
|
||||
parms.Add(new SqlParameter()
|
||||
{
|
||||
ParameterName = "isPraise",
|
||||
SqlDbType = System.Data.SqlDbType.Bit,
|
||||
Value = isPraise
|
||||
});
|
||||
|
||||
if (prayerId.HasValue)
|
||||
parms.Add(new SqlParameter()
|
||||
{
|
||||
ParameterName = "prayerId",
|
||||
SqlDbType = System.Data.SqlDbType.Int,
|
||||
Value = prayerId.Value
|
||||
});
|
||||
else
|
||||
parms.Add(new SqlParameter()
|
||||
{
|
||||
ParameterName = "prayerId",
|
||||
SqlDbType = System.Data.SqlDbType.Int,
|
||||
Value = DBNull.Value
|
||||
});
|
||||
|
||||
parms.Add(new SqlParameter()
|
||||
{
|
||||
ParameterName = "isSubmitted",
|
||||
SqlDbType = System.Data.SqlDbType.Bit,
|
||||
Value = isSubmitted
|
||||
});
|
||||
parms.Add(new SqlParameter()
|
||||
{
|
||||
ParameterName = "isBookmarked",
|
||||
SqlDbType = System.Data.SqlDbType.Bit,
|
||||
Value = isBookmarked
|
||||
});
|
||||
parms.Add(new SqlParameter()
|
||||
{
|
||||
ParameterName = "isPrayedFor",
|
||||
SqlDbType = System.Data.SqlDbType.Bit,
|
||||
Value = isPrayedFor
|
||||
});
|
||||
|
||||
var fetchItems = controllerHelper.db.Database.SqlQuery<PrayerItemViewModel>("GetPrayers @affiliateId, @fetchCount, @skipCount, @days, @userId, @orderBy, @skipToPrayerId, @isPraise, @prayerId, @isSubmitted, @isBookmarked, @isPrayedFor", parms.ToArray()) .ToList();
|
||||
|
||||
foreach (var item in fetchItems)
|
||||
{
|
||||
item.DetailUrl = controllerHelper.Absolute(this.Url, Url.Action("Detail", "Prayer", new { id = item.Id, affiliatekey = affiliatekey }));
|
||||
//item.IsUserAuthenticated = User.Identity.IsAuthenticated;
|
||||
//item.EnableNotifications = item.IsUserAuthenticated || !affiliate.RequireLoginForNoticiations;
|
||||
item.IsAffiliateNotesEnabled = affiliate.EnableNotes;
|
||||
item.EnableNotifications = affiliate.EnableNotes;
|
||||
item.OffsetMinutes = offset;
|
||||
|
||||
if (!affiliate.EnableShowName)
|
||||
item.UserName = "";
|
||||
|
||||
if (!affiliate.EnableShowLocation)
|
||||
item.UserLocation = "";
|
||||
}
|
||||
return fetchItems;
|
||||
}
|
||||
|
||||
public JsonResult Subscribe(int prayerId, string affiliatekey)
|
||||
{
|
||||
var userIdentity = this.User.Identity.GetUserId();
|
||||
if (string.IsNullOrEmpty(userIdentity))
|
||||
return Json(false, JsonRequestBehavior.AllowGet);
|
||||
|
||||
var subscription = controllerHelper.db.PrayerSubscriptions.FirstOrDefault(i => i.PrayerId == prayerId && i.ApplicationUserId == userIdentity);
|
||||
|
||||
if (subscription == null)
|
||||
{
|
||||
controllerHelper.db.PrayerSubscriptions.Add(new PrayerSubscription()
|
||||
{
|
||||
ApplicationUserId = userIdentity,
|
||||
PrayerId = prayerId,
|
||||
CreatedUTC = DateTime.UtcNow
|
||||
});
|
||||
controllerHelper.db.SaveChanges();
|
||||
}
|
||||
|
||||
return Json(true, JsonRequestBehavior.AllowGet);
|
||||
}
|
||||
|
||||
public JsonResult Unsubscribe(int prayerId, string affiliatekey)
|
||||
{
|
||||
var userIdentity = this.User.Identity.GetUserId();
|
||||
if (string.IsNullOrEmpty(userIdentity))
|
||||
return Json(false, JsonRequestBehavior.AllowGet);
|
||||
|
||||
var subscription = controllerHelper.db.PrayerSubscriptions.FirstOrDefault(i => i.PrayerId == prayerId && i.ApplicationUserId == userIdentity);
|
||||
|
||||
if (subscription != null)
|
||||
{
|
||||
controllerHelper.db.PrayerSubscriptions.Remove(subscription);
|
||||
controllerHelper.db.SaveChanges();
|
||||
}
|
||||
|
||||
return Json(true, JsonRequestBehavior.AllowGet);
|
||||
}
|
||||
|
||||
public JsonResult Bookmark(int prayerId, string affiliatekey)
|
||||
{
|
||||
var userIdentity = this.User.Identity.GetUserId();
|
||||
if (string.IsNullOrEmpty(userIdentity))
|
||||
return Json(false, JsonRequestBehavior.AllowGet);
|
||||
|
||||
var bookmark = controllerHelper.db.PrayerBookmarks.FirstOrDefault(i => i.PrayerId == prayerId && i.ApplicationUserId == userIdentity);
|
||||
|
||||
if (bookmark == null)
|
||||
{
|
||||
controllerHelper.db.PrayerBookmarks.Add(new PrayerBookmark()
|
||||
{
|
||||
ApplicationUserId = userIdentity,
|
||||
PrayerId = prayerId,
|
||||
CreatedUTC = DateTime.UtcNow
|
||||
});
|
||||
controllerHelper.db.SaveChanges();
|
||||
}
|
||||
|
||||
return Json(true, JsonRequestBehavior.AllowGet);
|
||||
}
|
||||
|
||||
public JsonResult RemoveBookmark(int prayerId, string affiliatekey)
|
||||
{
|
||||
var userIdentity = this.User.Identity.GetUserId();
|
||||
if (string.IsNullOrEmpty(userIdentity))
|
||||
return Json(false, JsonRequestBehavior.AllowGet);
|
||||
|
||||
var bookmark = controllerHelper.db.PrayerBookmarks.FirstOrDefault(i => i.PrayerId == prayerId && i.ApplicationUserId == userIdentity);
|
||||
|
||||
if (bookmark != null)
|
||||
{
|
||||
controllerHelper.db.PrayerBookmarks.Remove(bookmark);
|
||||
controllerHelper.db.SaveChanges();
|
||||
}
|
||||
|
||||
return Json(true, JsonRequestBehavior.AllowGet);
|
||||
}
|
||||
|
||||
|
||||
public JsonResult Prayed(int prayerId, string affiliatekey)
|
||||
{
|
||||
var prayer = controllerHelper.db.Prayers.Include("ApplicationUser").FirstOrDefault(i => i.Id == prayerId && i.IsActive && !i.IsDeleted);
|
||||
|
||||
if (prayer == null)
|
||||
return Json(false, JsonRequestBehavior.AllowGet);
|
||||
|
||||
var user = controllerHelper.GetLoggedInUser();
|
||||
var ipAddress = RequestHelper.GetClientIpAddress(this.Request);
|
||||
var userAgent = this.Request.UserAgent ?? "";
|
||||
|
||||
controllerHelper.db.PrayerItems.Add(new PrayerItem()
|
||||
{
|
||||
PrayerId = prayerId,
|
||||
ApplicationUserId = user != null ? user.Id : null,
|
||||
CreatedUTC = DateTime.UtcNow,
|
||||
IPAddress = ipAddress,
|
||||
UserAgent = userAgent
|
||||
});
|
||||
|
||||
controllerHelper.db.SaveChanges();
|
||||
|
||||
var dbPrayedCount = controllerHelper.db.PrayerItems.Count(i => i.PrayerId == prayerId);
|
||||
prayer.CountPrayed = Math.Max(prayer.CountPrayed + 1, dbPrayedCount);
|
||||
controllerHelper.db.SaveChanges();
|
||||
|
||||
var affiliate = controllerHelper.GetAffiliate(affiliatekey);
|
||||
|
||||
NotificationController.NotifyPrayed(this.Url, affiliate, prayer.ApplicationUser, prayer);
|
||||
|
||||
var data = new
|
||||
{
|
||||
id = prayer.Id,
|
||||
count = prayer.CountPrayed
|
||||
};
|
||||
|
||||
return Json(data, JsonRequestBehavior.AllowGet);
|
||||
}
|
||||
|
||||
public JsonResult SendNote(int prayerId, string content, string affiliatekey)
|
||||
{
|
||||
var prayer = controllerHelper.db.Prayers.Include("ApplicationUser").FirstOrDefault(i => i.Id == prayerId && i.IsActive && !i.IsDeleted);
|
||||
|
||||
if (prayer == null)
|
||||
return Json(new { success = false, message = "Prayer doesn't exist." }, JsonRequestBehavior.AllowGet);
|
||||
|
||||
var user = controllerHelper.GetLoggedInUser();
|
||||
var ipAddress = RequestHelper.GetClientIpAddress(this.Request);
|
||||
var userAgent = this.Request.UserAgent ?? "";
|
||||
|
||||
var validationMessage = "";
|
||||
if (!ValidatePrayerSubmission(affiliatekey, "note of encouragement", content, "", ipAddress, out validationMessage))
|
||||
{
|
||||
return Json(new { success = false, message = validationMessage }, JsonRequestBehavior.AllowGet);
|
||||
}
|
||||
|
||||
var note = controllerHelper.db.PrayerNotes.Add(new PrayerNote()
|
||||
{
|
||||
PrayerId = prayerId,
|
||||
ApplicationUserId = user != null ? user.Id : null,
|
||||
NoteText = content,
|
||||
CreatedUTC = DateTime.UtcNow,
|
||||
IPAddress = ipAddress,
|
||||
UserAgent = userAgent
|
||||
});
|
||||
|
||||
controllerHelper.db.SaveChanges();
|
||||
|
||||
var affiliate = controllerHelper.GetAffiliate(affiliatekey);
|
||||
NotificationController.NotifyNoteSent(this.Url, affiliate, prayer.ApplicationUser, prayer, note);
|
||||
|
||||
return Json(new { success = true, message = "" }, JsonRequestBehavior.AllowGet);
|
||||
}
|
||||
|
||||
public JsonResult Flag(int prayerId, string reason, string name, string email, string affiliatekey)
|
||||
{
|
||||
var prayer = controllerHelper.db.Prayers.FirstOrDefault(i => i.Id == prayerId && i.IsActive && !i.IsDeleted);
|
||||
|
||||
if (prayer != null)
|
||||
{
|
||||
var user = controllerHelper.GetLoggedInUser();
|
||||
string userid = null;
|
||||
if (user != null)
|
||||
{
|
||||
userid = user.Id;
|
||||
name = user.UserName;
|
||||
email = user.Email;
|
||||
}
|
||||
|
||||
var flag = new PrayerFlag()
|
||||
{
|
||||
PrayerId = prayerId,
|
||||
ApplicationUserId = userid,
|
||||
Reason = reason,
|
||||
AnonymousName = name,
|
||||
AnonymousEmail = email,
|
||||
CreatedUTC = DateTime.UtcNow
|
||||
};
|
||||
|
||||
controllerHelper.db.PrayerFlags.Add(flag);
|
||||
controllerHelper.db.SaveChanges();
|
||||
|
||||
var dbFlagCount = controllerHelper.db.PrayerFlags.Count(i => i.PrayerId == prayerId);
|
||||
prayer.CountFlagged = Math.Max(prayer.CountFlagged + 1, dbFlagCount);
|
||||
controllerHelper.db.SaveChanges();
|
||||
|
||||
var affiliate = controllerHelper.GetAffiliate(affiliatekey);
|
||||
NotificationController.NotifyPrayerFlagged(this.Url, affiliate, prayer, flag);
|
||||
|
||||
var data = new
|
||||
{
|
||||
id = prayer.Id,
|
||||
hide = prayer.CountFlagged >= affiliate.FlagThreshold
|
||||
};
|
||||
|
||||
return Json(data, JsonRequestBehavior.AllowGet);
|
||||
}
|
||||
else
|
||||
{
|
||||
return Json(false, JsonRequestBehavior.AllowGet);
|
||||
}
|
||||
}
|
||||
|
||||
public bool Delete(int id, string affiliatekey)
|
||||
{
|
||||
if (!User.Identity.IsAuthenticated)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
var prayer = controllerHelper.db.Prayers.Include("Affiliate").FirstOrDefault(i => i.Id == id);
|
||||
var userIdentity = User.Identity.GetUserId();
|
||||
|
||||
if (prayer.ApplicationUserId != userIdentity)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
prayer.IsDeleted = true;
|
||||
prayer.ModifiedUTC = DateTime.UtcNow;
|
||||
controllerHelper.db.SaveChanges();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private bool ValidatePrayerSubmission(string affiliatekey, string subject, string content, string emailAddress, string ipAddress, out string message)
|
||||
{
|
||||
message = "";
|
||||
if (string.IsNullOrEmpty(subject) || string.IsNullOrEmpty(content))
|
||||
{
|
||||
message = "Prayer Request cannot be empty";
|
||||
return false;
|
||||
}
|
||||
|
||||
emailAddress = (emailAddress ?? "").Trim();
|
||||
ipAddress = (ipAddress ?? "").Trim();
|
||||
|
||||
var affiliate = controllerHelper.db.Affiliates.Include("BlacklistEmails").Include("BlacklistIPs").Include("AutoFlagItems").FirstOrDefault(i => i.Key == affiliatekey && i.IsActive);
|
||||
|
||||
if (affiliate == null)
|
||||
{
|
||||
affiliate = controllerHelper.db.Affiliates.Include("BlacklistEmails").Include("BlacklistIPs").Include("AutoFlagItems").FirstOrDefault(i => i.Key.Equals(ControllerHelper.DefaultAffiliateKey, StringComparison.InvariantCultureIgnoreCase));
|
||||
}
|
||||
|
||||
//ensure not a blacklist email address
|
||||
if (affiliate.BlacklistEmails.Count(i => i.Email.Equals(emailAddress, StringComparison.InvariantCultureIgnoreCase)) > 0)
|
||||
{
|
||||
message = "Email address has been blocked";
|
||||
return false;
|
||||
}
|
||||
|
||||
//ensure not a blacklist ip address
|
||||
if (affiliate.BlacklistIPs.Count(i => i.IP.Equals(ipAddress, StringComparison.InvariantCultureIgnoreCase)) > 0)
|
||||
{
|
||||
message = "IP address has been blocked";
|
||||
return false;
|
||||
}
|
||||
|
||||
if (affiliate.AutoFlagItems.Count > 0)
|
||||
{
|
||||
subject = subject.StripPunctuation().ToLower();
|
||||
content = content.StripPunctuation().ToLower();
|
||||
|
||||
var flagWords = @"\b(" + string.Join("|", affiliate.AutoFlagItems.Select(i => i.Text.ToLower()).ToArray()) + @")\b";
|
||||
var subjectMatch = Regex.IsMatch(subject, flagWords);
|
||||
var contentMatch = Regex.IsMatch(content, flagWords);
|
||||
|
||||
if (contentMatch || subjectMatch)
|
||||
{
|
||||
message = "Title or Content contains inappropriate word or phrase.";
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public JsonResult Edit(PrayerEditViewModel model, string affiliatekey)
|
||||
{
|
||||
var user = controllerHelper.GetLoggedInUser();
|
||||
var appUserId = User.Identity.GetUserId() ?? "none";
|
||||
var ipAddress = RequestHelper.GetClientIpAddress(this.Request);
|
||||
var userAgent = this.Request.UserAgent ?? "";
|
||||
|
||||
var email = model.AnonymousEmail ?? "none";
|
||||
var phone = model.AnonymousPhone ?? "none";
|
||||
|
||||
if (user != null)
|
||||
{
|
||||
email = user.Email ?? email;
|
||||
phone = user.PhoneNumber ?? phone;
|
||||
}
|
||||
|
||||
//if (User.Identity.IsAuthenticated)
|
||||
//{
|
||||
// model.AnonymousName = null;
|
||||
// model.AnonymousEmail = null;
|
||||
//}
|
||||
|
||||
model.ContactPreference = model.ContactPreference ?? "email";
|
||||
|
||||
var validationMessage = "";
|
||||
if (!ValidatePrayerSubmission(affiliatekey, model.Summary, model.Content, email, ipAddress, out validationMessage))
|
||||
{
|
||||
return Json(new { success = false, message = validationMessage }, JsonRequestBehavior.AllowGet);
|
||||
}
|
||||
|
||||
var prayer = controllerHelper.db.Prayers.FirstOrDefault(i => i.Id == model.Id && i.IsActive && !i.IsDeleted && i.ApplicationUserId == appUserId);
|
||||
|
||||
if (model.IsNew)
|
||||
{
|
||||
var affiliate = controllerHelper.GetAffiliate(affiliatekey);
|
||||
prayer = controllerHelper.db.Prayers.Add(new Prayer()
|
||||
{
|
||||
AffiliateId = affiliate.Id,
|
||||
IsPraise = model.IsPraise,
|
||||
CreatedUTC = DateTime.UtcNow,
|
||||
AgreeTermsOfUse = model.AgreeTermsOfUse,
|
||||
IsActive = true,
|
||||
ApplicationUserId = User.Identity.IsAuthenticated ? appUserId : null,
|
||||
EnableEmailNotification = model.EnableEmailNotification,
|
||||
EnableTextNotification = model.EnableTextNotification,
|
||||
EnableEmailNote = model.EnableEmailNote,
|
||||
AnonymousEmail = email,
|
||||
AnonymousPhone = phone,
|
||||
AnonymousName = model.AnonymousName.Trim(),
|
||||
ShareThis = model.ShareThis,
|
||||
ContactPreference = model.ContactPreference,
|
||||
UserAgent = userAgent,
|
||||
IPAddress = ipAddress,
|
||||
PrayerSourceId = PrayerSource.DeterminePrayerSource(userAgent),
|
||||
Summary = model.Summary.Trim(),
|
||||
Content = model.Content.Trim(),
|
||||
ModifiedUTC = DateTime.UtcNow
|
||||
});
|
||||
|
||||
if (!model.IsPraise && affiliate.RequireModeration)
|
||||
{
|
||||
prayer.IsActive = false;
|
||||
}
|
||||
|
||||
controllerHelper.db.SaveChanges();
|
||||
|
||||
//send info to Dataverse for select affiliates
|
||||
//National: 293
|
||||
//West: 356
|
||||
//East: 357
|
||||
//South: 358
|
||||
//Way Nation: 350
|
||||
//KSBJ: 17
|
||||
//NGEN: 19
|
||||
//Vida: 352
|
||||
int[] aryAffliates = { 293, 356, 357, 358, 350, 17, 19, 352, 1 }; //TODO: remove 1, it's for testing
|
||||
if (aryAffliates.Contains(prayer.AffiliateId))
|
||||
{
|
||||
_ = SyncDataverseAsync("add_prayer", prayer.AffiliateId, prayer.Content, prayer.AnonymousName, prayer.AnonymousEmail, prayer.AnonymousPhone);
|
||||
}
|
||||
|
||||
NotificationController.NotifyPrayerRequest(this.Url, affiliate, user, prayer);
|
||||
}
|
||||
|
||||
if (prayer == null)
|
||||
return Json(new { success = false, message = "Prayer does not exist" }, JsonRequestBehavior.AllowGet);
|
||||
|
||||
if (!model.IsNew)
|
||||
{
|
||||
prayer.Summary = model.Summary;
|
||||
prayer.Content = model.Content;
|
||||
|
||||
prayer.EnableEmailNotification = model.EnableEmailNotification;
|
||||
prayer.EnableTextNotification = model.EnableTextNotification;
|
||||
prayer.EnableEmailNote = model.EnableEmailNote;
|
||||
|
||||
prayer.ModifiedUTC = DateTime.UtcNow;
|
||||
|
||||
controllerHelper.db.SaveChanges();
|
||||
}
|
||||
|
||||
return Json(new { success = true, message = "Success" }, JsonRequestBehavior.AllowGet);
|
||||
}
|
||||
|
||||
public async Task SyncDataverseAsync(string task, int affiliateId, string prayer_request, string name, string email, string phone)
|
||||
{
|
||||
// have to get Affiliate name by Id
|
||||
ApplicationDbContext db = new ApplicationDbContext();
|
||||
Affiliate affiliate = db.Affiliates.Find(affiliateId);
|
||||
|
||||
//string APIUrl = "http://localhost:7157/api/AmenDataSync";
|
||||
string APIUrl = "https://amendatasync.azurewebsites.net/api/AmenDataSync";
|
||||
APIUrl += "?task=" + task +
|
||||
"&brand=" + affiliate.Name +
|
||||
"&prayer_request=" + prayer_request +
|
||||
"&name=" + name +
|
||||
"&email=" + email +
|
||||
"&phone=" + phone;
|
||||
|
||||
try
|
||||
{
|
||||
using (var client = new HttpClient())
|
||||
{
|
||||
client.BaseAddress = new Uri(APIUrl);
|
||||
client.DefaultRequestHeaders.Accept.Clear();
|
||||
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
|
||||
HttpResponseMessage response = await client.GetAsync(APIUrl);
|
||||
//var result = client.GetAsync(APIUrl).Result;
|
||||
|
||||
if (response.IsSuccessStatusCode)
|
||||
{
|
||||
var readTask = response.Content.ReadAsStringAsync().ConfigureAwait(false);
|
||||
var rawResponse = readTask.GetAwaiter().GetResult();
|
||||
}
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
}
|
1
Amen/Global.asax
Normal file
@ -0,0 +1 @@
|
||||
<%@ Application Codebehind="Global.asax.cs" Inherits="Amen.MvcApplication" Language="C#" %>
|
29
Amen/Global.asax.cs
Normal file
@ -0,0 +1,29 @@
|
||||
using Amen.Models;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Data.Entity;
|
||||
using System.Linq;
|
||||
using System.Web;
|
||||
using System.Web.Http;
|
||||
using System.Web.Mvc;
|
||||
using System.Web.Optimization;
|
||||
using System.Web.Routing;
|
||||
|
||||
namespace Amen
|
||||
{
|
||||
public class MvcApplication : System.Web.HttpApplication
|
||||
{
|
||||
protected void Application_Start()
|
||||
{
|
||||
AreaRegistration.RegisterAllAreas();
|
||||
//GlobalConfiguration.Configure(WebApiConfig.Register);
|
||||
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
|
||||
RouteConfig.RegisterRoutes(RouteTable.Routes);
|
||||
BundleConfig.RegisterBundles(BundleTable.Bundles);
|
||||
|
||||
#if DEBUG
|
||||
//Database.SetInitializer(new ApplicationDbContextInitializer());
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
77
Amen/Helpers/BlobStorageHelper.cs
Normal file
@ -0,0 +1,77 @@
|
||||
using Microsoft.WindowsAzure.Storage;
|
||||
using Microsoft.WindowsAzure.Storage.Auth;
|
||||
using Microsoft.WindowsAzure.Storage.Blob;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Configuration;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Web;
|
||||
|
||||
namespace Amen.Helpers
|
||||
{
|
||||
public class BlobStorageHelper
|
||||
{
|
||||
|
||||
//public static string SaveToBlobStorage(string containerName, string blobName, string contentType, byte[] bytes)
|
||||
public static string SaveToBlobStorage(string containerName, string blobName, string contentType, Stream stream)
|
||||
{
|
||||
var accountName = ConfigurationManager.AppSettings["AzureBlobStorageAccount"];
|
||||
var accountKey = ConfigurationManager.AppSettings["AzureBlobStorageAccountKey"];
|
||||
|
||||
CloudStorageAccount storageAccount = new CloudStorageAccount(new StorageCredentials(accountName, accountKey), true);
|
||||
CloudBlobClient cloudBlobClient = storageAccount.CreateCloudBlobClient();
|
||||
CloudBlobContainer container = cloudBlobClient.GetContainerReference(containerName);
|
||||
|
||||
container.CreateIfNotExists();
|
||||
var permission = container.GetPermissions();
|
||||
permission.PublicAccess = BlobContainerPublicAccessType.Container;
|
||||
container.SetPermissions(permission);
|
||||
|
||||
CloudBlockBlob blob = container.GetBlockBlobReference(blobName);
|
||||
|
||||
blob.UploadFromStream(stream);
|
||||
//blob.UploadFromByteArray(bytes, 0, bytes.Length);
|
||||
blob.Properties.ContentType = contentType;
|
||||
blob.SetProperties();
|
||||
|
||||
return blob.Uri.AbsoluteUri;
|
||||
}
|
||||
|
||||
public static string RenameBlobStorageItem(string containerName, string oldBlobName, string newBlobName)
|
||||
{
|
||||
var accountName = ConfigurationManager.AppSettings["AzureBlobStorageAccount"];
|
||||
var accountKey = ConfigurationManager.AppSettings["AzureBlobStorageAccountKey"];
|
||||
|
||||
CloudStorageAccount storageAccount = new CloudStorageAccount(new StorageCredentials(accountName, accountKey), true);
|
||||
CloudBlobClient cloudBlobClient = storageAccount.CreateCloudBlobClient();
|
||||
CloudBlobContainer container = cloudBlobClient.GetContainerReference(containerName);
|
||||
|
||||
container.CreateIfNotExists();
|
||||
|
||||
CloudBlockBlob oldBlob = container.GetBlockBlobReference(oldBlobName);
|
||||
|
||||
if (!oldBlob.Exists())
|
||||
return string.Empty;
|
||||
|
||||
CloudBlockBlob newBlob = container.GetBlockBlobReference(newBlobName);
|
||||
|
||||
//newBlob.StartCopyFromBlob(oldBlob.Uri);
|
||||
newBlob.StartCopy(oldBlob);
|
||||
while (true)
|
||||
{
|
||||
newBlob.FetchAttributes();
|
||||
if (newBlob.CopyState.Status != CopyStatus.Pending)
|
||||
{
|
||||
break;
|
||||
}
|
||||
//Sleep for a second may be
|
||||
System.Threading.Thread.Sleep(100);
|
||||
}
|
||||
oldBlob.Delete();
|
||||
|
||||
return newBlob.Uri.AbsoluteUri;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
64
Amen/Helpers/RequestHelper.cs
Normal file
@ -0,0 +1,64 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Web;
|
||||
|
||||
namespace Amen.Helpers
|
||||
{
|
||||
public class RequestHelper
|
||||
{
|
||||
public static string GetClientIpAddress(HttpRequestBase request)
|
||||
{
|
||||
try
|
||||
{
|
||||
var userHostAddress = request.UserHostAddress;
|
||||
|
||||
// Attempt to parse. If it fails, we catch below and return "0.0.0.0"
|
||||
// Could use TryParse instead, but I wanted to catch all exceptions
|
||||
IPAddress.Parse(userHostAddress);
|
||||
|
||||
var xForwardedFor = request.ServerVariables["X_FORWARDED_FOR"];
|
||||
|
||||
if (string.IsNullOrEmpty(xForwardedFor))
|
||||
return userHostAddress;
|
||||
|
||||
// Get a list of public ip addresses in the X_FORWARDED_FOR variable
|
||||
var publicForwardingIps = xForwardedFor.Split(',').Where(ip => !IsPrivateIpAddress(ip)).ToList();
|
||||
|
||||
// If we found any, return the last one, otherwise return the user host address
|
||||
return publicForwardingIps.Any() ? publicForwardingIps.Last() : userHostAddress;
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
// Always return all zeroes for any failure (my calling code expects it)
|
||||
return "0.0.0.0";
|
||||
}
|
||||
}
|
||||
|
||||
private static bool IsPrivateIpAddress(string ipAddress)
|
||||
{
|
||||
// http://en.wikipedia.org/wiki/Private_network
|
||||
// Private IP Addresses are:
|
||||
// 24-bit block: 10.0.0.0 through 10.255.255.255
|
||||
// 20-bit block: 172.16.0.0 through 172.31.255.255
|
||||
// 16-bit block: 192.168.0.0 through 192.168.255.255
|
||||
// Link-local addresses: 169.254.0.0 through 169.254.255.255 (http://en.wikipedia.org/wiki/Link-local_address)
|
||||
|
||||
var ip = IPAddress.Parse(ipAddress);
|
||||
var octets = ip.GetAddressBytes();
|
||||
|
||||
var is24BitBlock = octets[0] == 10;
|
||||
if (is24BitBlock) return true; // Return to prevent further processing
|
||||
|
||||
var is20BitBlock = octets[0] == 172 && octets[1] >= 16 && octets[1] <= 31;
|
||||
if (is20BitBlock) return true; // Return to prevent further processing
|
||||
|
||||
var is16BitBlock = octets[0] == 192 && octets[1] == 168;
|
||||
if (is16BitBlock) return true; // Return to prevent further processing
|
||||
|
||||
var isLinkLocalAddress = octets[0] == 169 && octets[1] == 254;
|
||||
return isLinkLocalAddress;
|
||||
}
|
||||
}
|
||||
}
|
27
Amen/Helpers/StringHelper.cs
Normal file
@ -0,0 +1,27 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Web;
|
||||
|
||||
namespace Amen.Helpers
|
||||
{
|
||||
public static class StringExtension
|
||||
{
|
||||
public static string StripPunctuation(this string s)
|
||||
{
|
||||
var sb = new StringBuilder();
|
||||
foreach (char c in s)
|
||||
{
|
||||
if (!char.IsPunctuation(c))
|
||||
sb.Append(c);
|
||||
}
|
||||
return sb.ToString();
|
||||
}
|
||||
}
|
||||
|
||||
public class StringHelper
|
||||
{
|
||||
|
||||
}
|
||||
}
|
20
Amen/Helpers/UserHelper.cs
Normal file
@ -0,0 +1,20 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Security.Claims;
|
||||
using System.Web;
|
||||
|
||||
namespace Amen.Helpers
|
||||
{
|
||||
public static class UserHelper
|
||||
{
|
||||
public static string GetFullName(this System.Security.Principal.IPrincipal usr)
|
||||
{
|
||||
var fullNameClaim = ((ClaimsIdentity)usr.Identity).FindFirst("FullName");
|
||||
if (fullNameClaim != null)
|
||||
return fullNameClaim.Value;
|
||||
|
||||
return "";
|
||||
}
|
||||
}
|
||||
}
|
29
Amen/Migrations/201701031255563_AddCreatedUTCColumns.Designer.cs
generated
Normal file
@ -0,0 +1,29 @@
|
||||
// <auto-generated />
|
||||
namespace Amen.Migrations
|
||||
{
|
||||
using System.CodeDom.Compiler;
|
||||
using System.Data.Entity.Migrations;
|
||||
using System.Data.Entity.Migrations.Infrastructure;
|
||||
using System.Resources;
|
||||
|
||||
[GeneratedCode("EntityFramework.Migrations", "6.1.1-30610")]
|
||||
public sealed partial class AddCreatedUTCColumns : IMigrationMetadata
|
||||
{
|
||||
private readonly ResourceManager Resources = new ResourceManager(typeof(AddCreatedUTCColumns));
|
||||
|
||||
string IMigrationMetadata.Id
|
||||
{
|
||||
get { return "201701031255563_AddCreatedUTCColumns"; }
|
||||
}
|
||||
|
||||
string IMigrationMetadata.Source
|
||||
{
|
||||
get { return Resources.GetString("Source"); }
|
||||
}
|
||||
|
||||
string IMigrationMetadata.Target
|
||||
{
|
||||
get { return Resources.GetString("Target"); }
|
||||
}
|
||||
}
|
||||
}
|
30
Amen/Migrations/201701031255563_AddCreatedUTCColumns.cs
Normal file
@ -0,0 +1,30 @@
|
||||
namespace Amen.Migrations
|
||||
{
|
||||
using System;
|
||||
using System.Data.Entity.Migrations;
|
||||
|
||||
public partial class AddCreatedUTCColumns : DbMigration
|
||||
{
|
||||
public override void Up()
|
||||
{
|
||||
AddColumn("dbo.AffiliateAdmin", "CreatedUTC", c => c.DateTime(nullable: false, defaultValueSql: "GETUTCDATE()"));
|
||||
AddColumn("dbo.AffiliateStyle", "CreatedUTC", c => c.DateTime(nullable: false, defaultValueSql: "GETUTCDATE()"));
|
||||
AddColumn("dbo.PrayerBookmark", "CreatedUTC", c => c.DateTime(nullable: false, defaultValueSql: "GETUTCDATE()"));
|
||||
AddColumn("dbo.PrayerFlag", "CreatedUTC", c => c.DateTime(nullable: false, defaultValueSql: "GETUTCDATE()"));
|
||||
AddColumn("dbo.PrayerItem", "CreatedUTC", c => c.DateTime(nullable: false, defaultValueSql: "GETUTCDATE()"));
|
||||
AddColumn("dbo.PrayerNote", "CreatedUTC", c => c.DateTime(nullable: false, defaultValueSql: "GETUTCDATE()"));
|
||||
AddColumn("dbo.PrayerSubscription", "CreatedUTC", c => c.DateTime(nullable: false, defaultValueSql: "GETUTCDATE()"));
|
||||
}
|
||||
|
||||
public override void Down()
|
||||
{
|
||||
DropColumn("dbo.PrayerSubscription", "CreatedUTC");
|
||||
DropColumn("dbo.PrayerNote", "CreatedUTC");
|
||||
DropColumn("dbo.PrayerItem", "CreatedUTC");
|
||||
DropColumn("dbo.PrayerFlag", "CreatedUTC");
|
||||
DropColumn("dbo.PrayerBookmark", "CreatedUTC");
|
||||
DropColumn("dbo.AffiliateStyle", "CreatedUTC");
|
||||
DropColumn("dbo.AffiliateAdmin", "CreatedUTC");
|
||||
}
|
||||
}
|
||||
}
|
129
Amen/Migrations/201701031255563_AddCreatedUTCColumns.resx
Normal file
29
Amen/Migrations/201708042356577_AddAffiliateIntructions.Designer.cs
generated
Normal file
@ -0,0 +1,29 @@
|
||||
// <auto-generated />
|
||||
namespace Amen.Migrations
|
||||
{
|
||||
using System.CodeDom.Compiler;
|
||||
using System.Data.Entity.Migrations;
|
||||
using System.Data.Entity.Migrations.Infrastructure;
|
||||
using System.Resources;
|
||||
|
||||
[GeneratedCode("EntityFramework.Migrations", "6.1.1-30610")]
|
||||
public sealed partial class AddAffiliateIntructions : IMigrationMetadata
|
||||
{
|
||||
private readonly ResourceManager Resources = new ResourceManager(typeof(AddAffiliateIntructions));
|
||||
|
||||
string IMigrationMetadata.Id
|
||||
{
|
||||
get { return "201708042356577_AddAffiliateIntructions"; }
|
||||
}
|
||||
|
||||
string IMigrationMetadata.Source
|
||||
{
|
||||
get { return Resources.GetString("Source"); }
|
||||
}
|
||||
|
||||
string IMigrationMetadata.Target
|
||||
{
|
||||
get { return Resources.GetString("Target"); }
|
||||
}
|
||||
}
|
||||
}
|
22
Amen/Migrations/201708042356577_AddAffiliateIntructions.cs
Normal file
@ -0,0 +1,22 @@
|
||||
namespace Amen.Migrations
|
||||
{
|
||||
using System;
|
||||
using System.Data.Entity.Migrations;
|
||||
|
||||
public partial class AddAffiliateIntructions : DbMigration
|
||||
{
|
||||
public override void Up()
|
||||
{
|
||||
AddColumn("dbo.Affiliate", "InstructionsPraise", c => c.String());
|
||||
AddColumn("dbo.Affiliate", "InstructionsAddPraise", c => c.String());
|
||||
AddColumn("dbo.Affiliate", "InstructionsNote", c => c.String());
|
||||
}
|
||||
|
||||
public override void Down()
|
||||
{
|
||||
DropColumn("dbo.Affiliate", "InstructionsNote");
|
||||
DropColumn("dbo.Affiliate", "InstructionsAddPraise");
|
||||
DropColumn("dbo.Affiliate", "InstructionsPraise");
|
||||
}
|
||||
}
|
||||
}
|
129
Amen/Migrations/201708042356577_AddAffiliateIntructions.resx
Normal file
29
Amen/Migrations/201708050049099_AddFieldsToSupportShowingUserNameAndLocation.Designer.cs
generated
Normal file
@ -0,0 +1,29 @@
|
||||
// <auto-generated />
|
||||
namespace Amen.Migrations
|
||||
{
|
||||
using System.CodeDom.Compiler;
|
||||
using System.Data.Entity.Migrations;
|
||||
using System.Data.Entity.Migrations.Infrastructure;
|
||||
using System.Resources;
|
||||
|
||||
[GeneratedCode("EntityFramework.Migrations", "6.1.1-30610")]
|
||||
public sealed partial class AddFieldsToSupportShowingUserNameAndLocation : IMigrationMetadata
|
||||
{
|
||||
private readonly ResourceManager Resources = new ResourceManager(typeof(AddFieldsToSupportShowingUserNameAndLocation));
|
||||
|
||||
string IMigrationMetadata.Id
|
||||
{
|
||||
get { return "201708050049099_AddFieldsToSupportShowingUserNameAndLocation"; }
|
||||
}
|
||||
|
||||
string IMigrationMetadata.Source
|
||||
{
|
||||
get { return null; }
|
||||
}
|
||||
|
||||
string IMigrationMetadata.Target
|
||||
{
|
||||
get { return Resources.GetString("Target"); }
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,26 @@
|
||||
namespace Amen.Migrations
|
||||
{
|
||||
using System;
|
||||
using System.Data.Entity.Migrations;
|
||||
|
||||
public partial class AddFieldsToSupportShowingUserNameAndLocation : DbMigration
|
||||
{
|
||||
public override void Up()
|
||||
{
|
||||
AddColumn("dbo.Affiliate", "EnableShowLocation", c => c.Boolean(nullable: false));
|
||||
AddColumn("dbo.Affiliate", "EnableShowName", c => c.Boolean(nullable: false));
|
||||
AddColumn("dbo.AspNetUsers", "Location", c => c.String());
|
||||
AddColumn("dbo.AspNetUsers", "ShouldShowLocation", c => c.Boolean(nullable: false));
|
||||
AddColumn("dbo.AspNetUsers", "ShouldShowName", c => c.Boolean(nullable: false));
|
||||
}
|
||||
|
||||
public override void Down()
|
||||
{
|
||||
DropColumn("dbo.AspNetUsers", "ShouldShowName");
|
||||
DropColumn("dbo.AspNetUsers", "ShouldShowLocation");
|
||||
DropColumn("dbo.AspNetUsers", "Location");
|
||||
DropColumn("dbo.Affiliate", "EnableShowName");
|
||||
DropColumn("dbo.Affiliate", "EnableShowLocation");
|
||||
}
|
||||
}
|
||||
}
|
116
Amen/Migrations/Configuration.cs
Normal file
@ -0,0 +1,116 @@
|
||||
namespace Amen.Migrations
|
||||
{
|
||||
using Amen.Controllers;
|
||||
using Amen.Models;
|
||||
using System;
|
||||
using System.Data.Entity;
|
||||
using System.Data.Entity.Migrations;
|
||||
using System.Linq;
|
||||
using System.Web.Security;
|
||||
|
||||
internal sealed class Configuration : DbMigrationsConfiguration<Amen.Models.ApplicationDbContext>
|
||||
{
|
||||
public Configuration()
|
||||
{
|
||||
AutomaticMigrationsEnabled = true;
|
||||
ContextKey = "Amen.Models.ApplicationDbContext";
|
||||
AutomaticMigrationDataLossAllowed = true;
|
||||
|
||||
/*
|
||||
* Add-Migration [MigrationName]
|
||||
* Update-Database -Script -SourceMigration: $InitialDatabase -TargetMigration: [MigrationName]
|
||||
*
|
||||
* Update-Database -ConnectionStringName: AmenPrayerDev
|
||||
* Update-Database -ConnectionStringName: AmenPrayerProd
|
||||
*
|
||||
* */
|
||||
}
|
||||
|
||||
protected override void Seed(Amen.Models.ApplicationDbContext context)
|
||||
{
|
||||
// This method will be called after migrating to the latest version.
|
||||
|
||||
// You can use the DbSet<T>.AddOrUpdate() helper extension method
|
||||
// to avoid creating duplicate seed data. E.g.
|
||||
//
|
||||
// context.People.AddOrUpdate(
|
||||
// p => p.FullName,
|
||||
// new Person { FullName = "Andrew Peters" },
|
||||
// new Person { FullName = "Brice Lambson" },
|
||||
// new Person { FullName = "Rowan Miller" }
|
||||
// );
|
||||
//
|
||||
|
||||
context.PrayerSources.AddOrUpdate(i => i.Label,
|
||||
new PrayerSource() { Label = "Web", Description = "Requests made via the web site." },
|
||||
new PrayerSource() { Label = "iOS", Description = "Requests made via the iOS app." }
|
||||
);
|
||||
context.SaveChanges();
|
||||
|
||||
context.SubscriptionTypes.AddOrUpdate(i => i.Label,
|
||||
new SubscriptionType() { Label = "Basic", Description = "Basic subscription with web access." },
|
||||
new SubscriptionType() { Label = "BasicPlus", Description = "Basic Plus access to iOS app." },
|
||||
new SubscriptionType() { Label = "Demo", Description = "Try it out, but does not show up in the affiliate list." }
|
||||
);
|
||||
context.SaveChanges();
|
||||
|
||||
var noSource = context.Prayers.Where(i => !i.PrayerSourceId.HasValue).ToList();
|
||||
//var noSource = context.Prayers.ToList();
|
||||
foreach (var item in noSource)
|
||||
{
|
||||
item.PrayerSourceId = PrayerSource.DeterminePrayerSource(item.UserAgent);
|
||||
}
|
||||
context.SaveChanges();
|
||||
|
||||
if (context.Roles.Count(i => i.Name == ControllerHelper.Role_SuperAdministrator) == 0)
|
||||
{
|
||||
context.Roles.Add(new Microsoft.AspNet.Identity.EntityFramework.IdentityRole(ControllerHelper.Role_SuperAdministrator));
|
||||
context.SaveChanges();
|
||||
}
|
||||
|
||||
if (context.Roles.Count(i => i.Name == ControllerHelper.Role_Administrator) == 0)
|
||||
{
|
||||
context.Roles.Add(new Microsoft.AspNet.Identity.EntityFramework.IdentityRole(ControllerHelper.Role_Administrator));
|
||||
context.SaveChanges();
|
||||
}
|
||||
|
||||
if (context.Roles.Count(i => i.Name == ControllerHelper.Role_AffiliateAdministrator) == 0)
|
||||
{
|
||||
context.Roles.Add(new Microsoft.AspNet.Identity.EntityFramework.IdentityRole(ControllerHelper.Role_AffiliateAdministrator));
|
||||
context.SaveChanges();
|
||||
}
|
||||
|
||||
var than = context.Users.Include(i => i.Roles).FirstOrDefault(i => i.Email == "thannap@hotmail.com");
|
||||
if (than != null)
|
||||
{
|
||||
var adminRole = context.Roles.FirstOrDefault(i => i.Name == ControllerHelper.Role_Administrator);
|
||||
if (than.Roles.Count(i => i.RoleId == adminRole.Id) == 0)
|
||||
{
|
||||
than.Roles.Add(new Microsoft.AspNet.Identity.EntityFramework.IdentityUserRole() { RoleId = adminRole.Id, UserId = than.Id });
|
||||
context.SaveChanges();
|
||||
}
|
||||
|
||||
var superAdminRole = context.Roles.FirstOrDefault(i => i.Name == ControllerHelper.Role_SuperAdministrator);
|
||||
if (than.Roles.Count(i => i.RoleId == superAdminRole.Id) == 0)
|
||||
{
|
||||
than.Roles.Add(new Microsoft.AspNet.Identity.EntityFramework.IdentityUserRole() { RoleId = superAdminRole.Id, UserId = than.Id });
|
||||
context.SaveChanges();
|
||||
}
|
||||
}
|
||||
|
||||
var thangmail = context.Users.Include(i => i.Roles).FirstOrDefault(i => i.Email == "thannap@gmail.com");
|
||||
if (thangmail != null)
|
||||
{
|
||||
var adminRole = context.Roles.FirstOrDefault(i => i.Name == ControllerHelper.Role_AffiliateAdministrator);
|
||||
if (thangmail.Roles.Count(i => i.RoleId == adminRole.Id) == 0)
|
||||
{
|
||||
thangmail.Roles.Add(new Microsoft.AspNet.Identity.EntityFramework.IdentityUserRole() { RoleId = adminRole.Id, UserId = thangmail.Id });
|
||||
context.SaveChanges();
|
||||
}
|
||||
}
|
||||
|
||||
//RoleManager = new RoleManager<IdentityRole>(new RoleStore<IdentityRole>(new MyDbContext()));
|
||||
//var roleresult = RoleManager.Create(new IdentityRole(roleName));
|
||||
}
|
||||
}
|
||||
}
|
140
Amen/Models/AccountViewModels.cs
Normal file
@ -0,0 +1,140 @@
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace Amen.Models
|
||||
{
|
||||
public class ExternalLoginConfirmationViewModel
|
||||
{
|
||||
[Required]
|
||||
[Display(Name = "Email")]
|
||||
public string Email { get; set; }
|
||||
|
||||
[Required]
|
||||
[Display(Name = "Full Name")]
|
||||
public string FullName { get; set; }
|
||||
}
|
||||
|
||||
public class ExternalLoginListViewModel
|
||||
{
|
||||
public string ReturnUrl { get; set; }
|
||||
}
|
||||
|
||||
public class SendCodeViewModel
|
||||
{
|
||||
public string SelectedProvider { get; set; }
|
||||
public ICollection<System.Web.Mvc.SelectListItem> Providers { get; set; }
|
||||
public string ReturnUrl { get; set; }
|
||||
public bool RememberMe { get; set; }
|
||||
}
|
||||
|
||||
public class VerifyCodeViewModel
|
||||
{
|
||||
[Required]
|
||||
public string Provider { get; set; }
|
||||
|
||||
[Required]
|
||||
[Display(Name = "Code")]
|
||||
public string Code { get; set; }
|
||||
public string ReturnUrl { get; set; }
|
||||
|
||||
[Display(Name = "Remember this browser?")]
|
||||
public bool RememberBrowser { get; set; }
|
||||
|
||||
public bool RememberMe { get; set; }
|
||||
}
|
||||
|
||||
public class ForgotViewModel
|
||||
{
|
||||
[Required]
|
||||
[Display(Name = "Email")]
|
||||
public string Email { get; set; }
|
||||
}
|
||||
|
||||
public class LoginViewModel
|
||||
{
|
||||
[Required]
|
||||
[Display(Name = "Email")]
|
||||
[EmailAddress]
|
||||
public string Email { get; set; }
|
||||
|
||||
[Required]
|
||||
[DataType(DataType.Password)]
|
||||
[Display(Name = "Password")]
|
||||
public string Password { get; set; }
|
||||
|
||||
[Display(Name = "Remember me?")]
|
||||
public bool RememberMe { get; set; }
|
||||
}
|
||||
|
||||
public class RegisterViewModel
|
||||
{
|
||||
|
||||
[Required]
|
||||
[Display(Name = "Full Name")]
|
||||
public string FullName { get; set; }
|
||||
|
||||
[Required]
|
||||
[EmailAddress]
|
||||
[Display(Name = "Email")]
|
||||
public string Email { get; set; }
|
||||
|
||||
[Display(Name = "Location")]
|
||||
public string Location { get; set; }
|
||||
|
||||
[Display(Name = "Enable Text Notifications")]
|
||||
public bool EnableSmsNotifications { get; set; }
|
||||
|
||||
[Display(Name = "Enable Email Notifications")]
|
||||
public bool EnableEmailNotifications { get; set; }
|
||||
|
||||
[Display(Name = "Allow My Name To Be Shown When Posting")]
|
||||
public bool ShouldShowName { get; set; }
|
||||
|
||||
[Display(Name = "Allow My Location To Be Shown When Posting")]
|
||||
public bool ShouldShowLocation { get; set; }
|
||||
|
||||
[Required]
|
||||
[StringLength(100, ErrorMessage = "The {0} must be at least {2} characters long.", MinimumLength = 6)]
|
||||
[DataType(DataType.Password)]
|
||||
[Display(Name = "Password")]
|
||||
public string Password { get; set; }
|
||||
|
||||
[DataType(DataType.Password)]
|
||||
[Display(Name = "Confirm password")]
|
||||
[Compare("Password", ErrorMessage = "The password and confirmation password do not match.")]
|
||||
public string ConfirmPassword { get; set; }
|
||||
|
||||
public bool AffiliateEnableShowLocation { get; set; }
|
||||
public bool AffiliateEnableShowName { get; set; }
|
||||
public bool AffiliateIsSmsCapable { get; set; }
|
||||
}
|
||||
|
||||
public class ResetPasswordViewModel
|
||||
{
|
||||
[Required]
|
||||
[EmailAddress]
|
||||
[Display(Name = "Email")]
|
||||
public string Email { get; set; }
|
||||
|
||||
[Required]
|
||||
[StringLength(100, ErrorMessage = "The {0} must be at least {2} characters long.", MinimumLength = 6)]
|
||||
[DataType(DataType.Password)]
|
||||
[Display(Name = "Password")]
|
||||
public string Password { get; set; }
|
||||
|
||||
[DataType(DataType.Password)]
|
||||
[Display(Name = "Confirm password")]
|
||||
[Compare("Password", ErrorMessage = "The password and confirmation password do not match.")]
|
||||
public string ConfirmPassword { get; set; }
|
||||
|
||||
public string Code { get; set; }
|
||||
}
|
||||
|
||||
public class ForgotPasswordViewModel
|
||||
{
|
||||
[Required]
|
||||
[EmailAddress]
|
||||
[Display(Name = "Email")]
|
||||
public string Email { get; set; }
|
||||
}
|
||||
}
|
137
Amen/Models/Affiliate.cs
Normal file
@ -0,0 +1,137 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
using System.Linq;
|
||||
using System.Web;
|
||||
using System.Web.Mvc;
|
||||
|
||||
namespace Amen.Models
|
||||
{
|
||||
public class Affiliate
|
||||
{
|
||||
public int Id { get; set; }
|
||||
|
||||
[ScaffoldColumn(false)]
|
||||
public int PWId { get; set; }
|
||||
|
||||
[Index(IsUnique = true)]
|
||||
[StringLength(64)]
|
||||
[Required]
|
||||
public string Key { get; set; }
|
||||
|
||||
[Display(Name = "Include prayers in Amen universal list?", Description = "Increases visibility of prayers")]
|
||||
public bool IncludeInUniversal { get; set; }
|
||||
|
||||
|
||||
[Display(Name = "Is Active?")]
|
||||
public bool IsActive { get; set; }
|
||||
|
||||
[Required]
|
||||
public string Name { get; set; }
|
||||
|
||||
[AllowHtml]
|
||||
[DataType(DataType.MultilineText)]
|
||||
[Display(Name = "Instructions for Prayer List")]
|
||||
public string Instructions { get; set; }
|
||||
|
||||
[AllowHtml]
|
||||
[DataType(DataType.MultilineText)]
|
||||
[Display(Name = "Instructions for Praise List")]
|
||||
public string InstructionsPraise { get; set; }
|
||||
|
||||
[AllowHtml]
|
||||
[DataType(DataType.MultilineText)]
|
||||
[Display(Name = "Instructions for Submitting Individual Prayers")]
|
||||
public string InstructionsAddPrayer { get; set; }
|
||||
|
||||
[AllowHtml]
|
||||
[DataType(DataType.MultilineText)]
|
||||
[Display(Name = "Instructions for Submitting Individual Praise")]
|
||||
public string InstructionsAddPraise { get; set; }
|
||||
|
||||
[AllowHtml]
|
||||
[DataType(DataType.MultilineText)]
|
||||
[Display(Name = "Instructions for Notes of Encouragement")]
|
||||
public string InstructionsNote { get; set; }
|
||||
|
||||
[Display(Name = "Website Url")]
|
||||
public string UrlWebsite { get; set; }
|
||||
[Display(Name = "Logo Url")]
|
||||
public string UrlLogo { get; set; }
|
||||
|
||||
[Display(Name = "Email Address of Admin Contact")]
|
||||
public string EmailAdmin { get; set; }
|
||||
[Display(Name = "Email Address of Billing Contact")]
|
||||
public string EmailBilling { get; set; }
|
||||
[Display(Name = "Email Address of Flag Contact")]
|
||||
public string EmailFlag { get; set; }
|
||||
|
||||
[Display(Name = "Email Subject Line For Prayed Notification")]
|
||||
public string SendMessagePrayed { get; set; }
|
||||
[Display(Name = "Email Subject Line For Note of Encouragement Notification")]
|
||||
public string SendMessageNote { get; set; }
|
||||
|
||||
[Display(Name = "How many days of prayers to include")]
|
||||
public int PrayerDaysThreshold { get; set; }
|
||||
|
||||
[Display(Name = "How many flags to disable a prayer")]
|
||||
public int FlagThreshold { get; set; }
|
||||
|
||||
public string TwilioSID { get; set; }
|
||||
public string TwilioAuthToken { get; set; }
|
||||
public string TwilioPhoneNumber { get; set; }
|
||||
|
||||
|
||||
[Display(Name = "Send notification to admin when someone submits prayer request")]
|
||||
public bool ShouldSendPrayerNotificationAdmin { get; set; }
|
||||
|
||||
[Display(Name = "Send notification to admin when someone submits praise")]
|
||||
public bool ShouldSendPraiseNotificationAdmin { get; set; }
|
||||
|
||||
[Display(Name = "Allow users to send notes of encouragement")]
|
||||
public bool EnableNotes { get; set; }
|
||||
|
||||
[Display(Name = "Require admin moderation in order for prayers to become 'active'")]
|
||||
public bool RequireModeration { get; set; }
|
||||
|
||||
public int? SubscriptionTypeId { get; set; }
|
||||
public SubscriptionType SubscriptionType { get; set; }
|
||||
|
||||
[Display(Name = "Require users to create and log into an account to use notification features (recommended)")]
|
||||
public bool RequireLoginForNoticiations { get; set; }
|
||||
|
||||
[Display(Name = "Allow users to opt in to show their location")]
|
||||
public bool EnableShowLocation { get; set; }
|
||||
|
||||
[Display(Name = "Allow users to opt in to show their name")]
|
||||
public bool EnableShowName { get; set; }
|
||||
|
||||
//TODO: implement something new
|
||||
//public int Level { get; set; }
|
||||
//public int Status { get; set; }
|
||||
//public bool ShouldUseBlacklist { get; set; }
|
||||
//public string BlacklistEmails { get; set; }
|
||||
//public string BlacklistIPs { get; set; }
|
||||
|
||||
//public int MaxLengthPrayer { get; set; }
|
||||
//public int MaxLengthStory { get; set; }
|
||||
|
||||
public virtual IList<AffiliateStyle> Styles { get; set; }
|
||||
public virtual IList<BlacklistEmail> BlacklistEmails { get; set; }
|
||||
public virtual IList<BlacklistIP> BlacklistIPs { get; set; }
|
||||
public virtual IList<AutoFlagItem> AutoFlagItems { get; set; }
|
||||
public virtual IList<AffiliateAdmin> AffiliateAdmins { get; set; }
|
||||
|
||||
[NotMapped]
|
||||
public bool IsSmsCapable
|
||||
{
|
||||
get
|
||||
{
|
||||
return !string.IsNullOrEmpty(this.TwilioSID)
|
||||
&& !string.IsNullOrEmpty(this.TwilioAuthToken)
|
||||
&& !string.IsNullOrEmpty(this.TwilioPhoneNumber);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
23
Amen/Models/AffiliateAdmin.cs
Normal file
@ -0,0 +1,23 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
using System.Linq;
|
||||
using System.Web;
|
||||
|
||||
namespace Amen.Models
|
||||
{
|
||||
public class AffiliateAdmin
|
||||
{
|
||||
[Key, Column(Order = 0)]
|
||||
[ForeignKey("ApplicationUser")]
|
||||
public string ApplicationUserId { get; set; }
|
||||
public ApplicationUser ApplicationUser { get; set; }
|
||||
|
||||
[Key, Column(Order = 1)]
|
||||
public int AffiliateId { get; set; }
|
||||
public Affiliate Affiliate { get; set; }
|
||||
|
||||
public DateTime CreatedUTC { get; set; }
|
||||
}
|
||||
}
|
19
Amen/Models/AffiliateStyle.cs
Normal file
@ -0,0 +1,19 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Web;
|
||||
|
||||
namespace Amen.Models
|
||||
{
|
||||
public class AffiliateStyle
|
||||
{
|
||||
public int Id { get; set; }
|
||||
|
||||
public int AffiliateId { get; set; }
|
||||
public Affiliate Affiliate { get; set; }
|
||||
|
||||
public string StyleSheet { get; set; }
|
||||
|
||||
public DateTime CreatedUTC { get; set; }
|
||||
}
|
||||
}
|
127
Amen/Models/AffiliateViewModels.cs
Normal file
@ -0,0 +1,127 @@
|
||||
using PagedList;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.Linq;
|
||||
using System.Web;
|
||||
|
||||
namespace Amen.Models
|
||||
{
|
||||
public class AffiliateSelectViewModel
|
||||
{
|
||||
public int Id { get; set; }
|
||||
public string Name { get; set; }
|
||||
public string Key { get; set; }
|
||||
public string UrlLogo { get; set; }
|
||||
public string NavigateUrl { get; set; }
|
||||
|
||||
public int? SubscriptionTypeId { get; set; }
|
||||
}
|
||||
|
||||
public class AffiliateTabsViewModel
|
||||
{
|
||||
public int Id { get; set; }
|
||||
public string Key { get; set; }
|
||||
public string Selected { get; set; }
|
||||
}
|
||||
|
||||
public class AffiliateStyleViewModel
|
||||
{
|
||||
public int Id { get; set; }
|
||||
public string Key { get; set; }
|
||||
|
||||
[DataType(DataType.MultilineText)]
|
||||
public string StyleContent { get; set; }
|
||||
public string Template { get; set; }
|
||||
}
|
||||
|
||||
public class AffiliateFlagItemsViewModel
|
||||
{
|
||||
public int Id { get; set; }
|
||||
public string Key { get; set; }
|
||||
|
||||
//[DataType(DataType.MultilineText)]
|
||||
public string FlagItems { get; set; }
|
||||
}
|
||||
|
||||
public class AffiliatePrayersViewModel
|
||||
{
|
||||
public int Id { get; set; }
|
||||
public int Page { get; set; }
|
||||
public int PageSize { get; set; }
|
||||
public IPagedList<Prayer> Prayers { get; set; }
|
||||
}
|
||||
|
||||
public class AffiliateStatsViewModel
|
||||
{
|
||||
public int Id { get; set; }
|
||||
|
||||
[Display(Name = "Total Requests")]
|
||||
public int TotalRequests { get; set; }
|
||||
[Display(Name = "Total Praise")]
|
||||
public int TotalPraise { get; set; }
|
||||
[Display(Name = "Total Notes Sent")]
|
||||
public int TotalNotesSent { get; set; }
|
||||
[Display(Name = "Total Prayers Prayed")]
|
||||
public int TotalPrayersPrayed { get; set; }
|
||||
[Display(Name = "Total Flags")]
|
||||
public int TotalFlagsIndicated { get; set; }
|
||||
|
||||
[Display(Name = "Recent Requests")]
|
||||
public int RecentRequests { get; set; }
|
||||
[Display(Name = "Recent Praise")]
|
||||
public int RecentPraise { get; set; }
|
||||
[Display(Name = "Recent Notes Sent")]
|
||||
public int RecentNotesSent { get; set; }
|
||||
[Display(Name = "Recent Prayers Prayed")]
|
||||
public int RecentPrayersPrayed { get; set; }
|
||||
[Display(Name = "Recent Flags")]
|
||||
public int RecentFlagsIndicated { get; set; }
|
||||
|
||||
[Display(Name="Recent Requests %")]
|
||||
[DisplayFormat(DataFormatString = "{0:N2}")]
|
||||
public double RecentRequestsPercentage { get { if (this.TotalRequests == 0) return 0; return (double)this.RecentRequests / (double)this.TotalRequests * 100.0; } }
|
||||
[Display(Name = "Recent Praise %")]
|
||||
[DisplayFormat(DataFormatString = "{0:N2}")]
|
||||
public double RecentPraisePercentage { get { if (this.TotalPraise == 0) return 0; return (double)this.RecentPraise / (double)this.TotalPraise * 100.0; } }
|
||||
[Display(Name = "Recent Notes %")]
|
||||
[DisplayFormat(DataFormatString = "{0:N2}")]
|
||||
public double RecentNotesSentPercentage { get { if (this.TotalNotesSent == 0) return 0; return (double)this.RecentNotesSent / (double)this.TotalNotesSent * 100.0; } }
|
||||
[Display(Name = "Recent Prayed %")]
|
||||
[DisplayFormat(DataFormatString = "{0:N2}")]
|
||||
public double RecentPrayersPrayedPercentage { get { if (this.TotalPrayersPrayed == 0) return 0; return (double)this.RecentPrayersPrayed / (double)this.TotalPrayersPrayed * 100.0; } }
|
||||
[Display(Name = "Recent Flags %")]
|
||||
[DisplayFormat(DataFormatString = "{0:N2}")]
|
||||
public double RecentFlagsIndicatedPercentage { get { if (this.TotalFlagsIndicated == 0) return 0; return (double)this.RecentFlagsIndicated / (double)this.TotalFlagsIndicated * 100.0; } }
|
||||
}
|
||||
|
||||
public class AffiliateUsersViewModel
|
||||
{
|
||||
public int Id { get; set; }
|
||||
public List<AffiliateUserViewModel> Users { get; set; }
|
||||
|
||||
public class AffiliateUserViewModel
|
||||
{
|
||||
public string Id { get; set; }
|
||||
public string FullName { get; set; }
|
||||
public string Email { get; set; }
|
||||
|
||||
public DateTime? LastLoginDate { get; set; }
|
||||
public bool IsAdmin { get; set; }
|
||||
public int OffsetMinutes { get; set; }
|
||||
|
||||
public string DisplayLoginDate
|
||||
{
|
||||
get
|
||||
{
|
||||
if (!this.LastLoginDate.HasValue)
|
||||
return "";
|
||||
|
||||
return this.LastLoginDate.Value.AddMinutes(OffsetMinutes).ToShortDateString();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
17
Amen/Models/AutoFlagItem.cs
Normal file
@ -0,0 +1,17 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Web;
|
||||
|
||||
namespace Amen.Models
|
||||
{
|
||||
public class AutoFlagItem
|
||||
{
|
||||
public int Id { get; set; }
|
||||
|
||||
public int AffiliateId { get; set; }
|
||||
public Affiliate Affiliate { get; set; }
|
||||
|
||||
public string Text { get; set; }
|
||||
}
|
||||
}
|
17
Amen/Models/BlacklistEmail.cs
Normal file
@ -0,0 +1,17 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Web;
|
||||
|
||||
namespace Amen.Models
|
||||
{
|
||||
public class BlacklistEmail
|
||||
{
|
||||
public int Id { get; set; }
|
||||
|
||||
public int AffiliateId { get; set; }
|
||||
public Affiliate Affiliate { get; set; }
|
||||
|
||||
public string Email { get; set; }
|
||||
}
|
||||
}
|
17
Amen/Models/BlacklistIP.cs
Normal file
@ -0,0 +1,17 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Web;
|
||||
|
||||
namespace Amen.Models
|
||||
{
|
||||
public class BlacklistIP
|
||||
{
|
||||
public int Id { get; set; }
|
||||
|
||||
public int AffiliateId { get; set; }
|
||||
public Affiliate Affiliate { get; set; }
|
||||
|
||||
public string IP { get; set; }
|
||||
}
|
||||
}
|
33
Amen/Models/EmailViewModels.cs
Normal file
@ -0,0 +1,33 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Web;
|
||||
|
||||
namespace Amen.Models
|
||||
{
|
||||
public class EmailViewModel
|
||||
{
|
||||
public string To { get; set; }
|
||||
public string Subject { get; set; }
|
||||
}
|
||||
|
||||
public class PrayerEmailViewModel : EmailViewModel
|
||||
{
|
||||
public string Title { get; set; }
|
||||
public string NoteText { get; set; }
|
||||
public string DetailUrl { get; set; }
|
||||
public string ManageUrl { get; set; }
|
||||
public bool IsUserLoggedIn { get; set; }
|
||||
public bool IsPraise { get; set; }
|
||||
}
|
||||
|
||||
|
||||
public class AdminEmailViewModel : EmailViewModel
|
||||
{
|
||||
public string PrayerTitle { get; set; }
|
||||
public string PrayerContent { get; set; }
|
||||
public string NotificationTypeMessage { get; set; }
|
||||
public string DetailUrl { get; set; }
|
||||
public string ManageUrl { get; set; }
|
||||
}
|
||||
}
|
44
Amen/Models/FacebookAuthModels.cs
Normal file
@ -0,0 +1,44 @@
|
||||
using Newtonsoft.Json;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Net.Http;
|
||||
using System.Web;
|
||||
|
||||
namespace Amen.Models
|
||||
{
|
||||
public class FacebookOauthResponse
|
||||
{
|
||||
public string access_token { get; set; }
|
||||
public string token_type { get; set; }
|
||||
public int expires_in { get; set; }
|
||||
}
|
||||
|
||||
public class FacebookBackChannelHandler : HttpClientHandler
|
||||
{
|
||||
protected override async System.Threading.Tasks.Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, System.Threading.CancellationToken cancellationToken)
|
||||
{
|
||||
var result = await base.SendAsync(request, cancellationToken);
|
||||
if (!request.RequestUri.AbsolutePath.Contains("access_token"))
|
||||
return result;
|
||||
|
||||
// For the access token we need to now deal with the fact that the response is now in JSON format, not form values. Owin looks for form values.
|
||||
var content = await result.Content.ReadAsStringAsync();
|
||||
var facebookOauthResponse = JsonConvert.DeserializeObject<FacebookOauthResponse>(content);
|
||||
|
||||
var outgoingQueryString = HttpUtility.ParseQueryString(string.Empty);
|
||||
outgoingQueryString.Add("access_token", facebookOauthResponse.access_token);
|
||||
outgoingQueryString.Add("expires_in", facebookOauthResponse.expires_in + string.Empty);
|
||||
outgoingQueryString.Add("token_type", facebookOauthResponse.token_type);
|
||||
var postdata = outgoingQueryString.ToString();
|
||||
|
||||
var modifiedResult = new HttpResponseMessage(HttpStatusCode.OK)
|
||||
{
|
||||
Content = new StringContent(postdata)
|
||||
};
|
||||
|
||||
return modifiedResult;
|
||||
}
|
||||
}
|
||||
}
|
217
Amen/Models/IdentityModels.cs
Normal file
@ -0,0 +1,217 @@
|
||||
using System.Data.Entity;
|
||||
using System.Security.Claims;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNet.Identity;
|
||||
using Microsoft.AspNet.Identity.EntityFramework;
|
||||
using System.Data.Entity.ModelConfiguration.Conventions;
|
||||
using System.Collections.Generic;
|
||||
using System;
|
||||
using Amen.Controllers;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
|
||||
namespace Amen.Models
|
||||
{
|
||||
|
||||
// You can add profile data for the user by adding more properties to your ApplicationUser class, please visit http://go.microsoft.com/fwlink/?LinkID=317594 to learn more.
|
||||
public class ApplicationUser : IdentityUser
|
||||
{
|
||||
public int AffiliateId { get; set; }
|
||||
public Affiliate Affiliate { get; set; }
|
||||
|
||||
[Display(Name = "Name")]
|
||||
public string FullName { get; set; }
|
||||
|
||||
|
||||
public bool EnableSmsNotifications { get; set; }
|
||||
public bool EnableEmailNotifications { get; set; }
|
||||
|
||||
public DateTime? LastLoginDateUtc { get; set; }
|
||||
|
||||
public string Location { get; set; }
|
||||
public bool ShouldShowLocation { get; set; }
|
||||
public bool ShouldShowName { get; set; }
|
||||
|
||||
[NotMapped]
|
||||
public bool IsSmsCapable
|
||||
{
|
||||
get
|
||||
{
|
||||
return !string.IsNullOrEmpty(this.PhoneNumber) && this.EnableSmsNotifications;
|
||||
}
|
||||
}
|
||||
|
||||
public virtual IList<Prayer> Prayers { get; set; }
|
||||
|
||||
public async Task<ClaimsIdentity> GenerateUserIdentityAsync(UserManager<ApplicationUser> manager)
|
||||
{
|
||||
// Note the authenticationType must match the one defined in CookieAuthenticationOptions.AuthenticationType
|
||||
var userIdentity = await manager.CreateIdentityAsync(this, DefaultAuthenticationTypes.ApplicationCookie);
|
||||
|
||||
userIdentity.AddClaim(new Claim("FullName", this.FullName));
|
||||
// Add custom user claims here
|
||||
return userIdentity;
|
||||
}
|
||||
}
|
||||
|
||||
public class ApplicationDbContext : IdentityDbContext<ApplicationUser>
|
||||
{
|
||||
public DbSet<Prayer> Prayers { get; set; }
|
||||
public DbSet<Affiliate> Affiliates { get; set; }
|
||||
public DbSet<PrayerBookmark> PrayerBookmarks { get; set; }
|
||||
public DbSet<PrayerSubscription> PrayerSubscriptions { get; set; }
|
||||
public DbSet<PrayerFlag> PrayerFlags { get; set; }
|
||||
public DbSet<PrayerItem> PrayerItems { get; set; }
|
||||
public DbSet<BlacklistEmail> BlacklistEmails { get; set; }
|
||||
public DbSet<BlacklistIP> BlacklistIPs { get; set; }
|
||||
public DbSet<AutoFlagItem> AutoFlagItems { get; set; }
|
||||
public DbSet<PrayerNote> PrayerNotes { get; set; }
|
||||
public DbSet<AffiliateStyle> AffiliateStyles { get; set; }
|
||||
public DbSet<AffiliateAdmin> AffiliateAdmins { get; set; }
|
||||
public DbSet<PrayerSource> PrayerSources { get; set; }
|
||||
public DbSet<SubscriptionType> SubscriptionTypes { get; set; }
|
||||
|
||||
public ApplicationDbContext()
|
||||
: base("AmenPrayer", throwIfV1Schema: false)
|
||||
{
|
||||
this.Database.CommandTimeout = 300;
|
||||
}
|
||||
|
||||
public static ApplicationDbContext Create()
|
||||
{
|
||||
return new ApplicationDbContext();
|
||||
}
|
||||
|
||||
|
||||
protected override void OnModelCreating(DbModelBuilder modelBuilder)
|
||||
{
|
||||
base.OnModelCreating(modelBuilder);
|
||||
|
||||
//keep table names singular
|
||||
modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();
|
||||
|
||||
//turn off cascade delete
|
||||
modelBuilder.Conventions.Remove<OneToManyCascadeDeleteConvention>();
|
||||
modelBuilder.Conventions.Remove<ManyToManyCascadeDeleteConvention>();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public class ApplicationDbContextInitializer : DropCreateDatabaseIfModelChanges<ApplicationDbContext>
|
||||
{
|
||||
private void SeedMembership(ApplicationDbContext db)
|
||||
{
|
||||
//var roles = Roles.Provider;
|
||||
//var membership = Membership.Provider;
|
||||
|
||||
//if (!roles.RoleExists("Administrator"))
|
||||
//{
|
||||
// roles.CreateRole("Administrator");
|
||||
//}
|
||||
//if (membership.GetUser("thannap", false) == null)
|
||||
//{
|
||||
// MembershipCreateStatus status;
|
||||
// membership.CreateUser("thannap", "password", "thannap@hotmail.com", "pass?", "password", true, null, out status);
|
||||
// //membership.CreateUserAndAccount("sallen", "imalittleteapot");
|
||||
//}
|
||||
//if (!roles.GetRolesForUser("thannap").Contains("Admin"))
|
||||
//{
|
||||
// roles.AddUsersToRoles(new[] { "thannap" }, new[] { "Admin" });
|
||||
//}
|
||||
}
|
||||
|
||||
protected override void Seed(ApplicationDbContext db)
|
||||
{
|
||||
var aff = db.Affiliates.Add(new Affiliate()
|
||||
{
|
||||
Key = ControllerHelper.DefaultAffiliateKey,
|
||||
IsActive = true,
|
||||
Name = "Amen",
|
||||
Instructions = "Amen: A prayer app",
|
||||
//Status = 0,
|
||||
//Level = 0,
|
||||
PrayerDaysThreshold = 30,
|
||||
//BlacklistEmails = "",
|
||||
//BlacklistIPs = "",
|
||||
EmailAdmin = "than@effectivepixels.net",
|
||||
EmailBilling = "than@effectivepixels.net",
|
||||
EmailFlag = "than@effectivepixels.net",
|
||||
FlagThreshold = 3,
|
||||
//HasCustomCSS = false,
|
||||
//MaxLengthPrayer = 1024,
|
||||
//MaxLengthStory = 1024,
|
||||
SendMessageNote = "Someone has sent you a note!",
|
||||
SendMessagePrayed = "Someone has prayed for you!",
|
||||
InstructionsAddPrayer = "This is text that shows up before the add prayer button",
|
||||
ShouldSendPrayerNotificationAdmin = true,
|
||||
ShouldSendPraiseNotificationAdmin = true,
|
||||
//ShouldUseBlacklist = true,
|
||||
TwilioAuthToken = "480bcbad18cd89e11ab5627532549c18",
|
||||
TwilioPhoneNumber = "2064296488",
|
||||
TwilioSID = "ACffd3ffac5601e6ee480e3ff6855d3b54",
|
||||
UrlLogo = "https://amen.blob.core.windows.net/logos/amen-logo.png",
|
||||
UrlWebsite = "http://www.amenprayer.com",
|
||||
IncludeInUniversal = true
|
||||
});
|
||||
|
||||
var aff2 = db.Affiliates.Add(new Affiliate()
|
||||
{
|
||||
Key = "joyfm",
|
||||
IsActive = true,
|
||||
Name = "Joy FM",
|
||||
Instructions = "Nap: There's a Nap for that",
|
||||
//Status = 0,
|
||||
//Level = 0,
|
||||
PrayerDaysThreshold = 30,
|
||||
//BlacklistEmails = "",
|
||||
//BlacklistIPs = "",
|
||||
EmailAdmin = "than@napclan.com",
|
||||
EmailBilling = "than@napclan.com",
|
||||
EmailFlag = "than@napclan.com",
|
||||
FlagThreshold = 3,
|
||||
//HasCustomCSS = false,
|
||||
//MaxLengthPrayer = 1024,
|
||||
//MaxLengthStory = 1024,
|
||||
SendMessageNote = "Someone has sent you a note!",
|
||||
SendMessagePrayed = "Someone has prayed for you!",
|
||||
InstructionsAddPrayer = "This is text that shows up before the add prayer button",
|
||||
ShouldSendPrayerNotificationAdmin = true,
|
||||
ShouldSendPraiseNotificationAdmin = true,
|
||||
//ShouldUseBlacklist = true,
|
||||
TwilioAuthToken = "480bcbad18cd89e11ab5627532549c18",
|
||||
TwilioPhoneNumber = "2064296488",
|
||||
TwilioSID = "ACffd3ffac5601e6ee480e3ff6855d3b54",
|
||||
UrlLogo = "https://amen.blob.core.windows.net/logos/joy-logo.gif",
|
||||
UrlWebsite = "http://www.napclan.com",
|
||||
IncludeInUniversal = false
|
||||
});
|
||||
db.SaveChanges();
|
||||
|
||||
for (int i = 0; i < 100; i++)
|
||||
{
|
||||
db.Prayers.Add(new Prayer()
|
||||
{
|
||||
Summary = "Prayer Summary " + i.ToString(),
|
||||
Content = i.ToString() + " - Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vestibulum gravida fringilla dui mattis consequat.\r\rDonec ultrices facilisis metus, et ultrices erat efficitur non. Nunc viverra id nulla id pulvinar. Donec posuere, nibh a pretium tempus, leo enim bibendum metus, eu efficitur justo tellus ullamcorper purus. Mauris mi dui, porta quis pellentesque laoreet, finibus sollicitudin elit. Cras maximus dui lorem, at tincidunt metus egestas ac. Nam vitae neque tincidunt, pulvinar nibh id, molestie nisl. Aliquam nec libero faucibus, aliquet urna ut, ultrices diam. Aenean purus tortor, pulvinar sit amet arcu a, lacinia tristique est.",
|
||||
CreatedUTC = System.DateTime.UtcNow,
|
||||
AffiliateId = i % 2 == 0 ? aff.Id : aff2.Id,
|
||||
AgreeTermsOfUse = true,
|
||||
AnonymousEmail = "thannap@gmail.com",
|
||||
AnonymousName = "Annon Than",
|
||||
//AnonymousPhone = "2067550211",
|
||||
EnableEmailNote = i % 3 == 0,
|
||||
EnableEmailNotification = i % 4 == 0,
|
||||
EnableTextNotification = i % 5 == 0,
|
||||
IsActive = true,
|
||||
IsPraise = i % 5 == 0,
|
||||
CountFlagged = 0,
|
||||
CountPrayed = (int)Math.Floor((double)i % 5),
|
||||
PrayerSourceId = (int)PrayerSourceEnum.Web
|
||||
});
|
||||
db.SaveChanges();
|
||||
}
|
||||
|
||||
SeedMembership(db);
|
||||
}
|
||||
}
|
||||
}
|
115
Amen/Models/ManageViewModels.cs
Normal file
@ -0,0 +1,115 @@
|
||||
using Microsoft.AspNet.Identity;
|
||||
using Microsoft.Owin.Security;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace Amen.Models
|
||||
{
|
||||
public class SaveProfileViewModel
|
||||
{
|
||||
public string FullName { get; set; }
|
||||
public string Location { get; set; }
|
||||
public bool EnableEmailNotifications { get; set; }
|
||||
public bool EnableSmsNotifications { get; set; }
|
||||
public bool ShouldShowName { get; set; }
|
||||
public bool ShouldShowLocation { get; set; }
|
||||
}
|
||||
|
||||
public class IndexViewModel
|
||||
{
|
||||
public bool HasPassword { get; set; }
|
||||
|
||||
public IList<UserLoginInfo> Logins { get; set; }
|
||||
public string PhoneNumber { get; set; }
|
||||
public bool TwoFactor { get; set; }
|
||||
public bool BrowserRemembered { get; set; }
|
||||
public string FullName { get; set; }
|
||||
|
||||
public string Location { get; set; }
|
||||
|
||||
[Display(Name="Enable Text Notifications")]
|
||||
public bool EnableSmsNotifications { get; set; }
|
||||
[Display(Name = "Enable Email Notifications")]
|
||||
public bool EnableEmailNotifications { get; set; }
|
||||
|
||||
[Display(Name = "Allow My Name To Be Shown When Posting")]
|
||||
public bool ShouldShowName { get; set; }
|
||||
|
||||
[Display(Name = "Allow My Location To Be Shown When Posting")]
|
||||
public bool ShouldShowLocation { get; set; }
|
||||
|
||||
public bool AffiliateSmsCapable { get; set; }
|
||||
public bool AffiliateEnableShowLocation { get; set; }
|
||||
public bool AffiliateEnableShowName { get; set; }
|
||||
}
|
||||
|
||||
public class ManageLoginsViewModel
|
||||
{
|
||||
public IList<UserLoginInfo> CurrentLogins { get; set; }
|
||||
public IList<AuthenticationDescription> OtherLogins { get; set; }
|
||||
}
|
||||
|
||||
public class FactorViewModel
|
||||
{
|
||||
public string Purpose { get; set; }
|
||||
}
|
||||
|
||||
public class SetPasswordViewModel
|
||||
{
|
||||
[Required]
|
||||
[StringLength(100, ErrorMessage = "The {0} must be at least {2} characters long.", MinimumLength = 6)]
|
||||
[DataType(DataType.Password)]
|
||||
[Display(Name = "New password")]
|
||||
public string NewPassword { get; set; }
|
||||
|
||||
[DataType(DataType.Password)]
|
||||
[Display(Name = "Confirm new password")]
|
||||
[Compare("NewPassword", ErrorMessage = "The new password and confirmation password do not match.")]
|
||||
public string ConfirmPassword { get; set; }
|
||||
}
|
||||
|
||||
public class ChangePasswordViewModel
|
||||
{
|
||||
[Required]
|
||||
[DataType(DataType.Password)]
|
||||
[Display(Name = "Current password")]
|
||||
public string OldPassword { get; set; }
|
||||
|
||||
[Required]
|
||||
[StringLength(100, ErrorMessage = "The {0} must be at least {2} characters long.", MinimumLength = 6)]
|
||||
[DataType(DataType.Password)]
|
||||
[Display(Name = "New password")]
|
||||
public string NewPassword { get; set; }
|
||||
|
||||
[DataType(DataType.Password)]
|
||||
[Display(Name = "Confirm new password")]
|
||||
[Compare("NewPassword", ErrorMessage = "The new password and confirmation password do not match.")]
|
||||
public string ConfirmPassword { get; set; }
|
||||
}
|
||||
|
||||
public class AddPhoneNumberViewModel
|
||||
{
|
||||
[Required]
|
||||
[Phone]
|
||||
[Display(Name = "Phone Number")]
|
||||
public string Number { get; set; }
|
||||
}
|
||||
|
||||
public class VerifyPhoneNumberViewModel
|
||||
{
|
||||
[Required]
|
||||
[Display(Name = "Code")]
|
||||
public string Code { get; set; }
|
||||
|
||||
[Required]
|
||||
[Phone]
|
||||
[Display(Name = "Phone Number")]
|
||||
public string PhoneNumber { get; set; }
|
||||
}
|
||||
|
||||
public class ConfigureTwoFactorViewModel
|
||||
{
|
||||
public string SelectedProvider { get; set; }
|
||||
public ICollection<System.Web.Mvc.SelectListItem> Providers { get; set; }
|
||||
}
|
||||
}
|
142
Amen/Models/Prayer.cs
Normal file
@ -0,0 +1,142 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
using System.Linq;
|
||||
using System.Web;
|
||||
|
||||
namespace Amen.Models
|
||||
{
|
||||
public class Prayer
|
||||
{
|
||||
public int Id { get; set; }
|
||||
|
||||
public int PWId { get; set; }
|
||||
|
||||
public int AffiliateId { get; set; }
|
||||
|
||||
public Affiliate Affiliate { get; set; }
|
||||
|
||||
[ForeignKey("ApplicationUser")]
|
||||
public string ApplicationUserId { get; set; }
|
||||
|
||||
public ApplicationUser ApplicationUser { get; set; }
|
||||
|
||||
[Display(Name = "Active?")]
|
||||
public bool IsActive { get; set; }
|
||||
|
||||
public bool IsDeleted { get; set; }
|
||||
|
||||
[Display(Name = "Enable Text Notifications?")]
|
||||
public bool EnableTextNotification { get; set; }
|
||||
|
||||
[Display(Name = "Enable Email Notifications?")]
|
||||
public bool EnableEmailNotification { get; set; }
|
||||
|
||||
[Display(Name = "Enable Note of Encouragement?")]
|
||||
public bool EnableEmailNote { get; set; }
|
||||
|
||||
[Display(Name = "Title")]
|
||||
public string Summary { get; set; }
|
||||
|
||||
[DataType(DataType.MultilineText)]
|
||||
public string Content { get; set; }
|
||||
|
||||
public bool IsPraise { get; set; }
|
||||
|
||||
[Display(Name = "Anonymous Name")]
|
||||
public string AnonymousName { get; set; }
|
||||
|
||||
[Display(Name = "Anonymous Email")]
|
||||
public string AnonymousEmail { get; set; }
|
||||
|
||||
[Display(Name = "Phone")]
|
||||
public string AnonymousPhone { get; set; }
|
||||
|
||||
[Display(Name = "Share this?")]
|
||||
public string ShareThis { get; set; }
|
||||
|
||||
[Display(Name = "Contact Preference")]
|
||||
public string ContactPreference { get; set; }
|
||||
|
||||
[Display(Name="Terms?")]
|
||||
public bool AgreeTermsOfUse { get; set; }
|
||||
|
||||
[Display(Name = "IP")]
|
||||
public string IPAddress { get; set; }
|
||||
|
||||
public string UserAgent { get; set; }
|
||||
|
||||
public DateTime? ModifiedUTC { get; set; }
|
||||
|
||||
[DisplayFormat(DataFormatString="{0:MMM d, yyyy}")]
|
||||
[Display(Name = "Created")]
|
||||
public DateTime CreatedUTC { get; set; }
|
||||
|
||||
[Display(Name = "Prayed")]
|
||||
public int CountPrayed { get; set; }
|
||||
|
||||
[Display(Name="Flagged")]
|
||||
public int CountFlagged { get; set; }
|
||||
|
||||
public int? PrayerSourceId { get; set; }
|
||||
|
||||
public PrayerSource PrayerSource { get; set; }
|
||||
|
||||
public virtual IList<PrayerItem> PrayerItems { get; set; }
|
||||
|
||||
public virtual IList<PrayerFlag> PrayerFlags { get; set; }
|
||||
|
||||
public virtual IList<PrayerNote> PrayerNotes { get; set; }
|
||||
|
||||
public virtual IList<PrayerBookmark> PrayerBookmarks { get; set; }
|
||||
|
||||
public virtual IList<PrayerSubscription> PrayerSubscriptions { get; set; }
|
||||
|
||||
|
||||
[ForeignKey("ParentPrayer")]
|
||||
public int? ParentPrayerId { get; set; }
|
||||
|
||||
public virtual Prayer ParentPrayer { get; set; }
|
||||
|
||||
public virtual ICollection<Prayer> ChildPrayers { get; set; }
|
||||
|
||||
[NotMapped]
|
||||
public string ContentElipsis
|
||||
{
|
||||
get
|
||||
{
|
||||
if (string.IsNullOrEmpty(this.Content) || this.Content.Length <= 50)
|
||||
return this.Content;
|
||||
|
||||
else
|
||||
return this.Content.Substring(0, Math.Min(100, this.Content.Length)) + "...";
|
||||
}
|
||||
}
|
||||
|
||||
[NotMapped]
|
||||
public string DisplayUserName
|
||||
{
|
||||
get
|
||||
{
|
||||
if (this.ApplicationUser != null)
|
||||
return this.ApplicationUser.FullName;
|
||||
else
|
||||
return this.AnonymousName;
|
||||
}
|
||||
}
|
||||
|
||||
[NotMapped]
|
||||
public string DisplayUserEmail
|
||||
{
|
||||
get
|
||||
{
|
||||
if (this.ApplicationUser != null)
|
||||
return this.ApplicationUser.Email;
|
||||
else
|
||||
return this.AnonymousEmail;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
22
Amen/Models/PrayerBookmark.cs
Normal file
@ -0,0 +1,22 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
using System.Linq;
|
||||
using System.Web;
|
||||
|
||||
namespace Amen.Models
|
||||
{
|
||||
public class PrayerBookmark
|
||||
{
|
||||
public int Id { get; set; }
|
||||
|
||||
public int PrayerId { get; set; }
|
||||
public Prayer Prayer { get; set; }
|
||||
|
||||
[ForeignKey("ApplicationUser")]
|
||||
public string ApplicationUserId { get; set; }
|
||||
public ApplicationUser ApplicationUser { get; set; }
|
||||
|
||||
public DateTime CreatedUTC { get; set; }
|
||||
}
|
||||
}
|
28
Amen/Models/PrayerFlag.cs
Normal file
@ -0,0 +1,28 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
using System.Linq;
|
||||
using System.Web;
|
||||
|
||||
namespace Amen.Models
|
||||
{
|
||||
public class PrayerFlag
|
||||
{
|
||||
public int Id { get; set; }
|
||||
|
||||
public int PrayerId { get; set; }
|
||||
public Prayer Prayer { get; set; }
|
||||
|
||||
[ForeignKey("ApplicationUser")]
|
||||
public string ApplicationUserId { get; set; }
|
||||
public ApplicationUser ApplicationUser { get; set; }
|
||||
|
||||
public string AnonymousName { get; set; }
|
||||
public string AnonymousEmail { get; set; }
|
||||
|
||||
public string Reason { get; set; }
|
||||
|
||||
public DateTime CreatedUTC { get; set; }
|
||||
|
||||
}
|
||||
}
|
25
Amen/Models/PrayerItem.cs
Normal file
@ -0,0 +1,25 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
using System.Linq;
|
||||
using System.Web;
|
||||
|
||||
namespace Amen.Models
|
||||
{
|
||||
public class PrayerItem
|
||||
{
|
||||
public int Id { get; set; }
|
||||
|
||||
public int PrayerId { get; set; }
|
||||
public Prayer Prayer { get; set; }
|
||||
|
||||
[ForeignKey("ApplicationUser")]
|
||||
public string ApplicationUserId { get; set; }
|
||||
public ApplicationUser ApplicationUser { get; set; }
|
||||
|
||||
public string IPAddress { get; set; }
|
||||
public string UserAgent { get; set; }
|
||||
|
||||
public DateTime CreatedUTC { get; set; }
|
||||
}
|
||||
}
|
27
Amen/Models/PrayerNote.cs
Normal file
@ -0,0 +1,27 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
using System.Linq;
|
||||
using System.Web;
|
||||
|
||||
namespace Amen.Models
|
||||
{
|
||||
public class PrayerNote
|
||||
{
|
||||
public int Id { get; set; }
|
||||
|
||||
public int PrayerId { get; set; }
|
||||
public Prayer Prayer { get; set; }
|
||||
|
||||
[ForeignKey("ApplicationUser")]
|
||||
public string ApplicationUserId { get; set; }
|
||||
public ApplicationUser ApplicationUser { get; set; }
|
||||
|
||||
public string NoteText { get; set; }
|
||||
|
||||
public string IPAddress { get; set; }
|
||||
public string UserAgent { get; set; }
|
||||
|
||||
public DateTime CreatedUTC { get; set; }
|
||||
}
|
||||
}
|
52
Amen/Models/PrayerSource.cs
Normal file
@ -0,0 +1,52 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
using System.Linq;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Web;
|
||||
|
||||
namespace Amen.Models
|
||||
{
|
||||
public enum PrayerSourceEnum
|
||||
{
|
||||
Web = 1,
|
||||
iOS = 2
|
||||
}
|
||||
|
||||
public class PrayerSource
|
||||
{
|
||||
public int Id { get; set; }
|
||||
public string Label { get; set; }
|
||||
public string Description { get; set; }
|
||||
|
||||
[NotMapped]
|
||||
public PrayerSourceEnum EnumValue
|
||||
{
|
||||
get
|
||||
{
|
||||
return (PrayerSourceEnum)this.Id;
|
||||
}
|
||||
set
|
||||
{
|
||||
this.Id = (int)value;
|
||||
}
|
||||
}
|
||||
|
||||
public static int DeterminePrayerSource(string userAgent)
|
||||
{
|
||||
userAgent = userAgent ?? "";
|
||||
var isWebView = Regex.IsMatch(userAgent, "((iPhone|iPod|iPad).*AppleWebKit(?!.*(Safari|CriOS)))", RegexOptions.IgnoreCase);
|
||||
isWebView = isWebView || userAgent.Contains("AmenPrayer iOS");
|
||||
|
||||
if (isWebView)
|
||||
{
|
||||
return (int)PrayerSourceEnum.iOS;
|
||||
}
|
||||
else
|
||||
{
|
||||
return (int)PrayerSourceEnum.Web;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
22
Amen/Models/PrayerSubscription.cs
Normal file
@ -0,0 +1,22 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
using System.Linq;
|
||||
using System.Web;
|
||||
|
||||
namespace Amen.Models
|
||||
{
|
||||
public class PrayerSubscription
|
||||
{
|
||||
public int Id { get; set; }
|
||||
|
||||
public int PrayerId { get; set; }
|
||||
public Prayer Prayer { get; set; }
|
||||
|
||||
[ForeignKey("ApplicationUser")]
|
||||
public string ApplicationUserId { get; set; }
|
||||
public ApplicationUser ApplicationUser { get; set; }
|
||||
|
||||
public DateTime CreatedUTC { get; set; }
|
||||
}
|
||||
}
|
214
Amen/Models/PrayerViewModels.cs
Normal file
@ -0,0 +1,214 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Web;
|
||||
|
||||
namespace Amen.Models
|
||||
{
|
||||
public class PrayersViewModel
|
||||
{
|
||||
public string Instructions { get; set; }
|
||||
public string InstructionsPraise { get; set; }
|
||||
public string InstructionsAddPrayer { get; set; }
|
||||
public string InstructionsAddPraise { get; set; }
|
||||
public string InstructionsNote { get; set; }
|
||||
public bool ShouldOpenSubmit { get; set; }
|
||||
public bool IsDetail { get; set; }
|
||||
public bool IsPraise { get; set; }
|
||||
public bool IsUserAuthenticated { get; set; }
|
||||
public string AuthenticatedUserEmail { get; set; }
|
||||
public bool IsAffiliateSmsCapable { get; set; }
|
||||
public bool IsUserSmsCapable { get; set; }
|
||||
public bool EnableNotifications { get; set; }
|
||||
public bool IsAffiliateNotesEnabled { get; set; }
|
||||
public bool ShouldReturnToUserPage { get; set; }
|
||||
public IList<PrayerItemViewModel> Prayers { get; set; }
|
||||
|
||||
public bool ShowPraiseListInstructions
|
||||
{
|
||||
get
|
||||
{
|
||||
return !this.IsDetail && this.IsPraise && !string.IsNullOrEmpty(InstructionsPraise);
|
||||
}
|
||||
}
|
||||
|
||||
public bool ShowPrayerListInstructions
|
||||
{
|
||||
get
|
||||
{
|
||||
return !this.IsDetail && !this.IsPraise && !string.IsNullOrEmpty(Instructions);
|
||||
}
|
||||
}
|
||||
|
||||
public bool ShowAddPraiseInstructions
|
||||
{
|
||||
get
|
||||
{
|
||||
return this.IsPraise && !string.IsNullOrEmpty(InstructionsAddPraise);
|
||||
}
|
||||
}
|
||||
|
||||
public bool ShowAddPrayerInstructions
|
||||
{
|
||||
get
|
||||
{
|
||||
return !this.IsPraise && !string.IsNullOrEmpty(InstructionsAddPrayer);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class PrayerItemViewModel
|
||||
{
|
||||
public int Id { get; set; }
|
||||
public string UserName { get; set; }
|
||||
public string UserLocation { get; set; }
|
||||
public string Summary { get; set; }
|
||||
public string Content { get; set; }
|
||||
public string ContentElipsis
|
||||
{
|
||||
get
|
||||
{
|
||||
if (string.IsNullOrEmpty(this.Content) || this.Content.Length <= 50)
|
||||
return this.Content;
|
||||
|
||||
else
|
||||
return this.Content.Substring(0, Math.Min(100, this.Content.Length)) + "...";
|
||||
}
|
||||
}
|
||||
public bool IsPraise { get; set; }
|
||||
public int CountPrayed { get; set; }
|
||||
public bool EnableEmailNote { get; set; }
|
||||
|
||||
//public bool IsUserAuthenticated { get; set; }
|
||||
public string ShareThis { get; set; }
|
||||
public bool EnableNotifications { get; set; }
|
||||
public bool IsAffiliateNotesEnabled { get; set; }
|
||||
public bool IsUserSubscribed { get; set; }
|
||||
public bool IsUserBookmarked { get; set; }
|
||||
public bool EnableEdit { get; set; }
|
||||
public DateTime CreatedUTC { get; set; }
|
||||
public int OffsetMinutes { get; set; }
|
||||
public string DetailUrl { get; set; }
|
||||
public string UrlLogo { get; set; }
|
||||
|
||||
public string DisplaySubmittedDate
|
||||
{
|
||||
get
|
||||
{
|
||||
var now = DateTime.UtcNow.AddMinutes(-this.OffsetMinutes);
|
||||
var created = this.CreatedUTC.AddMinutes(-this.OffsetMinutes);
|
||||
var diffMinutes = Math.Round((now - created).TotalMinutes);
|
||||
var hours = Math.Round( diffMinutes / 60);
|
||||
|
||||
if (diffMinutes <= 1)
|
||||
return "1 minute ago";
|
||||
else if (diffMinutes < 60)
|
||||
return string.Format("{0} minutes ago", diffMinutes);
|
||||
else if (hours == 1)
|
||||
return "1 hour ago";
|
||||
else if (hours <= 12)
|
||||
return string.Format("{0} hours ago", hours);
|
||||
else if (created.DayOfYear != now.DayOfYear)
|
||||
return string.Format("{0:MMM d, yyyy}", created);
|
||||
else
|
||||
return string.Format("{0} hours ago", hours);
|
||||
}
|
||||
}
|
||||
|
||||
public string DisplaySubscribeText
|
||||
{
|
||||
get
|
||||
{
|
||||
return this.IsUserSubscribed ? "Unsubscribe" : "Subscribe";
|
||||
}
|
||||
}
|
||||
|
||||
public string DisplayBookmarkText
|
||||
{
|
||||
get
|
||||
{
|
||||
return this.IsUserBookmarked ? "Remove Bookmark" : "Bookmark";
|
||||
}
|
||||
}
|
||||
|
||||
public string ShareFacebookUrl
|
||||
{
|
||||
get
|
||||
{
|
||||
return string.Format("https://www.facebook.com/sharer/sharer.php?u={0}", HttpUtility.UrlEncode(DetailUrl));
|
||||
}
|
||||
}
|
||||
|
||||
public string ShareTwitterUrl
|
||||
{
|
||||
get
|
||||
{
|
||||
return string.Format("https://twitter.com/home?status={0}", HttpUtility.UrlEncode(DetailUrl));
|
||||
}
|
||||
}
|
||||
|
||||
public string ShareEmailUrl
|
||||
{
|
||||
get
|
||||
{
|
||||
return string.Format("mailto:?&subject={0}&body={1}", HttpUtility.UrlPathEncode("Amen Prayer - " + this.Summary), HttpUtility.UrlPathEncode("Please pray with me - " + this.DetailUrl));
|
||||
}
|
||||
}
|
||||
|
||||
public bool HasUserName
|
||||
{
|
||||
get { return !string.IsNullOrEmpty(this.UserName); }
|
||||
}
|
||||
|
||||
public bool HasUserLocation
|
||||
{
|
||||
get { return !string.IsNullOrEmpty(this.UserLocation); }
|
||||
}
|
||||
|
||||
public bool HasUserNameAndLocation
|
||||
{
|
||||
get { return HasUserName && HasUserLocation; }
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
//public class PrayerFlagViewModel
|
||||
//{
|
||||
// public int Id { get; set; }
|
||||
// public string Reason { get; set; }
|
||||
// public string Name { get; set; }
|
||||
// public string Email { get; set; }
|
||||
//}
|
||||
|
||||
public class PrayerEditViewModel
|
||||
{
|
||||
public int Id { get; set; }
|
||||
|
||||
public string Summary { get; set; }
|
||||
|
||||
public string Content { get; set; }
|
||||
|
||||
public bool IsNew { get; set; }
|
||||
|
||||
public bool IsPraise { get; set; }
|
||||
|
||||
public bool AgreeTermsOfUse { get; set; }
|
||||
|
||||
public string AnonymousName { get; set; }
|
||||
|
||||
public string AnonymousEmail { get; set; }
|
||||
|
||||
public string AnonymousPhone { get; set; }
|
||||
|
||||
public string ShareThis { get; set; }
|
||||
|
||||
public string ContactPreference { get; set; }
|
||||
|
||||
public bool EnableEmailNote { get; set; }
|
||||
|
||||
public bool EnableEmailNotification { get; set; }
|
||||
|
||||
public bool EnableTextNotification { get; set; }
|
||||
}
|
||||
}
|
24
Amen/Models/RelatedPrayer.cs
Normal file
@ -0,0 +1,24 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
using System.Linq;
|
||||
using System.Web;
|
||||
|
||||
namespace Amen.Models
|
||||
{
|
||||
//public class RelatedPrayer
|
||||
//{
|
||||
// [Key, Column(Order = 0)]
|
||||
// [ForeignKey("Prayer")]
|
||||
// public string ParentPrayerId { get; set; }
|
||||
// public Prayer ParentPrayer { get; set; }
|
||||
|
||||
// [Key, Column(Order = 1)]
|
||||
// [ForeignKey("Prayer")]
|
||||
// public int ChildPrayerId { get; set; }
|
||||
// public Prayer ChildPrayer { get; set; }
|
||||
|
||||
// public DateTime CreatedUTC { get; set; }
|
||||
//}
|
||||
}
|
37
Amen/Models/SubscriptionType.cs
Normal file
@ -0,0 +1,37 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
using System.Linq;
|
||||
using System.Web;
|
||||
|
||||
namespace Amen.Models
|
||||
{
|
||||
public enum SubscriptionTypeEnum
|
||||
{
|
||||
Basic = 1,
|
||||
BasicPlus = 2,
|
||||
Demo = 3
|
||||
}
|
||||
|
||||
public class SubscriptionType
|
||||
{
|
||||
public int Id { get; set; }
|
||||
[Display(Name = "Subscription Type")]
|
||||
public string Label { get; set; }
|
||||
public string Description { get; set; }
|
||||
|
||||
[NotMapped]
|
||||
public SubscriptionTypeEnum EnumValue
|
||||
{
|
||||
get
|
||||
{
|
||||
return (SubscriptionTypeEnum)this.Id;
|
||||
}
|
||||
set
|
||||
{
|
||||
this.Id = (int)value;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
151
Amen/Project_Readme.html
Normal file
@ -0,0 +1,151 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<title>Your ASP.NET application</title>
|
||||
<style>
|
||||
body {
|
||||
background: #fff;
|
||||
color: #505050;
|
||||
font: 14px 'Segoe UI', tahoma, arial, helvetica, sans-serif;
|
||||
margin: 20px;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
#header {
|
||||
background: #efefef;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-size: 48px;
|
||||
font-weight: normal;
|
||||
margin: 0;
|
||||
padding: 0 30px;
|
||||
line-height: 150px;
|
||||
}
|
||||
|
||||
p {
|
||||
font-size: 20px;
|
||||
color: #fff;
|
||||
background: #969696;
|
||||
padding: 0 30px;
|
||||
line-height: 50px;
|
||||
}
|
||||
|
||||
#main {
|
||||
padding: 5px 30px;
|
||||
}
|
||||
|
||||
.section {
|
||||
width: 21.7%;
|
||||
float: left;
|
||||
margin: 0 0 0 4%;
|
||||
}
|
||||
|
||||
.section h2 {
|
||||
font-size: 13px;
|
||||
text-transform: uppercase;
|
||||
margin: 0;
|
||||
border-bottom: 1px solid silver;
|
||||
padding-bottom: 12px;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.section.first {
|
||||
margin-left: 0;
|
||||
}
|
||||
|
||||
.section.first h2 {
|
||||
font-size: 24px;
|
||||
text-transform: none;
|
||||
margin-bottom: 25px;
|
||||
border: none;
|
||||
}
|
||||
|
||||
.section.first li {
|
||||
border-top: 1px solid silver;
|
||||
padding: 8px 0;
|
||||
}
|
||||
|
||||
.section.last {
|
||||
margin-right: 0;
|
||||
}
|
||||
|
||||
ul {
|
||||
list-style: none;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
line-height: 20px;
|
||||
}
|
||||
|
||||
li {
|
||||
padding: 4px 0;
|
||||
}
|
||||
|
||||
a {
|
||||
color: #267cb2;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
a:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<div id="header">
|
||||
<h1>Your ASP.NET application</h1>
|
||||
<p>Congratulations! You've created a project</p>
|
||||
</div>
|
||||
|
||||
<div id="main">
|
||||
<div class="section first">
|
||||
<h2>This application consists of:</h2>
|
||||
<ul>
|
||||
<li>Sample pages showing basic nav between Home, About, and Contact</li>
|
||||
<li>Theming using <a href="http://go.microsoft.com/fwlink/?LinkID=320754">Bootstrap</a></li>
|
||||
<li><a href="http://go.microsoft.com/fwlink/?LinkID=320755">Authentication</a>, if selected, shows how to register and sign in</li>
|
||||
<li>ASP.NET features managed using <a href="http://go.microsoft.com/fwlink/?LinkID=320756">NuGet</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="section">
|
||||
<h2>Customize app</h2>
|
||||
<ul>
|
||||
<li><a href="http://go.microsoft.com/fwlink/?LinkID=320757">Get started with ASP.NET MVC</a></li>
|
||||
<li><a href="http://go.microsoft.com/fwlink/?LinkID=320758">Change the site's theme</a></li>
|
||||
<li><a href="http://go.microsoft.com/fwlink/?LinkID=320759">Add more libraries using NuGet</a></li>
|
||||
<li><a href="http://go.microsoft.com/fwlink/?LinkID=320760">Configure authentication</a></li>
|
||||
<li><a href="http://go.microsoft.com/fwlink/?LinkID=320761">Customize information about the website users</a></li>
|
||||
<li><a href="http://go.microsoft.com/fwlink/?LinkID=320762">Get information from social providers</a></li>
|
||||
<li><a href="http://go.microsoft.com/fwlink/?LinkID=320763">Add HTTP services using ASP.NET Web API</a></li>
|
||||
<li><a href="http://go.microsoft.com/fwlink/?LinkID=320764">Secure your web API</a></li>
|
||||
<li><a href="http://go.microsoft.com/fwlink/?LinkID=320765">Add real-time web with ASP.NET SignalR</a></li>
|
||||
<li><a href="http://go.microsoft.com/fwlink/?LinkID=320766">Add components using Scaffolding</a></li>
|
||||
<li><a href="http://go.microsoft.com/fwlink/?LinkID=320767">Test your app with Browser Link</a></li>
|
||||
<li><a href="http://go.microsoft.com/fwlink/?LinkID=320768">Share your project</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="section">
|
||||
<h2>Deploy</h2>
|
||||
<ul>
|
||||
<li><a href="http://go.microsoft.com/fwlink/?LinkID=320769">Ensure your app is ready for production</a></li>
|
||||
<li><a href="http://go.microsoft.com/fwlink/?LinkID=320770">Microsoft Azure</a></li>
|
||||
<li><a href="http://go.microsoft.com/fwlink/?LinkID=320771">Hosting providers</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="section last">
|
||||
<h2>Get help</h2>
|
||||
<ul>
|
||||
<li><a href="http://go.microsoft.com/fwlink/?LinkID=320772">Get help</a></li>
|
||||
<li><a href="http://go.microsoft.com/fwlink/?LinkID=320773">Get more templates</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</body>
|
||||
</html>
|
35
Amen/Properties/AssemblyInfo.cs
Normal file
@ -0,0 +1,35 @@
|
||||
using System.Reflection;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
// General Information about an assembly is controlled through the following
|
||||
// set of attributes. Change these attribute values to modify the information
|
||||
// associated with an assembly.
|
||||
[assembly: AssemblyTitle("Amen")]
|
||||
[assembly: AssemblyDescription("")]
|
||||
[assembly: AssemblyConfiguration("")]
|
||||
[assembly: AssemblyCompany("")]
|
||||
[assembly: AssemblyProduct("Amen")]
|
||||
[assembly: AssemblyCopyright("Copyright © 2016")]
|
||||
[assembly: AssemblyTrademark("")]
|
||||
[assembly: AssemblyCulture("")]
|
||||
|
||||
// Setting ComVisible to false makes the types in this assembly not visible
|
||||
// to COM components. If you need to access a type in this assembly from
|
||||
// COM, set the ComVisible attribute to true on that type.
|
||||
[assembly: ComVisible(false)]
|
||||
|
||||
// The following GUID is for the ID of the typelib if this project is exposed to COM
|
||||
[assembly: Guid("4699afe3-6d5c-43bd-b9e6-4c06583eae1f")]
|
||||
|
||||
// Version information for an assembly consists of the following four values:
|
||||
//
|
||||
// Major Version
|
||||
// Minor Version
|
||||
// Build Number
|
||||
// Revision
|
||||
//
|
||||
// You can specify all the values or you can default the Revision and Build Numbers
|
||||
// by using the '*' as shown below:
|
||||
[assembly: AssemblyVersion("1.0.*")]
|
||||
[assembly: AssemblyFileVersion("1.0.*")]
|
BIN
Amen/Scripts/_references.js
Normal file
92
Amen/Scripts/bootstrap-tagsinput-angular.js
vendored
Normal file
@ -0,0 +1,92 @@
|
||||
/*
|
||||
* bootstrap-tagsinput v0.8.0
|
||||
*
|
||||
*/
|
||||
|
||||
angular.module('bootstrap-tagsinput', [])
|
||||
.directive('bootstrapTagsinput', [function() {
|
||||
|
||||
function getItemProperty(scope, property) {
|
||||
if (!property)
|
||||
return undefined;
|
||||
|
||||
if (angular.isFunction(scope.$parent[property]))
|
||||
return scope.$parent[property];
|
||||
|
||||
return function(item) {
|
||||
return item[property];
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
restrict: 'EA',
|
||||
scope: {
|
||||
model: '=ngModel'
|
||||
},
|
||||
template: '<select multiple></select>',
|
||||
replace: false,
|
||||
link: function(scope, element, attrs) {
|
||||
$(function() {
|
||||
if (!angular.isArray(scope.model))
|
||||
scope.model = [];
|
||||
|
||||
var select = $('select', element);
|
||||
var typeaheadSourceArray = attrs.typeaheadSource ? attrs.typeaheadSource.split('.') : null;
|
||||
var typeaheadSource = typeaheadSourceArray ?
|
||||
(typeaheadSourceArray.length > 1 ?
|
||||
scope.$parent[typeaheadSourceArray[0]][typeaheadSourceArray[1]]
|
||||
: scope.$parent[typeaheadSourceArray[0]])
|
||||
: null;
|
||||
|
||||
select.tagsinput(scope.$parent[attrs.options || ''] || {
|
||||
typeahead : {
|
||||
source : angular.isFunction(typeaheadSource) ? typeaheadSource : null
|
||||
},
|
||||
itemValue: getItemProperty(scope, attrs.itemvalue),
|
||||
itemText : getItemProperty(scope, attrs.itemtext),
|
||||
confirmKeys : getItemProperty(scope, attrs.confirmkeys) ? JSON.parse(attrs.confirmkeys) : [13],
|
||||
tagClass : angular.isFunction(scope.$parent[attrs.tagclass]) ? scope.$parent[attrs.tagclass] : function(item) { return attrs.tagclass; }
|
||||
});
|
||||
|
||||
for (var i = 0; i < scope.model.length; i++) {
|
||||
select.tagsinput('add', scope.model[i]);
|
||||
}
|
||||
|
||||
select.on('itemAdded', function(event) {
|
||||
if (scope.model.indexOf(event.item) === -1)
|
||||
scope.model.push(event.item);
|
||||
});
|
||||
|
||||
select.on('itemRemoved', function(event) {
|
||||
var idx = scope.model.indexOf(event.item);
|
||||
if (idx !== -1)
|
||||
scope.model.splice(idx, 1);
|
||||
});
|
||||
|
||||
// create a shallow copy of model's current state, needed to determine
|
||||
// diff when model changes
|
||||
var prev = scope.model.slice();
|
||||
scope.$watch("model", function() {
|
||||
var added = scope.model.filter(function(i) {return prev.indexOf(i) === -1;}),
|
||||
removed = prev.filter(function(i) {return scope.model.indexOf(i) === -1;}),
|
||||
i;
|
||||
|
||||
prev = scope.model.slice();
|
||||
|
||||
// Remove tags no longer in binded model
|
||||
for (i = 0; i < removed.length; i++) {
|
||||
select.tagsinput('remove', removed[i]);
|
||||
}
|
||||
|
||||
// Refresh remaining tags
|
||||
select.tagsinput('refresh');
|
||||
|
||||
// Add new items in model as tags
|
||||
for (i = 0; i < added.length; i++) {
|
||||
select.tagsinput('add', added[i]);
|
||||
}
|
||||
}, true);
|
||||
});
|
||||
}
|
||||
};
|
||||
}]);
|
7
Amen/Scripts/bootstrap-tagsinput-angular.min.js
vendored
Normal file
@ -0,0 +1,7 @@
|
||||
/*
|
||||
* bootstrap-tagsinput v0.8.0
|
||||
*
|
||||
*/
|
||||
|
||||
angular.module("bootstrap-tagsinput",[]).directive("bootstrapTagsinput",[function(){function a(a,b){return b?angular.isFunction(a.$parent[b])?a.$parent[b]:function(a){return a[b]}:void 0}return{restrict:"EA",scope:{model:"=ngModel"},template:"<select multiple></select>",replace:!1,link:function(b,c,d){$(function(){angular.isArray(b.model)||(b.model=[]);var e=$("select",c),f=d.typeaheadSource?d.typeaheadSource.split("."):null,g=f?f.length>1?b.$parent[f[0]][f[1]]:b.$parent[f[0]]:null;e.tagsinput(b.$parent[d.options||""]||{typeahead:{source:angular.isFunction(g)?g:null},itemValue:a(b,d.itemvalue),itemText:a(b,d.itemtext),confirmKeys:a(b,d.confirmkeys)?JSON.parse(d.confirmkeys):[13],tagClass:angular.isFunction(b.$parent[d.tagclass])?b.$parent[d.tagclass]:function(a){return d.tagclass}});for(var h=0;h<b.model.length;h++)e.tagsinput("add",b.model[h]);e.on("itemAdded",function(a){-1===b.model.indexOf(a.item)&&b.model.push(a.item)}),e.on("itemRemoved",function(a){var c=b.model.indexOf(a.item);-1!==c&&b.model.splice(c,1)});var i=b.model.slice();b.$watch("model",function(){var a,c=b.model.filter(function(a){return-1===i.indexOf(a)}),d=i.filter(function(a){return-1===b.model.indexOf(a)});for(i=b.model.slice(),a=0;a<d.length;a++)e.tagsinput("remove",d[a]);for(e.tagsinput("refresh"),a=0;a<c.length;a++)e.tagsinput("add",c[a])},!0)})}}}]);
|
||||
//# sourceMappingURL=bootstrap-tagsinput-angular.min.js.map
|
1
Amen/Scripts/bootstrap-tagsinput-angular.min.js.map
Normal file
@ -0,0 +1 @@
|
||||
{"version":3,"sources":["../src/bootstrap-tagsinput-angular.js"],"names":["angular","module","directive","getItemProperty","scope","property","isFunction","$parent","item","undefined","restrict","model","template","replace","link","element","attrs","$","isArray","select","typeaheadSourceArray","typeaheadSource","split","length","tagsinput","options","typeahead","source","itemValue","itemvalue","itemText","itemtext","confirmKeys","confirmkeys","JSON","parse","tagClass","tagclass","i","on","event","indexOf","push","idx","splice","prev","slice","$watch","added","filter","removed"],"mappings":";;;;;AAAAA,QAAQC,OAAO,0BACdC,UAAU,sBAAuB,WAEhC,QAASC,GAAgBC,EAAOC,GAC9B,MAAKA,GAGDL,QAAQM,WAAWF,EAAMG,QAAQF,IAC5BD,EAAMG,QAAQF,GAEhB,SAASG,GACd,MAAOA,GAAKH,IANLI,OAUX,OACEC,SAAU,KACVN,OACEO,MAAO,YAETC,SAAU,6BACVC,SAAS,EACTC,KAAM,SAASV,EAAOW,EAASC,GAC7BC,EAAE,WACKjB,QAAQkB,QAAQd,EAAMO,SACzBP,EAAMO,SAER,IAAIQ,GAASF,EAAE,SAAUF,GACrBK,EAAuBJ,EAAMK,gBAAkBL,EAAMK,gBAAgBC,MAAM,KAAO,KAClFD,EAAkBD,EACjBA,EAAqBG,OAAS,EAC3BnB,EAAMG,QAAQa,EAAqB,IAAIA,EAAqB,IAC1DhB,EAAMG,QAAQa,EAAqB,IACvC,IAEND,GAAOK,UAAUpB,EAAMG,QAAQS,EAAMS,SAAW,MAC9CC,WACEC,OAAW3B,QAAQM,WAAWe,GAAmBA,EAAkB,MAErEO,UAAWzB,EAAgBC,EAAOY,EAAMa,WACxCC,SAAW3B,EAAgBC,EAAOY,EAAMe,UACxCC,YAAc7B,EAAgBC,EAAOY,EAAMiB,aAAeC,KAAKC,MAAMnB,EAAMiB,cAAgB,IAC3FG,SAAWpC,QAAQM,WAAWF,EAAMG,QAAQS,EAAMqB,WAAajC,EAAMG,QAAQS,EAAMqB,UAAY,SAAS7B,GAAQ,MAAOQ,GAAMqB,WAG/H,KAAK,GAAIC,GAAI,EAAGA,EAAIlC,EAAMO,MAAMY,OAAQe,IACtCnB,EAAOK,UAAU,MAAOpB,EAAMO,MAAM2B,GAGtCnB,GAAOoB,GAAG,YAAa,SAASC,GACU,KAApCpC,EAAMO,MAAM8B,QAAQD,EAAMhC,OAC5BJ,EAAMO,MAAM+B,KAAKF,EAAMhC,QAG3BW,EAAOoB,GAAG,cAAe,SAASC,GAChC,GAAIG,GAAMvC,EAAMO,MAAM8B,QAAQD,EAAMhC,KACxB,MAARmC,GACFvC,EAAMO,MAAMiC,OAAOD,EAAK,IAK5B,IAAIE,GAAOzC,EAAMO,MAAMmC,OACvB1C,GAAM2C,OAAO,QAAS,WACpB,GAEIT,GAFAU,EAAQ5C,EAAMO,MAAMsC,OAAO,SAASX,GAAI,MAA2B,KAApBO,EAAKJ,QAAQH,KAC5DY,EAAUL,EAAKI,OAAO,SAASX,GAAI,MAAkC,KAA3BlC,EAAMO,MAAM8B,QAAQH,IAMlE,KAHAO,EAAOzC,EAAMO,MAAMmC,QAGdR,EAAI,EAAGA,EAAIY,EAAQ3B,OAAQe,IAC9BnB,EAAOK,UAAU,SAAU0B,EAAQZ,GAOrC,KAHAnB,EAAOK,UAAU,WAGZc,EAAI,EAAGA,EAAIU,EAAMzB,OAAQe,IAC5BnB,EAAOK,UAAU,MAAOwB,EAAMV,MAE/B","file":"bootstrap-tagsinput-angular.min.js"}
|
682
Amen/Scripts/bootstrap-tagsinput.js
vendored
Normal file
@ -0,0 +1,682 @@
|
||||
/*
|
||||
* bootstrap-tagsinput v0.8.0
|
||||
*
|
||||
*/
|
||||
|
||||
(function ($) {
|
||||
"use strict";
|
||||
|
||||
var defaultOptions = {
|
||||
tagClass: function(item) {
|
||||
return 'label label-info';
|
||||
},
|
||||
focusClass: 'focus',
|
||||
itemValue: function(item) {
|
||||
return item ? item.toString() : item;
|
||||
},
|
||||
itemText: function(item) {
|
||||
return this.itemValue(item);
|
||||
},
|
||||
itemTitle: function(item) {
|
||||
return null;
|
||||
},
|
||||
freeInput: true,
|
||||
addOnBlur: true,
|
||||
maxTags: undefined,
|
||||
maxChars: undefined,
|
||||
confirmKeys: [13, 44],
|
||||
delimiter: ',',
|
||||
delimiterRegex: null,
|
||||
cancelConfirmKeysOnEmpty: false,
|
||||
onTagExists: function(item, $tag) {
|
||||
$tag.hide().fadeIn();
|
||||
},
|
||||
trimValue: false,
|
||||
allowDuplicates: false,
|
||||
triggerChange: true
|
||||
};
|
||||
|
||||
/**
|
||||
* Constructor function
|
||||
*/
|
||||
function TagsInput(element, options) {
|
||||
this.isInit = true;
|
||||
this.itemsArray = [];
|
||||
|
||||
this.$element = $(element);
|
||||
this.$element.hide();
|
||||
|
||||
this.isSelect = (element.tagName === 'SELECT');
|
||||
this.multiple = (this.isSelect && element.hasAttribute('multiple'));
|
||||
this.objectItems = options && options.itemValue;
|
||||
this.placeholderText = element.hasAttribute('placeholder') ? this.$element.attr('placeholder') : '';
|
||||
this.inputSize = Math.max(1, this.placeholderText.length);
|
||||
|
||||
this.$container = $('<div class="bootstrap-tagsinput"></div>');
|
||||
this.$input = $('<input type="text" placeholder="' + this.placeholderText + '"/>').appendTo(this.$container);
|
||||
|
||||
this.$element.before(this.$container);
|
||||
|
||||
this.build(options);
|
||||
this.isInit = false;
|
||||
}
|
||||
|
||||
TagsInput.prototype = {
|
||||
constructor: TagsInput,
|
||||
|
||||
/**
|
||||
* Adds the given item as a new tag. Pass true to dontPushVal to prevent
|
||||
* updating the elements val()
|
||||
*/
|
||||
add: function(item, dontPushVal, options) {
|
||||
var self = this;
|
||||
|
||||
if (self.options.maxTags && self.itemsArray.length >= self.options.maxTags)
|
||||
return;
|
||||
|
||||
// Ignore falsey values, except false
|
||||
if (item !== false && !item)
|
||||
return;
|
||||
|
||||
// Trim value
|
||||
if (typeof item === "string" && self.options.trimValue) {
|
||||
item = $.trim(item);
|
||||
}
|
||||
|
||||
// Throw an error when trying to add an object while the itemValue option was not set
|
||||
if (typeof item === "object" && !self.objectItems)
|
||||
throw("Can't add objects when itemValue option is not set");
|
||||
|
||||
// Ignore strings only containg whitespace
|
||||
if (item.toString().match(/^\s*$/))
|
||||
return;
|
||||
|
||||
// If SELECT but not multiple, remove current tag
|
||||
if (self.isSelect && !self.multiple && self.itemsArray.length > 0)
|
||||
self.remove(self.itemsArray[0]);
|
||||
|
||||
if (typeof item === "string" && this.$element[0].tagName === 'INPUT') {
|
||||
var delimiter = (self.options.delimiterRegex) ? self.options.delimiterRegex : self.options.delimiter;
|
||||
var items = item.split(delimiter);
|
||||
if (items.length > 1) {
|
||||
for (var i = 0; i < items.length; i++) {
|
||||
this.add(items[i], true);
|
||||
}
|
||||
|
||||
if (!dontPushVal)
|
||||
self.pushVal(self.options.triggerChange);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
var itemValue = self.options.itemValue(item),
|
||||
itemText = self.options.itemText(item),
|
||||
tagClass = self.options.tagClass(item),
|
||||
itemTitle = self.options.itemTitle(item);
|
||||
|
||||
// Ignore items allready added
|
||||
var existing = $.grep(self.itemsArray, function(item) { return self.options.itemValue(item) === itemValue; } )[0];
|
||||
if (existing && !self.options.allowDuplicates) {
|
||||
// Invoke onTagExists
|
||||
if (self.options.onTagExists) {
|
||||
var $existingTag = $(".tag", self.$container).filter(function() { return $(this).data("item") === existing; });
|
||||
self.options.onTagExists(item, $existingTag);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// if length greater than limit
|
||||
if (self.items().toString().length + item.length + 1 > self.options.maxInputLength)
|
||||
return;
|
||||
|
||||
// raise beforeItemAdd arg
|
||||
var beforeItemAddEvent = $.Event('beforeItemAdd', { item: item, cancel: false, options: options});
|
||||
self.$element.trigger(beforeItemAddEvent);
|
||||
if (beforeItemAddEvent.cancel)
|
||||
return;
|
||||
|
||||
// register item in internal array and map
|
||||
self.itemsArray.push(item);
|
||||
|
||||
// add a tag element
|
||||
|
||||
var $tag = $('<span class="tag ' + htmlEncode(tagClass) + (itemTitle !== null ? ('" title="' + itemTitle) : '') + '">' + htmlEncode(itemText) + '<span data-role="remove"></span></span>');
|
||||
$tag.data('item', item);
|
||||
self.findInputWrapper().before($tag);
|
||||
$tag.after(' ');
|
||||
|
||||
// Check to see if the tag exists in its raw or uri-encoded form
|
||||
var optionExists = (
|
||||
$('option[value="' + encodeURIComponent(itemValue) + '"]', self.$element).length ||
|
||||
$('option[value="' + htmlEncode(itemValue) + '"]', self.$element).length
|
||||
);
|
||||
|
||||
// add <option /> if item represents a value not present in one of the <select />'s options
|
||||
if (self.isSelect && !optionExists) {
|
||||
var $option = $('<option selected>' + htmlEncode(itemText) + '</option>');
|
||||
$option.data('item', item);
|
||||
$option.attr('value', itemValue);
|
||||
self.$element.append($option);
|
||||
}
|
||||
|
||||
if (!dontPushVal)
|
||||
self.pushVal(self.options.triggerChange);
|
||||
|
||||
// Add class when reached maxTags
|
||||
if (self.options.maxTags === self.itemsArray.length || self.items().toString().length === self.options.maxInputLength)
|
||||
self.$container.addClass('bootstrap-tagsinput-max');
|
||||
|
||||
// If using typeahead, once the tag has been added, clear the typeahead value so it does not stick around in the input.
|
||||
if ($('.typeahead, .twitter-typeahead', self.$container).length) {
|
||||
self.$input.typeahead('val', '');
|
||||
}
|
||||
|
||||
if (this.isInit) {
|
||||
self.$element.trigger($.Event('itemAddedOnInit', { item: item, options: options }));
|
||||
} else {
|
||||
self.$element.trigger($.Event('itemAdded', { item: item, options: options }));
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Removes the given item. Pass true to dontPushVal to prevent updating the
|
||||
* elements val()
|
||||
*/
|
||||
remove: function(item, dontPushVal, options) {
|
||||
var self = this;
|
||||
|
||||
if (self.objectItems) {
|
||||
if (typeof item === "object")
|
||||
item = $.grep(self.itemsArray, function(other) { return self.options.itemValue(other) == self.options.itemValue(item); } );
|
||||
else
|
||||
item = $.grep(self.itemsArray, function(other) { return self.options.itemValue(other) == item; } );
|
||||
|
||||
item = item[item.length-1];
|
||||
}
|
||||
|
||||
if (item) {
|
||||
var beforeItemRemoveEvent = $.Event('beforeItemRemove', { item: item, cancel: false, options: options });
|
||||
self.$element.trigger(beforeItemRemoveEvent);
|
||||
if (beforeItemRemoveEvent.cancel)
|
||||
return;
|
||||
|
||||
$('.tag', self.$container).filter(function() { return $(this).data('item') === item; }).remove();
|
||||
$('option', self.$element).filter(function() { return $(this).data('item') === item; }).remove();
|
||||
if($.inArray(item, self.itemsArray) !== -1)
|
||||
self.itemsArray.splice($.inArray(item, self.itemsArray), 1);
|
||||
}
|
||||
|
||||
if (!dontPushVal)
|
||||
self.pushVal(self.options.triggerChange);
|
||||
|
||||
// Remove class when reached maxTags
|
||||
if (self.options.maxTags > self.itemsArray.length)
|
||||
self.$container.removeClass('bootstrap-tagsinput-max');
|
||||
|
||||
self.$element.trigger($.Event('itemRemoved', { item: item, options: options }));
|
||||
},
|
||||
|
||||
/**
|
||||
* Removes all items
|
||||
*/
|
||||
removeAll: function() {
|
||||
var self = this;
|
||||
|
||||
$('.tag', self.$container).remove();
|
||||
$('option', self.$element).remove();
|
||||
|
||||
while(self.itemsArray.length > 0)
|
||||
self.itemsArray.pop();
|
||||
|
||||
self.pushVal(self.options.triggerChange);
|
||||
},
|
||||
|
||||
/**
|
||||
* Refreshes the tags so they match the text/value of their corresponding
|
||||
* item.
|
||||
*/
|
||||
refresh: function() {
|
||||
var self = this;
|
||||
$('.tag', self.$container).each(function() {
|
||||
var $tag = $(this),
|
||||
item = $tag.data('item'),
|
||||
itemValue = self.options.itemValue(item),
|
||||
itemText = self.options.itemText(item),
|
||||
tagClass = self.options.tagClass(item);
|
||||
|
||||
// Update tag's class and inner text
|
||||
$tag.attr('class', null);
|
||||
$tag.addClass('tag ' + htmlEncode(tagClass));
|
||||
$tag.contents().filter(function() {
|
||||
return this.nodeType == 3;
|
||||
})[0].nodeValue = htmlEncode(itemText);
|
||||
|
||||
if (self.isSelect) {
|
||||
var option = $('option', self.$element).filter(function() { return $(this).data('item') === item; });
|
||||
option.attr('value', itemValue);
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns the items added as tags
|
||||
*/
|
||||
items: function() {
|
||||
return this.itemsArray;
|
||||
},
|
||||
|
||||
/**
|
||||
* Assembly value by retrieving the value of each item, and set it on the
|
||||
* element.
|
||||
*/
|
||||
pushVal: function() {
|
||||
var self = this,
|
||||
val = $.map(self.items(), function(item) {
|
||||
return self.options.itemValue(item).toString();
|
||||
});
|
||||
|
||||
self.$element.val(val, true);
|
||||
|
||||
if (self.options.triggerChange)
|
||||
self.$element.trigger('change');
|
||||
},
|
||||
|
||||
/**
|
||||
* Initializes the tags input behaviour on the element
|
||||
*/
|
||||
build: function(options) {
|
||||
var self = this;
|
||||
|
||||
self.options = $.extend({}, defaultOptions, options);
|
||||
// When itemValue is set, freeInput should always be false
|
||||
if (self.objectItems)
|
||||
self.options.freeInput = false;
|
||||
|
||||
makeOptionItemFunction(self.options, 'itemValue');
|
||||
makeOptionItemFunction(self.options, 'itemText');
|
||||
makeOptionFunction(self.options, 'tagClass');
|
||||
|
||||
// Typeahead Bootstrap version 2.3.2
|
||||
if (self.options.typeahead) {
|
||||
var typeahead = self.options.typeahead || {};
|
||||
|
||||
makeOptionFunction(typeahead, 'source');
|
||||
|
||||
self.$input.typeahead($.extend({}, typeahead, {
|
||||
source: function (query, process) {
|
||||
function processItems(items) {
|
||||
var texts = [];
|
||||
|
||||
for (var i = 0; i < items.length; i++) {
|
||||
var text = self.options.itemText(items[i]);
|
||||
map[text] = items[i];
|
||||
texts.push(text);
|
||||
}
|
||||
process(texts);
|
||||
}
|
||||
|
||||
this.map = {};
|
||||
var map = this.map,
|
||||
data = typeahead.source(query);
|
||||
|
||||
if ($.isFunction(data.success)) {
|
||||
// support for Angular callbacks
|
||||
data.success(processItems);
|
||||
} else if ($.isFunction(data.then)) {
|
||||
// support for Angular promises
|
||||
data.then(processItems);
|
||||
} else {
|
||||
// support for functions and jquery promises
|
||||
$.when(data)
|
||||
.then(processItems);
|
||||
}
|
||||
},
|
||||
updater: function (text) {
|
||||
self.add(this.map[text]);
|
||||
return this.map[text];
|
||||
},
|
||||
matcher: function (text) {
|
||||
return (text.toLowerCase().indexOf(this.query.trim().toLowerCase()) !== -1);
|
||||
},
|
||||
sorter: function (texts) {
|
||||
return texts.sort();
|
||||
},
|
||||
highlighter: function (text) {
|
||||
var regex = new RegExp( '(' + this.query + ')', 'gi' );
|
||||
return text.replace( regex, "<strong>$1</strong>" );
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
// typeahead.js
|
||||
if (self.options.typeaheadjs) {
|
||||
var typeaheadConfig = null;
|
||||
var typeaheadDatasets = {};
|
||||
|
||||
// Determine if main configurations were passed or simply a dataset
|
||||
var typeaheadjs = self.options.typeaheadjs;
|
||||
if ($.isArray(typeaheadjs)) {
|
||||
typeaheadConfig = typeaheadjs[0];
|
||||
typeaheadDatasets = typeaheadjs[1];
|
||||
} else {
|
||||
typeaheadDatasets = typeaheadjs;
|
||||
}
|
||||
|
||||
self.$input.typeahead(typeaheadConfig, typeaheadDatasets).on('typeahead:selected', $.proxy(function (obj, datum) {
|
||||
if (typeaheadDatasets.valueKey)
|
||||
self.add(datum[typeaheadDatasets.valueKey]);
|
||||
else
|
||||
self.add(datum);
|
||||
self.$input.typeahead('val', '');
|
||||
}, self));
|
||||
}
|
||||
|
||||
self.$container.on('click', $.proxy(function(event) {
|
||||
if (! self.$element.attr('disabled')) {
|
||||
self.$input.removeAttr('disabled');
|
||||
}
|
||||
self.$input.focus();
|
||||
}, self));
|
||||
|
||||
if (self.options.addOnBlur && self.options.freeInput) {
|
||||
self.$input.on('focusout', $.proxy(function(event) {
|
||||
// HACK: only process on focusout when no typeahead opened, to
|
||||
// avoid adding the typeahead text as tag
|
||||
if ($('.typeahead, .twitter-typeahead', self.$container).length === 0) {
|
||||
self.add(self.$input.val());
|
||||
self.$input.val('');
|
||||
}
|
||||
}, self));
|
||||
}
|
||||
|
||||
// Toggle the 'focus' css class on the container when it has focus
|
||||
self.$container.on({
|
||||
focusin: function() {
|
||||
self.$container.addClass(self.options.focusClass);
|
||||
},
|
||||
focusout: function() {
|
||||
self.$container.removeClass(self.options.focusClass);
|
||||
},
|
||||
});
|
||||
|
||||
self.$container.on('keydown', 'input', $.proxy(function(event) {
|
||||
var $input = $(event.target),
|
||||
$inputWrapper = self.findInputWrapper();
|
||||
|
||||
if (self.$element.attr('disabled')) {
|
||||
self.$input.attr('disabled', 'disabled');
|
||||
return;
|
||||
}
|
||||
|
||||
switch (event.which) {
|
||||
// BACKSPACE
|
||||
case 8:
|
||||
if (doGetCaretPosition($input[0]) === 0) {
|
||||
var prev = $inputWrapper.prev();
|
||||
if (prev.length) {
|
||||
self.remove(prev.data('item'));
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
// DELETE
|
||||
case 46:
|
||||
if (doGetCaretPosition($input[0]) === 0) {
|
||||
var next = $inputWrapper.next();
|
||||
if (next.length) {
|
||||
self.remove(next.data('item'));
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
// LEFT ARROW
|
||||
case 37:
|
||||
// Try to move the input before the previous tag
|
||||
var $prevTag = $inputWrapper.prev();
|
||||
if ($input.val().length === 0 && $prevTag[0]) {
|
||||
$prevTag.before($inputWrapper);
|
||||
$input.focus();
|
||||
}
|
||||
break;
|
||||
// RIGHT ARROW
|
||||
case 39:
|
||||
// Try to move the input after the next tag
|
||||
var $nextTag = $inputWrapper.next();
|
||||
if ($input.val().length === 0 && $nextTag[0]) {
|
||||
$nextTag.after($inputWrapper);
|
||||
$input.focus();
|
||||
}
|
||||
break;
|
||||
default:
|
||||
// ignore
|
||||
}
|
||||
|
||||
// Reset internal input's size
|
||||
var textLength = $input.val().length,
|
||||
wordSpace = Math.ceil(textLength / 5),
|
||||
size = textLength + wordSpace + 1;
|
||||
$input.attr('size', Math.max(this.inputSize, $input.val().length));
|
||||
}, self));
|
||||
|
||||
self.$container.on('keypress', 'input', $.proxy(function(event) {
|
||||
var $input = $(event.target);
|
||||
|
||||
if (self.$element.attr('disabled')) {
|
||||
self.$input.attr('disabled', 'disabled');
|
||||
return;
|
||||
}
|
||||
|
||||
var text = $input.val(),
|
||||
maxLengthReached = self.options.maxChars && text.length >= self.options.maxChars;
|
||||
if (self.options.freeInput && (keyCombinationInList(event, self.options.confirmKeys) || maxLengthReached)) {
|
||||
// Only attempt to add a tag if there is data in the field
|
||||
if (text.length !== 0) {
|
||||
self.add(maxLengthReached ? text.substr(0, self.options.maxChars) : text);
|
||||
$input.val('');
|
||||
}
|
||||
|
||||
// If the field is empty, let the event triggered fire as usual
|
||||
if (self.options.cancelConfirmKeysOnEmpty === false) {
|
||||
event.preventDefault();
|
||||
}
|
||||
}
|
||||
|
||||
// Reset internal input's size
|
||||
var textLength = $input.val().length,
|
||||
wordSpace = Math.ceil(textLength / 5),
|
||||
size = textLength + wordSpace + 1;
|
||||
$input.attr('size', Math.max(this.inputSize, $input.val().length));
|
||||
}, self));
|
||||
|
||||
// Remove icon clicked
|
||||
self.$container.on('click', '[data-role=remove]', $.proxy(function(event) {
|
||||
if (self.$element.attr('disabled')) {
|
||||
return;
|
||||
}
|
||||
self.remove($(event.target).closest('.tag').data('item'));
|
||||
}, self));
|
||||
|
||||
// Only add existing value as tags when using strings as tags
|
||||
if (self.options.itemValue === defaultOptions.itemValue) {
|
||||
if (self.$element[0].tagName === 'INPUT') {
|
||||
self.add(self.$element.val());
|
||||
} else {
|
||||
$('option', self.$element).each(function() {
|
||||
self.add($(this).attr('value'), true);
|
||||
});
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Removes all tagsinput behaviour and unregsiter all event handlers
|
||||
*/
|
||||
destroy: function() {
|
||||
var self = this;
|
||||
|
||||
// Unbind events
|
||||
self.$container.off('keypress', 'input');
|
||||
self.$container.off('click', '[role=remove]');
|
||||
|
||||
self.$container.remove();
|
||||
self.$element.removeData('tagsinput');
|
||||
self.$element.show();
|
||||
},
|
||||
|
||||
/**
|
||||
* Sets focus on the tagsinput
|
||||
*/
|
||||
focus: function() {
|
||||
this.$input.focus();
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns the internal input element
|
||||
*/
|
||||
input: function() {
|
||||
return this.$input;
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns the element which is wrapped around the internal input. This
|
||||
* is normally the $container, but typeahead.js moves the $input element.
|
||||
*/
|
||||
findInputWrapper: function() {
|
||||
var elt = this.$input[0],
|
||||
container = this.$container[0];
|
||||
while(elt && elt.parentNode !== container)
|
||||
elt = elt.parentNode;
|
||||
|
||||
return $(elt);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Register JQuery plugin
|
||||
*/
|
||||
$.fn.tagsinput = function(arg1, arg2, arg3) {
|
||||
var results = [];
|
||||
|
||||
this.each(function() {
|
||||
var tagsinput = $(this).data('tagsinput');
|
||||
// Initialize a new tags input
|
||||
if (!tagsinput) {
|
||||
tagsinput = new TagsInput(this, arg1);
|
||||
$(this).data('tagsinput', tagsinput);
|
||||
results.push(tagsinput);
|
||||
|
||||
if (this.tagName === 'SELECT') {
|
||||
$('option', $(this)).attr('selected', 'selected');
|
||||
}
|
||||
|
||||
// Init tags from $(this).val()
|
||||
$(this).val($(this).val());
|
||||
} else if (!arg1 && !arg2) {
|
||||
// tagsinput already exists
|
||||
// no function, trying to init
|
||||
results.push(tagsinput);
|
||||
} else if(tagsinput[arg1] !== undefined) {
|
||||
// Invoke function on existing tags input
|
||||
if(tagsinput[arg1].length === 3 && arg3 !== undefined){
|
||||
var retVal = tagsinput[arg1](arg2, null, arg3);
|
||||
}else{
|
||||
var retVal = tagsinput[arg1](arg2);
|
||||
}
|
||||
if (retVal !== undefined)
|
||||
results.push(retVal);
|
||||
}
|
||||
});
|
||||
|
||||
if ( typeof arg1 == 'string') {
|
||||
// Return the results from the invoked function calls
|
||||
return results.length > 1 ? results : results[0];
|
||||
} else {
|
||||
return results;
|
||||
}
|
||||
};
|
||||
|
||||
$.fn.tagsinput.Constructor = TagsInput;
|
||||
|
||||
/**
|
||||
* Most options support both a string or number as well as a function as
|
||||
* option value. This function makes sure that the option with the given
|
||||
* key in the given options is wrapped in a function
|
||||
*/
|
||||
function makeOptionItemFunction(options, key) {
|
||||
if (typeof options[key] !== 'function') {
|
||||
var propertyName = options[key];
|
||||
options[key] = function(item) { return item[propertyName]; };
|
||||
}
|
||||
}
|
||||
function makeOptionFunction(options, key) {
|
||||
if (typeof options[key] !== 'function') {
|
||||
var value = options[key];
|
||||
options[key] = function() { return value; };
|
||||
}
|
||||
}
|
||||
/**
|
||||
* HtmlEncodes the given value
|
||||
*/
|
||||
var htmlEncodeContainer = $('<div />');
|
||||
function htmlEncode(value) {
|
||||
if (value) {
|
||||
return htmlEncodeContainer.text(value).html();
|
||||
} else {
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the position of the caret in the given input field
|
||||
* http://flightschool.acylt.com/devnotes/caret-position-woes/
|
||||
*/
|
||||
function doGetCaretPosition(oField) {
|
||||
var iCaretPos = 0;
|
||||
if (document.selection) {
|
||||
oField.focus ();
|
||||
var oSel = document.selection.createRange();
|
||||
oSel.moveStart ('character', -oField.value.length);
|
||||
iCaretPos = oSel.text.length;
|
||||
} else if (oField.selectionStart || oField.selectionStart == '0') {
|
||||
iCaretPos = oField.selectionStart;
|
||||
}
|
||||
return (iCaretPos);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns boolean indicates whether user has pressed an expected key combination.
|
||||
* @param object keyPressEvent: JavaScript event object, refer
|
||||
* http://www.w3.org/TR/2003/WD-DOM-Level-3-Events-20030331/ecma-script-binding.html
|
||||
* @param object lookupList: expected key combinations, as in:
|
||||
* [13, {which: 188, shiftKey: true}]
|
||||
*/
|
||||
function keyCombinationInList(keyPressEvent, lookupList) {
|
||||
var found = false;
|
||||
$.each(lookupList, function (index, keyCombination) {
|
||||
if (typeof (keyCombination) === 'number' && keyPressEvent.which === keyCombination) {
|
||||
found = true;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (keyPressEvent.which === keyCombination.which) {
|
||||
var alt = !keyCombination.hasOwnProperty('altKey') || keyPressEvent.altKey === keyCombination.altKey,
|
||||
shift = !keyCombination.hasOwnProperty('shiftKey') || keyPressEvent.shiftKey === keyCombination.shiftKey,
|
||||
ctrl = !keyCombination.hasOwnProperty('ctrlKey') || keyPressEvent.ctrlKey === keyCombination.ctrlKey;
|
||||
if (alt && shift && ctrl) {
|
||||
found = true;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return found;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize tagsinput behaviour on inputs and selects which have
|
||||
* data-role=tagsinput
|
||||
*/
|
||||
$(function() {
|
||||
$("input[data-role=tagsinput], select[multiple][data-role=tagsinput]").tagsinput();
|
||||
});
|
||||
})(window.jQuery);
|
7
Amen/Scripts/bootstrap-tagsinput.min.js
vendored
Normal file
1
Amen/Scripts/bootstrap-tagsinput.min.js.map
Normal file
2014
Amen/Scripts/bootstrap.js
vendored
Normal file
21
Amen/Scripts/bootstrap.min.js
vendored
Normal file
2671
Amen/Scripts/jquery-1.10.2.intellisense.js
vendored
Normal file
9803
Amen/Scripts/jquery-1.10.2.js
vendored
Normal file
23
Amen/Scripts/jquery-1.10.2.min.js
vendored
Normal file
1
Amen/Scripts/jquery-1.10.2.min.map
Normal file
1302
Amen/Scripts/jquery.validate-vsdoc.js
vendored
Normal file
1245
Amen/Scripts/jquery.validate.js
vendored
Normal file
16
Amen/Scripts/jquery.validate.min.js
vendored
Normal file
410
Amen/Scripts/jquery.validate.unobtrusive.js
vendored
Normal file
@ -0,0 +1,410 @@
|
||||
/* NUGET: BEGIN LICENSE TEXT
|
||||
*
|
||||
* Microsoft grants you the right to use these script files for the sole
|
||||
* purpose of either: (i) interacting through your browser with the Microsoft
|
||||
* website or online service, subject to the applicable licensing or use
|
||||
* terms; or (ii) using the files as included with a Microsoft product subject
|
||||
* to that product's license terms. Microsoft reserves all other rights to the
|
||||
* files not expressly granted by Microsoft, whether by implication, estoppel
|
||||
* or otherwise. Insofar as a script file is dual licensed under GPL,
|
||||
* Microsoft neither took the code under GPL nor distributes it thereunder but
|
||||
* under the terms set out in this paragraph. All notices and licenses
|
||||
* below are for informational purposes only.
|
||||
*
|
||||
* NUGET: END LICENSE TEXT */
|
||||
/*!
|
||||
** Unobtrusive validation support library for jQuery and jQuery Validate
|
||||
** Copyright (C) Microsoft Corporation. All rights reserved.
|
||||
*/
|
||||
|
||||
/*jslint white: true, browser: true, onevar: true, undef: true, nomen: true, eqeqeq: true, plusplus: true, bitwise: true, regexp: true, newcap: true, immed: true, strict: false */
|
||||
/*global document: false, jQuery: false */
|
||||
|
||||
(function ($) {
|
||||
var $jQval = $.validator,
|
||||
adapters,
|
||||
data_validation = "unobtrusiveValidation";
|
||||
|
||||
function setValidationValues(options, ruleName, value) {
|
||||
options.rules[ruleName] = value;
|
||||
if (options.message) {
|
||||
options.messages[ruleName] = options.message;
|
||||
}
|
||||
}
|
||||
|
||||
function splitAndTrim(value) {
|
||||
return value.replace(/^\s+|\s+$/g, "").split(/\s*,\s*/g);
|
||||
}
|
||||
|
||||
function escapeAttributeValue(value) {
|
||||
// As mentioned on http://api.jquery.com/category/selectors/
|
||||
return value.replace(/([!"#$%&'()*+,./:;<=>?@\[\\\]^`{|}~])/g, "\\$1");
|
||||
}
|
||||
|
||||
function getModelPrefix(fieldName) {
|
||||
return fieldName.substr(0, fieldName.lastIndexOf(".") + 1);
|
||||
}
|
||||
|
||||
function appendModelPrefix(value, prefix) {
|
||||
if (value.indexOf("*.") === 0) {
|
||||
value = value.replace("*.", prefix);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
function onError(error, inputElement) { // 'this' is the form element
|
||||
var container = $(this).find("[data-valmsg-for='" + escapeAttributeValue(inputElement[0].name) + "']"),
|
||||
replaceAttrValue = container.attr("data-valmsg-replace"),
|
||||
replace = replaceAttrValue ? $.parseJSON(replaceAttrValue) !== false : null;
|
||||
|
||||
container.removeClass("field-validation-valid").addClass("field-validation-error");
|
||||
error.data("unobtrusiveContainer", container);
|
||||
|
||||
if (replace) {
|
||||
container.empty();
|
||||
error.removeClass("input-validation-error").appendTo(container);
|
||||
}
|
||||
else {
|
||||
error.hide();
|
||||
}
|
||||
}
|
||||
|
||||
function onErrors(event, validator) { // 'this' is the form element
|
||||
var container = $(this).find("[data-valmsg-summary=true]"),
|
||||
list = container.find("ul");
|
||||
|
||||
if (list && list.length && validator.errorList.length) {
|
||||
list.empty();
|
||||
container.addClass("validation-summary-errors").removeClass("validation-summary-valid");
|
||||
|
||||
$.each(validator.errorList, function () {
|
||||
$("<li />").html(this.message).appendTo(list);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function onSuccess(error) { // 'this' is the form element
|
||||
var container = error.data("unobtrusiveContainer"),
|
||||
replaceAttrValue = container.attr("data-valmsg-replace"),
|
||||
replace = replaceAttrValue ? $.parseJSON(replaceAttrValue) : null;
|
||||
|
||||
if (container) {
|
||||
container.addClass("field-validation-valid").removeClass("field-validation-error");
|
||||
error.removeData("unobtrusiveContainer");
|
||||
|
||||
if (replace) {
|
||||
container.empty();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function onReset(event) { // 'this' is the form element
|
||||
var $form = $(this);
|
||||
$form.data("validator").resetForm();
|
||||
$form.find(".validation-summary-errors")
|
||||
.addClass("validation-summary-valid")
|
||||
.removeClass("validation-summary-errors");
|
||||
$form.find(".field-validation-error")
|
||||
.addClass("field-validation-valid")
|
||||
.removeClass("field-validation-error")
|
||||
.removeData("unobtrusiveContainer")
|
||||
.find(">*") // If we were using valmsg-replace, get the underlying error
|
||||
.removeData("unobtrusiveContainer");
|
||||
}
|
||||
|
||||
function validationInfo(form) {
|
||||
var $form = $(form),
|
||||
result = $form.data(data_validation),
|
||||
onResetProxy = $.proxy(onReset, form),
|
||||
defaultOptions = $jQval.unobtrusive.options || {},
|
||||
execInContext = function (name, args) {
|
||||
var func = defaultOptions[name];
|
||||
func && $.isFunction(func) && func.apply(form, args);
|
||||
}
|
||||
|
||||
if (!result) {
|
||||
result = {
|
||||
options: { // options structure passed to jQuery Validate's validate() method
|
||||
errorClass: defaultOptions.errorClass || "input-validation-error",
|
||||
errorElement: defaultOptions.errorElement || "span",
|
||||
errorPlacement: function () {
|
||||
onError.apply(form, arguments);
|
||||
execInContext("errorPlacement", arguments);
|
||||
},
|
||||
invalidHandler: function () {
|
||||
onErrors.apply(form, arguments);
|
||||
execInContext("invalidHandler", arguments);
|
||||
},
|
||||
messages: {},
|
||||
rules: {},
|
||||
success: function () {
|
||||
onSuccess.apply(form, arguments);
|
||||
execInContext("success", arguments);
|
||||
}
|
||||
},
|
||||
attachValidation: function () {
|
||||
$form
|
||||
.off("reset." + data_validation, onResetProxy)
|
||||
.on("reset." + data_validation, onResetProxy)
|
||||
.validate(this.options);
|
||||
},
|
||||
validate: function () { // a validation function that is called by unobtrusive Ajax
|
||||
$form.validate();
|
||||
return $form.valid();
|
||||
}
|
||||
};
|
||||
$form.data(data_validation, result);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
$jQval.unobtrusive = {
|
||||
adapters: [],
|
||||
|
||||
parseElement: function (element, skipAttach) {
|
||||
/// <summary>
|
||||
/// Parses a single HTML element for unobtrusive validation attributes.
|
||||
/// </summary>
|
||||
/// <param name="element" domElement="true">The HTML element to be parsed.</param>
|
||||
/// <param name="skipAttach" type="Boolean">[Optional] true to skip attaching the
|
||||
/// validation to the form. If parsing just this single element, you should specify true.
|
||||
/// If parsing several elements, you should specify false, and manually attach the validation
|
||||
/// to the form when you are finished. The default is false.</param>
|
||||
var $element = $(element),
|
||||
form = $element.parents("form")[0],
|
||||
valInfo, rules, messages;
|
||||
|
||||
if (!form) { // Cannot do client-side validation without a form
|
||||
return;
|
||||
}
|
||||
|
||||
valInfo = validationInfo(form);
|
||||
valInfo.options.rules[element.name] = rules = {};
|
||||
valInfo.options.messages[element.name] = messages = {};
|
||||
|
||||
$.each(this.adapters, function () {
|
||||
var prefix = "data-val-" + this.name,
|
||||
message = $element.attr(prefix),
|
||||
paramValues = {};
|
||||
|
||||
if (message !== undefined) { // Compare against undefined, because an empty message is legal (and falsy)
|
||||
prefix += "-";
|
||||
|
||||
$.each(this.params, function () {
|
||||
paramValues[this] = $element.attr(prefix + this);
|
||||
});
|
||||
|
||||
this.adapt({
|
||||
element: element,
|
||||
form: form,
|
||||
message: message,
|
||||
params: paramValues,
|
||||
rules: rules,
|
||||
messages: messages
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
$.extend(rules, { "__dummy__": true });
|
||||
|
||||
if (!skipAttach) {
|
||||
valInfo.attachValidation();
|
||||
}
|
||||
},
|
||||
|
||||
parse: function (selector) {
|
||||
/// <summary>
|
||||
/// Parses all the HTML elements in the specified selector. It looks for input elements decorated
|
||||
/// with the [data-val=true] attribute value and enables validation according to the data-val-*
|
||||
/// attribute values.
|
||||
/// </summary>
|
||||
/// <param name="selector" type="String">Any valid jQuery selector.</param>
|
||||
|
||||
// $forms includes all forms in selector's DOM hierarchy (parent, children and self) that have at least one
|
||||
// element with data-val=true
|
||||
var $selector = $(selector),
|
||||
$forms = $selector.parents()
|
||||
.addBack()
|
||||
.filter("form")
|
||||
.add($selector.find("form"))
|
||||
.has("[data-val=true]");
|
||||
|
||||
$selector.find("[data-val=true]").each(function () {
|
||||
$jQval.unobtrusive.parseElement(this, true);
|
||||
});
|
||||
|
||||
$forms.each(function () {
|
||||
var info = validationInfo(this);
|
||||
if (info) {
|
||||
info.attachValidation();
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
adapters = $jQval.unobtrusive.adapters;
|
||||
|
||||
adapters.add = function (adapterName, params, fn) {
|
||||
/// <summary>Adds a new adapter to convert unobtrusive HTML into a jQuery Validate validation.</summary>
|
||||
/// <param name="adapterName" type="String">The name of the adapter to be added. This matches the name used
|
||||
/// in the data-val-nnnn HTML attribute (where nnnn is the adapter name).</param>
|
||||
/// <param name="params" type="Array" optional="true">[Optional] An array of parameter names (strings) that will
|
||||
/// be extracted from the data-val-nnnn-mmmm HTML attributes (where nnnn is the adapter name, and
|
||||
/// mmmm is the parameter name).</param>
|
||||
/// <param name="fn" type="Function">The function to call, which adapts the values from the HTML
|
||||
/// attributes into jQuery Validate rules and/or messages.</param>
|
||||
/// <returns type="jQuery.validator.unobtrusive.adapters" />
|
||||
if (!fn) { // Called with no params, just a function
|
||||
fn = params;
|
||||
params = [];
|
||||
}
|
||||
this.push({ name: adapterName, params: params, adapt: fn });
|
||||
return this;
|
||||
};
|
||||
|
||||
adapters.addBool = function (adapterName, ruleName) {
|
||||
/// <summary>Adds a new adapter to convert unobtrusive HTML into a jQuery Validate validation, where
|
||||
/// the jQuery Validate validation rule has no parameter values.</summary>
|
||||
/// <param name="adapterName" type="String">The name of the adapter to be added. This matches the name used
|
||||
/// in the data-val-nnnn HTML attribute (where nnnn is the adapter name).</param>
|
||||
/// <param name="ruleName" type="String" optional="true">[Optional] The name of the jQuery Validate rule. If not provided, the value
|
||||
/// of adapterName will be used instead.</param>
|
||||
/// <returns type="jQuery.validator.unobtrusive.adapters" />
|
||||
return this.add(adapterName, function (options) {
|
||||
setValidationValues(options, ruleName || adapterName, true);
|
||||
});
|
||||
};
|
||||
|
||||
adapters.addMinMax = function (adapterName, minRuleName, maxRuleName, minMaxRuleName, minAttribute, maxAttribute) {
|
||||
/// <summary>Adds a new adapter to convert unobtrusive HTML into a jQuery Validate validation, where
|
||||
/// the jQuery Validate validation has three potential rules (one for min-only, one for max-only, and
|
||||
/// one for min-and-max). The HTML parameters are expected to be named -min and -max.</summary>
|
||||
/// <param name="adapterName" type="String">The name of the adapter to be added. This matches the name used
|
||||
/// in the data-val-nnnn HTML attribute (where nnnn is the adapter name).</param>
|
||||
/// <param name="minRuleName" type="String">The name of the jQuery Validate rule to be used when you only
|
||||
/// have a minimum value.</param>
|
||||
/// <param name="maxRuleName" type="String">The name of the jQuery Validate rule to be used when you only
|
||||
/// have a maximum value.</param>
|
||||
/// <param name="minMaxRuleName" type="String">The name of the jQuery Validate rule to be used when you
|
||||
/// have both a minimum and maximum value.</param>
|
||||
/// <param name="minAttribute" type="String" optional="true">[Optional] The name of the HTML attribute that
|
||||
/// contains the minimum value. The default is "min".</param>
|
||||
/// <param name="maxAttribute" type="String" optional="true">[Optional] The name of the HTML attribute that
|
||||
/// contains the maximum value. The default is "max".</param>
|
||||
/// <returns type="jQuery.validator.unobtrusive.adapters" />
|
||||
return this.add(adapterName, [minAttribute || "min", maxAttribute || "max"], function (options) {
|
||||
var min = options.params.min,
|
||||
max = options.params.max;
|
||||
|
||||
if (min && max) {
|
||||
setValidationValues(options, minMaxRuleName, [min, max]);
|
||||
}
|
||||
else if (min) {
|
||||
setValidationValues(options, minRuleName, min);
|
||||
}
|
||||
else if (max) {
|
||||
setValidationValues(options, maxRuleName, max);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
adapters.addSingleVal = function (adapterName, attribute, ruleName) {
|
||||
/// <summary>Adds a new adapter to convert unobtrusive HTML into a jQuery Validate validation, where
|
||||
/// the jQuery Validate validation rule has a single value.</summary>
|
||||
/// <param name="adapterName" type="String">The name of the adapter to be added. This matches the name used
|
||||
/// in the data-val-nnnn HTML attribute(where nnnn is the adapter name).</param>
|
||||
/// <param name="attribute" type="String">[Optional] The name of the HTML attribute that contains the value.
|
||||
/// The default is "val".</param>
|
||||
/// <param name="ruleName" type="String" optional="true">[Optional] The name of the jQuery Validate rule. If not provided, the value
|
||||
/// of adapterName will be used instead.</param>
|
||||
/// <returns type="jQuery.validator.unobtrusive.adapters" />
|
||||
return this.add(adapterName, [attribute || "val"], function (options) {
|
||||
setValidationValues(options, ruleName || adapterName, options.params[attribute]);
|
||||
});
|
||||
};
|
||||
|
||||
$jQval.addMethod("__dummy__", function (value, element, params) {
|
||||
return true;
|
||||
});
|
||||
|
||||
$jQval.addMethod("regex", function (value, element, params) {
|
||||
var match;
|
||||
if (this.optional(element)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
match = new RegExp(params).exec(value);
|
||||
return (match && (match.index === 0) && (match[0].length === value.length));
|
||||
});
|
||||
|
||||
$jQval.addMethod("nonalphamin", function (value, element, nonalphamin) {
|
||||
var match;
|
||||
if (nonalphamin) {
|
||||
match = value.match(/\W/g);
|
||||
match = match && match.length >= nonalphamin;
|
||||
}
|
||||
return match;
|
||||
});
|
||||
|
||||
if ($jQval.methods.extension) {
|
||||
adapters.addSingleVal("accept", "mimtype");
|
||||
adapters.addSingleVal("extension", "extension");
|
||||
} else {
|
||||
// for backward compatibility, when the 'extension' validation method does not exist, such as with versions
|
||||
// of JQuery Validation plugin prior to 1.10, we should use the 'accept' method for
|
||||
// validating the extension, and ignore mime-type validations as they are not supported.
|
||||
adapters.addSingleVal("extension", "extension", "accept");
|
||||
}
|
||||
|
||||
adapters.addSingleVal("regex", "pattern");
|
||||
adapters.addBool("creditcard").addBool("date").addBool("digits").addBool("email").addBool("number").addBool("url");
|
||||
adapters.addMinMax("length", "minlength", "maxlength", "rangelength").addMinMax("range", "min", "max", "range");
|
||||
adapters.addMinMax("minlength", "minlength").addMinMax("maxlength", "minlength", "maxlength");
|
||||
adapters.add("equalto", ["other"], function (options) {
|
||||
var prefix = getModelPrefix(options.element.name),
|
||||
other = options.params.other,
|
||||
fullOtherName = appendModelPrefix(other, prefix),
|
||||
element = $(options.form).find(":input").filter("[name='" + escapeAttributeValue(fullOtherName) + "']")[0];
|
||||
|
||||
setValidationValues(options, "equalTo", element);
|
||||
});
|
||||
adapters.add("required", function (options) {
|
||||
// jQuery Validate equates "required" with "mandatory" for checkbox elements
|
||||
if (options.element.tagName.toUpperCase() !== "INPUT" || options.element.type.toUpperCase() !== "CHECKBOX") {
|
||||
setValidationValues(options, "required", true);
|
||||
}
|
||||
});
|
||||
adapters.add("remote", ["url", "type", "additionalfields"], function (options) {
|
||||
var value = {
|
||||
url: options.params.url,
|
||||
type: options.params.type || "GET",
|
||||
data: {}
|
||||
},
|
||||
prefix = getModelPrefix(options.element.name);
|
||||
|
||||
$.each(splitAndTrim(options.params.additionalfields || options.element.name), function (i, fieldName) {
|
||||
var paramName = appendModelPrefix(fieldName, prefix);
|
||||
value.data[paramName] = function () {
|
||||
return $(options.form).find(":input").filter("[name='" + escapeAttributeValue(paramName) + "']").val();
|
||||
};
|
||||
});
|
||||
|
||||
setValidationValues(options, "remote", value);
|
||||
});
|
||||
adapters.add("password", ["min", "nonalphamin", "regex"], function (options) {
|
||||
if (options.params.min) {
|
||||
setValidationValues(options, "minlength", options.params.min);
|
||||
}
|
||||
if (options.params.nonalphamin) {
|
||||
setValidationValues(options, "nonalphamin", options.params.nonalphamin);
|
||||
}
|
||||
if (options.params.regex) {
|
||||
setValidationValues(options, "regex", options.params.regex);
|
||||
}
|
||||
});
|
||||
|
||||
$(function () {
|
||||
$jQval.unobtrusive.parse(document);
|
||||
});
|
||||
}(jQuery));
|
19
Amen/Scripts/jquery.validate.unobtrusive.min.js
vendored
Normal file
1416
Amen/Scripts/modernizr-2.6.2.js
vendored
Normal file
340
Amen/Scripts/respond.js
Normal file
@ -0,0 +1,340 @@
|
||||
/* NUGET: BEGIN LICENSE TEXT
|
||||
*
|
||||
* Microsoft grants you the right to use these script files for the sole
|
||||
* purpose of either: (i) interacting through your browser with the Microsoft
|
||||
* website or online service, subject to the applicable licensing or use
|
||||
* terms; or (ii) using the files as included with a Microsoft product subject
|
||||
* to that product's license terms. Microsoft reserves all other rights to the
|
||||
* files not expressly granted by Microsoft, whether by implication, estoppel
|
||||
* or otherwise. Insofar as a script file is dual licensed under GPL,
|
||||
* Microsoft neither took the code under GPL nor distributes it thereunder but
|
||||
* under the terms set out in this paragraph. All notices and licenses
|
||||
* below are for informational purposes only.
|
||||
*
|
||||
* NUGET: END LICENSE TEXT */
|
||||
/*! matchMedia() polyfill - Test a CSS media type/query in JS. Authors & copyright (c) 2012: Scott Jehl, Paul Irish, Nicholas Zakas. Dual MIT/BSD license */
|
||||
/*! NOTE: If you're already including a window.matchMedia polyfill via Modernizr or otherwise, you don't need this part */
|
||||
window.matchMedia = window.matchMedia || (function(doc, undefined){
|
||||
|
||||
var bool,
|
||||
docElem = doc.documentElement,
|
||||
refNode = docElem.firstElementChild || docElem.firstChild,
|
||||
// fakeBody required for <FF4 when executed in <head>
|
||||
fakeBody = doc.createElement('body'),
|
||||
div = doc.createElement('div');
|
||||
|
||||
div.id = 'mq-test-1';
|
||||
div.style.cssText = "position:absolute;top:-100em";
|
||||
fakeBody.style.background = "none";
|
||||
fakeBody.appendChild(div);
|
||||
|
||||
return function(q){
|
||||
|
||||
div.innerHTML = '­<style media="'+q+'"> #mq-test-1 { width: 42px; }</style>';
|
||||
|
||||
docElem.insertBefore(fakeBody, refNode);
|
||||
bool = div.offsetWidth == 42;
|
||||
docElem.removeChild(fakeBody);
|
||||
|
||||
return { matches: bool, media: q };
|
||||
};
|
||||
|
||||
})(document);
|
||||
|
||||
|
||||
|
||||
|
||||
/*! Respond.js v1.2.0: min/max-width media query polyfill. (c) Scott Jehl. MIT/GPLv2 Lic. j.mp/respondjs */
|
||||
(function( win ){
|
||||
//exposed namespace
|
||||
win.respond = {};
|
||||
|
||||
//define update even in native-mq-supporting browsers, to avoid errors
|
||||
respond.update = function(){};
|
||||
|
||||
//expose media query support flag for external use
|
||||
respond.mediaQueriesSupported = win.matchMedia && win.matchMedia( "only all" ).matches;
|
||||
|
||||
//if media queries are supported, exit here
|
||||
if( respond.mediaQueriesSupported ){ return; }
|
||||
|
||||
//define vars
|
||||
var doc = win.document,
|
||||
docElem = doc.documentElement,
|
||||
mediastyles = [],
|
||||
rules = [],
|
||||
appendedEls = [],
|
||||
parsedSheets = {},
|
||||
resizeThrottle = 30,
|
||||
head = doc.getElementsByTagName( "head" )[0] || docElem,
|
||||
base = doc.getElementsByTagName( "base" )[0],
|
||||
links = head.getElementsByTagName( "link" ),
|
||||
requestQueue = [],
|
||||
|
||||
//loop stylesheets, send text content to translate
|
||||
ripCSS = function(){
|
||||
var sheets = links,
|
||||
sl = sheets.length,
|
||||
i = 0,
|
||||
//vars for loop:
|
||||
sheet, href, media, isCSS;
|
||||
|
||||
for( ; i < sl; i++ ){
|
||||
sheet = sheets[ i ],
|
||||
href = sheet.href,
|
||||
media = sheet.media,
|
||||
isCSS = sheet.rel && sheet.rel.toLowerCase() === "stylesheet";
|
||||
|
||||
//only links plz and prevent re-parsing
|
||||
if( !!href && isCSS && !parsedSheets[ href ] ){
|
||||
// selectivizr exposes css through the rawCssText expando
|
||||
if (sheet.styleSheet && sheet.styleSheet.rawCssText) {
|
||||
translate( sheet.styleSheet.rawCssText, href, media );
|
||||
parsedSheets[ href ] = true;
|
||||
} else {
|
||||
if( (!/^([a-zA-Z:]*\/\/)/.test( href ) && !base)
|
||||
|| href.replace( RegExp.$1, "" ).split( "/" )[0] === win.location.host ){
|
||||
requestQueue.push( {
|
||||
href: href,
|
||||
media: media
|
||||
} );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
makeRequests();
|
||||
},
|
||||
|
||||
//recurse through request queue, get css text
|
||||
makeRequests = function(){
|
||||
if( requestQueue.length ){
|
||||
var thisRequest = requestQueue.shift();
|
||||
|
||||
ajax( thisRequest.href, function( styles ){
|
||||
translate( styles, thisRequest.href, thisRequest.media );
|
||||
parsedSheets[ thisRequest.href ] = true;
|
||||
makeRequests();
|
||||
} );
|
||||
}
|
||||
},
|
||||
|
||||
//find media blocks in css text, convert to style blocks
|
||||
translate = function( styles, href, media ){
|
||||
var qs = styles.match( /@media[^\{]+\{([^\{\}]*\{[^\}\{]*\})+/gi ),
|
||||
ql = qs && qs.length || 0,
|
||||
//try to get CSS path
|
||||
href = href.substring( 0, href.lastIndexOf( "/" )),
|
||||
repUrls = function( css ){
|
||||
return css.replace( /(url\()['"]?([^\/\)'"][^:\)'"]+)['"]?(\))/g, "$1" + href + "$2$3" );
|
||||
},
|
||||
useMedia = !ql && media,
|
||||
//vars used in loop
|
||||
i = 0,
|
||||
j, fullq, thisq, eachq, eql;
|
||||
|
||||
//if path exists, tack on trailing slash
|
||||
if( href.length ){ href += "/"; }
|
||||
|
||||
//if no internal queries exist, but media attr does, use that
|
||||
//note: this currently lacks support for situations where a media attr is specified on a link AND
|
||||
//its associated stylesheet has internal CSS media queries.
|
||||
//In those cases, the media attribute will currently be ignored.
|
||||
if( useMedia ){
|
||||
ql = 1;
|
||||
}
|
||||
|
||||
|
||||
for( ; i < ql; i++ ){
|
||||
j = 0;
|
||||
|
||||
//media attr
|
||||
if( useMedia ){
|
||||
fullq = media;
|
||||
rules.push( repUrls( styles ) );
|
||||
}
|
||||
//parse for styles
|
||||
else{
|
||||
fullq = qs[ i ].match( /@media *([^\{]+)\{([\S\s]+?)$/ ) && RegExp.$1;
|
||||
rules.push( RegExp.$2 && repUrls( RegExp.$2 ) );
|
||||
}
|
||||
|
||||
eachq = fullq.split( "," );
|
||||
eql = eachq.length;
|
||||
|
||||
for( ; j < eql; j++ ){
|
||||
thisq = eachq[ j ];
|
||||
mediastyles.push( {
|
||||
media : thisq.split( "(" )[ 0 ].match( /(only\s+)?([a-zA-Z]+)\s?/ ) && RegExp.$2 || "all",
|
||||
rules : rules.length - 1,
|
||||
hasquery: thisq.indexOf("(") > -1,
|
||||
minw : thisq.match( /\(min\-width:[\s]*([\s]*[0-9\.]+)(px|em)[\s]*\)/ ) && parseFloat( RegExp.$1 ) + ( RegExp.$2 || "" ),
|
||||
maxw : thisq.match( /\(max\-width:[\s]*([\s]*[0-9\.]+)(px|em)[\s]*\)/ ) && parseFloat( RegExp.$1 ) + ( RegExp.$2 || "" )
|
||||
} );
|
||||
}
|
||||
}
|
||||
|
||||
applyMedia();
|
||||
},
|
||||
|
||||
lastCall,
|
||||
|
||||
resizeDefer,
|
||||
|
||||
// returns the value of 1em in pixels
|
||||
getEmValue = function() {
|
||||
var ret,
|
||||
div = doc.createElement('div'),
|
||||
body = doc.body,
|
||||
fakeUsed = false;
|
||||
|
||||
div.style.cssText = "position:absolute;font-size:1em;width:1em";
|
||||
|
||||
if( !body ){
|
||||
body = fakeUsed = doc.createElement( "body" );
|
||||
body.style.background = "none";
|
||||
}
|
||||
|
||||
body.appendChild( div );
|
||||
|
||||
docElem.insertBefore( body, docElem.firstChild );
|
||||
|
||||
ret = div.offsetWidth;
|
||||
|
||||
if( fakeUsed ){
|
||||
docElem.removeChild( body );
|
||||
}
|
||||
else {
|
||||
body.removeChild( div );
|
||||
}
|
||||
|
||||
//also update eminpx before returning
|
||||
ret = eminpx = parseFloat(ret);
|
||||
|
||||
return ret;
|
||||
},
|
||||
|
||||
//cached container for 1em value, populated the first time it's needed
|
||||
eminpx,
|
||||
|
||||
//enable/disable styles
|
||||
applyMedia = function( fromResize ){
|
||||
var name = "clientWidth",
|
||||
docElemProp = docElem[ name ],
|
||||
currWidth = doc.compatMode === "CSS1Compat" && docElemProp || doc.body[ name ] || docElemProp,
|
||||
styleBlocks = {},
|
||||
lastLink = links[ links.length-1 ],
|
||||
now = (new Date()).getTime();
|
||||
|
||||
//throttle resize calls
|
||||
if( fromResize && lastCall && now - lastCall < resizeThrottle ){
|
||||
clearTimeout( resizeDefer );
|
||||
resizeDefer = setTimeout( applyMedia, resizeThrottle );
|
||||
return;
|
||||
}
|
||||
else {
|
||||
lastCall = now;
|
||||
}
|
||||
|
||||
for( var i in mediastyles ){
|
||||
var thisstyle = mediastyles[ i ],
|
||||
min = thisstyle.minw,
|
||||
max = thisstyle.maxw,
|
||||
minnull = min === null,
|
||||
maxnull = max === null,
|
||||
em = "em";
|
||||
|
||||
if( !!min ){
|
||||
min = parseFloat( min ) * ( min.indexOf( em ) > -1 ? ( eminpx || getEmValue() ) : 1 );
|
||||
}
|
||||
if( !!max ){
|
||||
max = parseFloat( max ) * ( max.indexOf( em ) > -1 ? ( eminpx || getEmValue() ) : 1 );
|
||||
}
|
||||
|
||||
// if there's no media query at all (the () part), or min or max is not null, and if either is present, they're true
|
||||
if( !thisstyle.hasquery || ( !minnull || !maxnull ) && ( minnull || currWidth >= min ) && ( maxnull || currWidth <= max ) ){
|
||||
if( !styleBlocks[ thisstyle.media ] ){
|
||||
styleBlocks[ thisstyle.media ] = [];
|
||||
}
|
||||
styleBlocks[ thisstyle.media ].push( rules[ thisstyle.rules ] );
|
||||
}
|
||||
}
|
||||
|
||||
//remove any existing respond style element(s)
|
||||
for( var i in appendedEls ){
|
||||
if( appendedEls[ i ] && appendedEls[ i ].parentNode === head ){
|
||||
head.removeChild( appendedEls[ i ] );
|
||||
}
|
||||
}
|
||||
|
||||
//inject active styles, grouped by media type
|
||||
for( var i in styleBlocks ){
|
||||
var ss = doc.createElement( "style" ),
|
||||
css = styleBlocks[ i ].join( "\n" );
|
||||
|
||||
ss.type = "text/css";
|
||||
ss.media = i;
|
||||
|
||||
//originally, ss was appended to a documentFragment and sheets were appended in bulk.
|
||||
//this caused crashes in IE in a number of circumstances, such as when the HTML element had a bg image set, so appending beforehand seems best. Thanks to @dvelyk for the initial research on this one!
|
||||
head.insertBefore( ss, lastLink.nextSibling );
|
||||
|
||||
if ( ss.styleSheet ){
|
||||
ss.styleSheet.cssText = css;
|
||||
}
|
||||
else {
|
||||
ss.appendChild( doc.createTextNode( css ) );
|
||||
}
|
||||
|
||||
//push to appendedEls to track for later removal
|
||||
appendedEls.push( ss );
|
||||
}
|
||||
},
|
||||
//tweaked Ajax functions from Quirksmode
|
||||
ajax = function( url, callback ) {
|
||||
var req = xmlHttp();
|
||||
if (!req){
|
||||
return;
|
||||
}
|
||||
req.open( "GET", url, true );
|
||||
req.onreadystatechange = function () {
|
||||
if ( req.readyState != 4 || req.status != 200 && req.status != 304 ){
|
||||
return;
|
||||
}
|
||||
callback( req.responseText );
|
||||
}
|
||||
if ( req.readyState == 4 ){
|
||||
return;
|
||||
}
|
||||
req.send( null );
|
||||
},
|
||||
//define ajax obj
|
||||
xmlHttp = (function() {
|
||||
var xmlhttpmethod = false;
|
||||
try {
|
||||
xmlhttpmethod = new XMLHttpRequest();
|
||||
}
|
||||
catch( e ){
|
||||
xmlhttpmethod = new ActiveXObject( "Microsoft.XMLHTTP" );
|
||||
}
|
||||
return function(){
|
||||
return xmlhttpmethod;
|
||||
};
|
||||
})();
|
||||
|
||||
//translate CSS
|
||||
ripCSS();
|
||||
|
||||
//expose update for re-running respond later on
|
||||
respond.update = ripCSS;
|
||||
|
||||
//adjust on resize
|
||||
function callMedia(){
|
||||
applyMedia( true );
|
||||
}
|
||||
if( win.addEventListener ){
|
||||
win.addEventListener( "resize", callMedia, false );
|
||||
}
|
||||
else if( win.attachEvent ){
|
||||
win.attachEvent( "onresize", callMedia );
|
||||
}
|
||||
})(this);
|
20
Amen/Scripts/respond.min.js
vendored
Normal file
@ -0,0 +1,20 @@
|
||||
/* NUGET: BEGIN LICENSE TEXT
|
||||
*
|
||||
* Microsoft grants you the right to use these script files for the sole
|
||||
* purpose of either: (i) interacting through your browser with the Microsoft
|
||||
* website or online service, subject to the applicable licensing or use
|
||||
* terms; or (ii) using the files as included with a Microsoft product subject
|
||||
* to that product's license terms. Microsoft reserves all other rights to the
|
||||
* files not expressly granted by Microsoft, whether by implication, estoppel
|
||||
* or otherwise. Insofar as a script file is dual licensed under GPL,
|
||||
* Microsoft neither took the code under GPL nor distributes it thereunder but
|
||||
* under the terms set out in this paragraph. All notices and licenses
|
||||
* below are for informational purposes only.
|
||||
*
|
||||
* NUGET: END LICENSE TEXT */
|
||||
/*! matchMedia() polyfill - Test a CSS media type/query in JS. Authors & copyright (c) 2012: Scott Jehl, Paul Irish, Nicholas Zakas. Dual MIT/BSD license */
|
||||
/*! NOTE: If you're already including a window.matchMedia polyfill via Modernizr or otherwise, you don't need this part */
|
||||
window.matchMedia=window.matchMedia||(function(e,f){var c,a=e.documentElement,b=a.firstElementChild||a.firstChild,d=e.createElement("body"),g=e.createElement("div");g.id="mq-test-1";g.style.cssText="position:absolute;top:-100em";d.style.background="none";d.appendChild(g);return function(h){g.innerHTML='­<style media="'+h+'"> #mq-test-1 { width: 42px; }</style>';a.insertBefore(d,b);c=g.offsetWidth==42;a.removeChild(d);return{matches:c,media:h}}})(document);
|
||||
|
||||
/*! Respond.js v1.2.0: min/max-width media query polyfill. (c) Scott Jehl. MIT/GPLv2 Lic. j.mp/respondjs */
|
||||
(function(e){e.respond={};respond.update=function(){};respond.mediaQueriesSupported=e.matchMedia&&e.matchMedia("only all").matches;if(respond.mediaQueriesSupported){return}var w=e.document,s=w.documentElement,i=[],k=[],q=[],o={},h=30,f=w.getElementsByTagName("head")[0]||s,g=w.getElementsByTagName("base")[0],b=f.getElementsByTagName("link"),d=[],a=function(){var D=b,y=D.length,B=0,A,z,C,x;for(;B<y;B++){A=D[B],z=A.href,C=A.media,x=A.rel&&A.rel.toLowerCase()==="stylesheet";if(!!z&&x&&!o[z]){if(A.styleSheet&&A.styleSheet.rawCssText){m(A.styleSheet.rawCssText,z,C);o[z]=true}else{if((!/^([a-zA-Z:]*\/\/)/.test(z)&&!g)||z.replace(RegExp.$1,"").split("/")[0]===e.location.host){d.push({href:z,media:C})}}}}u()},u=function(){if(d.length){var x=d.shift();n(x.href,function(y){m(y,x.href,x.media);o[x.href]=true;u()})}},m=function(I,x,z){var G=I.match(/@media[^\{]+\{([^\{\}]*\{[^\}\{]*\})+/gi),J=G&&G.length||0,x=x.substring(0,x.lastIndexOf("/")),y=function(K){return K.replace(/(url\()['"]?([^\/\)'"][^:\)'"]+)['"]?(\))/g,"$1"+x+"$2$3")},A=!J&&z,D=0,C,E,F,B,H;if(x.length){x+="/"}if(A){J=1}for(;D<J;D++){C=0;if(A){E=z;k.push(y(I))}else{E=G[D].match(/@media *([^\{]+)\{([\S\s]+?)$/)&&RegExp.$1;k.push(RegExp.$2&&y(RegExp.$2))}B=E.split(",");H=B.length;for(;C<H;C++){F=B[C];i.push({media:F.split("(")[0].match(/(only\s+)?([a-zA-Z]+)\s?/)&&RegExp.$2||"all",rules:k.length-1,hasquery:F.indexOf("(")>-1,minw:F.match(/\(min\-width:[\s]*([\s]*[0-9\.]+)(px|em)[\s]*\)/)&&parseFloat(RegExp.$1)+(RegExp.$2||""),maxw:F.match(/\(max\-width:[\s]*([\s]*[0-9\.]+)(px|em)[\s]*\)/)&&parseFloat(RegExp.$1)+(RegExp.$2||"")})}}j()},l,r,v=function(){var z,A=w.createElement("div"),x=w.body,y=false;A.style.cssText="position:absolute;font-size:1em;width:1em";if(!x){x=y=w.createElement("body");x.style.background="none"}x.appendChild(A);s.insertBefore(x,s.firstChild);z=A.offsetWidth;if(y){s.removeChild(x)}else{x.removeChild(A)}z=p=parseFloat(z);return z},p,j=function(I){var x="clientWidth",B=s[x],H=w.compatMode==="CSS1Compat"&&B||w.body[x]||B,D={},G=b[b.length-1],z=(new Date()).getTime();if(I&&l&&z-l<h){clearTimeout(r);r=setTimeout(j,h);return}else{l=z}for(var E in i){var K=i[E],C=K.minw,J=K.maxw,A=C===null,L=J===null,y="em";if(!!C){C=parseFloat(C)*(C.indexOf(y)>-1?(p||v()):1)}if(!!J){J=parseFloat(J)*(J.indexOf(y)>-1?(p||v()):1)}if(!K.hasquery||(!A||!L)&&(A||H>=C)&&(L||H<=J)){if(!D[K.media]){D[K.media]=[]}D[K.media].push(k[K.rules])}}for(var E in q){if(q[E]&&q[E].parentNode===f){f.removeChild(q[E])}}for(var E in D){var M=w.createElement("style"),F=D[E].join("\n");M.type="text/css";M.media=E;f.insertBefore(M,G.nextSibling);if(M.styleSheet){M.styleSheet.cssText=F}else{M.appendChild(w.createTextNode(F))}q.push(M)}},n=function(x,z){var y=c();if(!y){return}y.open("GET",x,true);y.onreadystatechange=function(){if(y.readyState!=4||y.status!=200&&y.status!=304){return}z(y.responseText)};if(y.readyState==4){return}y.send(null)},c=(function(){var x=false;try{x=new XMLHttpRequest()}catch(y){x=new ActiveXObject("Microsoft.XMLHTTP")}return function(){return x}})();a();respond.update=a;function t(){j(true)}if(e.addEventListener){e.addEventListener("resize",t,false)}else{if(e.attachEvent){e.attachEvent("onresize",t)}}})(this);
|
58
Amen/Scripts/site-affiliate.js
Normal file
@ -0,0 +1,58 @@
|
||||
//on page load
|
||||
$(function () {
|
||||
|
||||
$('#UploadLogo').on('change', function (event) {
|
||||
var files = $("#UploadLogo").get(0).files;
|
||||
|
||||
|
||||
// Add the uploaded image content to the form data collection
|
||||
if (files.length > 0) {
|
||||
|
||||
$('#UploadLogoSpinner').removeClass('transparent');
|
||||
|
||||
var k = files[0].size / 1024.0;
|
||||
|
||||
if (k > 4096) {
|
||||
alert('File is too large. Please resize to less than 4MB');
|
||||
event.preventDefault();
|
||||
return false;
|
||||
}
|
||||
|
||||
var data = new FormData();
|
||||
data.append("UploadedImage", files[0]);
|
||||
|
||||
var url = GetSiteUrlPath('/Affiliate/UploadImage');
|
||||
|
||||
|
||||
// Make Ajax request with the contentType = false, and procesDate = false
|
||||
var ajaxRequest = $.ajax({
|
||||
type: "POST",
|
||||
url: url,
|
||||
cache: false,
|
||||
contentType: false,
|
||||
processData: false,
|
||||
data: data,
|
||||
success: function (result) {
|
||||
$('#UrlLogo').val(result);
|
||||
$('#UploadLogo').val('');
|
||||
$('#UploadLogoSpinner').addClass('transparent');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
$('.affiliate-style-add-template').click(function (event) {
|
||||
|
||||
if ($('#StyleContent').val().length > 0) {
|
||||
if(!window.confirm('Your sure? This will replace your existing style content.'))
|
||||
{
|
||||
event.preventDefault();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
$('#StyleContent').val($('#Template').val());
|
||||
});
|
||||
|
||||
})
|
193
Amen/Scripts/site-common.js
Normal file
@ -0,0 +1,193 @@
|
||||
//on page load
|
||||
$(function () {
|
||||
var timezoneOffsetCookie = readCookie("TZOffset");
|
||||
if (!timezoneOffsetCookie) {
|
||||
createCookie("TZOffset", (new Date()).getTimezoneOffset(), 30);
|
||||
}
|
||||
|
||||
//back to top logic BEGIN
|
||||
var backToTopOffset = 300,
|
||||
backToTopOffsetOpacity = 1200,
|
||||
backToTopScrollDuration = 700,
|
||||
$backToTopButton = $('.page-top');
|
||||
|
||||
$(window).scroll(function () {
|
||||
|
||||
($(this).scrollTop() > backToTopOffset) ? $backToTopButton.addClass('page-top-visible') : $backToTopButton.removeClass('page-top-visible page-top-faded');
|
||||
if ($(this).scrollTop() > backToTopOffsetOpacity) {
|
||||
$backToTopButton.addClass('page-top-faded');
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
$backToTopButton.on('click', function (event) {
|
||||
event.preventDefault();
|
||||
$('body,html').animate({
|
||||
scrollTop: 0,
|
||||
}, backToTopScrollDuration
|
||||
);
|
||||
});
|
||||
//back to top logic END
|
||||
|
||||
//if inactive-affiliate-message is showing, hide it after a delay or a click
|
||||
$('.inactive-affiliate-message').click(function () {
|
||||
$(this).addClass('transparent');
|
||||
setTimeout(function () {
|
||||
$('.inactive-affiliate-message').addClass('hidden');
|
||||
}, 300);
|
||||
});
|
||||
|
||||
if ($('.inactive-affiliate-message').is(":visible") == true) {
|
||||
setTimeout(function () {
|
||||
$('.inactive-affiliate-message').trigger('click');
|
||||
}, 20000);
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
function ShowActivityIndicator() {
|
||||
$('#loading-container').removeClass('transparent');
|
||||
}
|
||||
|
||||
function HideActivityIndicator() {
|
||||
$('#loading-container').addClass('transparent');
|
||||
}
|
||||
|
||||
function GetSiteUrlPath(path) {
|
||||
|
||||
if (path.indexOf('/') == 0)
|
||||
path = path.substring(1);
|
||||
|
||||
return $('#SiteBaseUrl').val() + path;
|
||||
}
|
||||
|
||||
function ParseQueryString(key) {
|
||||
key = key.replace(/[*+?^$.\[\]{}()|\\\/]/g, "\\$&"); // escape RegEx meta chars
|
||||
var match = location.search.match(new RegExp("[?&]" + key + "=([^&]+)(&|$)"));
|
||||
return match && decodeURIComponent(match[1].replace(/\+/g, " "));
|
||||
}
|
||||
|
||||
function createCookie(name, value, days) {
|
||||
if (days) {
|
||||
var date = new Date();
|
||||
date.setTime(date.getTime() + (days * 24 * 60 * 60 * 1000));
|
||||
var expires = "; expires=" + date.toGMTString();
|
||||
}
|
||||
else var expires = "";
|
||||
document.cookie = name + "=" + value + expires + "; path=/";
|
||||
}
|
||||
|
||||
function readCookie(name) {
|
||||
var nameEQ = name + "=";
|
||||
var ca = document.cookie.split(';');
|
||||
for (var i = 0; i < ca.length; i++) {
|
||||
var c = ca[i];
|
||||
while (c.charAt(0) == ' ') c = c.substring(1, c.length);
|
||||
if (c.indexOf(nameEQ) == 0) return c.substring(nameEQ.length, c.length);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
function eraseCookie(name) {
|
||||
createCookie(name, "", -1);
|
||||
}
|
||||
|
||||
function UpperCasePercent(str) {
|
||||
|
||||
var upperLen = str.replace(/[^A-Z]/g, "").length;
|
||||
var lowerLen = str.replace(/[^a-z]/g, "").length;
|
||||
|
||||
var totalLen = upperLen + lowerLen;
|
||||
if (totalLen == 0)
|
||||
return 0;
|
||||
|
||||
return upperLen / totalLen;
|
||||
|
||||
}
|
||||
|
||||
$('a.toggler').click(function () {
|
||||
$(this).toggleClass('moretoggle lesstoggle');
|
||||
});
|
||||
|
||||
$('a.togglePrayerOverlay').click(function () {
|
||||
$(".prayer-item-container").toggleClass('fixedContainer');
|
||||
});
|
||||
|
||||
|
||||
(function ($) {
|
||||
|
||||
$.fn.setMaxLength = function (maxChars, feedbackSelector) {
|
||||
var tb = $(this);
|
||||
var fb = $(feedbackSelector);
|
||||
if (fb.length == 0) {
|
||||
fb = $('<span class="maxlength-feedback"></span>');
|
||||
fb.insertBefore(tb);
|
||||
}
|
||||
|
||||
tb.attr('maxlength', maxChars);
|
||||
|
||||
var update = function (e) {
|
||||
var remaining = maxChars - tb.val().length;
|
||||
if (remaining <= 0) {
|
||||
tb.val(tb.val().substring(0, maxChars));
|
||||
remaining = 0;
|
||||
}
|
||||
fb.text('(' + remaining + ' characters remaining)');
|
||||
};
|
||||
|
||||
update();
|
||||
tb.change(update);
|
||||
tb.keyup(update);
|
||||
|
||||
//fb.addClass('hidden');
|
||||
//tb.focus(function () {
|
||||
// fb.removeClass('hidden');
|
||||
//});
|
||||
//tb.blur(function () {
|
||||
// fb.addClass('hidden');
|
||||
//})
|
||||
};
|
||||
|
||||
$.fn.setAutoExpand = function (minRows, maxRows) {
|
||||
var tb = $(this);
|
||||
if (minRows) {
|
||||
tb.attr('data-min-rows', minRows);
|
||||
tb.attr('rows', minRows);
|
||||
}
|
||||
if (!maxRows) {
|
||||
maxRows = 1000;
|
||||
}
|
||||
tb.attr('data-max-rows', maxRows);
|
||||
|
||||
tb.one('focus.autoExpand', function () {
|
||||
var savedValue = this.value;
|
||||
this.value = '';
|
||||
this.baseScrollHeight = this.scrollHeight;
|
||||
this.value = savedValue;
|
||||
//alert(this.value);
|
||||
})
|
||||
.on('input.autoExpand', function () {
|
||||
var minRows = this.getAttribute('data-min-rows') | 0, rows;
|
||||
var maxRows = this.getAttribute('data-max-rows');
|
||||
this.rows = minRows;
|
||||
var lineheight = $(this).css('line-height');
|
||||
lineheight = 21;
|
||||
rows = Math.ceil((this.scrollHeight - this.baseScrollHeight) / lineheight);
|
||||
this.rows = Math.min(minRows + rows, maxRows);
|
||||
//alert(lineheight);
|
||||
$(this).css('min-height', (this.rows * lineheight) + 'px');
|
||||
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
$(function() {
|
||||
if (window.self != window.top) {
|
||||
$(document.body).addClass("in-iframe");
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
|
||||
|
||||
}(jQuery));
|