Skip to content

Commit

Permalink
Merge branch 'hotfix-1.14.3' into hotfix-1.14.4
Browse files Browse the repository at this point in the history
  • Loading branch information
ethan-sparkdevnetwork committed Jun 26, 2023
2 parents 188ab45 + a7454b4 commit 3b81299
Show file tree
Hide file tree
Showing 4 changed files with 167 additions and 71 deletions.
160 changes: 109 additions & 51 deletions Rock.JavaScript.Obsidian/Framework/Controls/addressControl.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,15 @@
// limitations under the License.
// </copyright>
//
import { defineComponent, PropType } from "vue";
import { computed, defineComponent, PropType, ref, watch } from "vue";
import RockFormField from "./rockFormField";
import DropDownList from "./dropDownList";
import RockLabel from "./rockLabel";
import TextBox from "./textBox";
import { newGuid } from "@Obsidian/Utility/guid";
import { ListItemBag } from "@Obsidian/ViewModels/Utility/listItemBag";
import { rulesPropType } from "@Obsidian/Utility/validationRules";
import { normalizeRules, rulesPropType } from "@Obsidian/Utility/validationRules";
import { updateRefValue } from "@Obsidian/Utility/component";

export type AddressControlValue = {
street1?: string;
Expand All @@ -48,10 +49,11 @@ const stateOptions: ListItemBag[] = [
"WA", "WV", "WI", "WY"]
.map(o => ({ value: o, text: o }));

export const AddressControlBase = defineComponent({
name: "AddressControlBase",
export default defineComponent({
name: "AddressControl",

components: {
RockFormField,
TextBox,
RockLabel,
DropDownList
Expand All @@ -63,65 +65,121 @@ export const AddressControlBase = defineComponent({
default: {}
},

id: {
type: String as PropType<string>,
default: ""
},
rules: rulesPropType
},

setup(props) {
const uniqueId = props.id || `rock-addresscontrol-${newGuid()}`;

return {
uniqueId,
stateOptions
};
emits: {
"update:modelValue": (_v: AddressControlValue) => true
},

template: `
<div :id="uniqueId">
<div class="form-group">
<TextBox placeholder="Address Line 1" :rules="rules" v-model="modelValue.street1" validationTitle="Address Line 1" />
</div>
<div class="form-group">
<TextBox placeholder="Address Line 2" v-model="modelValue.street2" validationTitle="Address Line 2" />
</div>
<div class="form-row">
<div class="form-group col-sm-6">
<TextBox placeholder="City" :rules="rules" v-model="modelValue.city" validationTitle="City" />
</div>
<div class="form-group col-sm-3">
<DropDownList :showBlankItem="false" v-model="modelValue.state" :items="stateOptions" />
</div>
<div class="form-group col-sm-3">
<TextBox placeholder="Zip" :rules="rules" v-model="modelValue.postalCode" validationTitle="Zip" />
</div>
</div>
</div>
`
});
setup(props, { emit }) {
const internalValue = ref(props.modelValue);

export default defineComponent({
name: "AddressControl",
watch(() => props.modelValue, () => {
updateRefValue(internalValue, props.modelValue);
}, { deep: true });

components: {
RockFormField,
AddressControlBase
},
watch(internalValue, () => {
emit("update:modelValue", internalValue.value);
}, { deep: true });

props: {
modelValue: {
type: Object as PropType<AddressControlValue>,
default: {}
},
rules: rulesPropType
// Custom address validation
const fieldRules = computed(() => {
const rules = normalizeRules(props.rules);

if (rules.includes("required")) {
const index = rules.indexOf("required");

rules[index] = (value: unknown) => {
try {
const val = JSON.parse(value as string) as AddressControlValue;
if (!val || !val.street1 || !val.city || !val.postalCode) {
return "is required";
}

if (!/^\d{5}(-\d{4})?$/.test(val.postalCode)) {
return "needs a valid Zip code";
}
}
catch (e) {
return "is required";
}

return true;
};
}
else {
rules.push((value: unknown) => {
try {
const val = JSON.parse(value as string) as AddressControlValue;
if (!val || !val.street1) {
// can be empty
return true;
}

if (!val.city || !val.postalCode) {
// If we have a street value, we also need a city and zip
const missing: string[] = [];
if (!val.city) {
missing.push("City");
}
if (!val.postalCode) {
missing.push("Zip");
}
return "must include " + missing.join(", ");
}

if (!/^\d{5}(-\d{4})?$/.test(val.postalCode)) {
return "needs a valid Zip code";
}
}
catch (e) {
return "must be filled out correctly.";
}

return true;
});
}

return rules;
});

// RockFormField doesn't watch for deep changes, so it doesn't notice when individual pieces
// change. This rememdies that by turning the value into a single string.
const fieldValue = computed(() => {
return JSON.stringify(internalValue.value);
});

return {
internalValue,
stateOptions,
fieldRules,
fieldValue
};
},

template: `
<RockFormField formGroupClasses="address-control" #default="{uniqueId, field}" name="addresscontrol" v-model.lazy="modelValue" :rules="rules" >
<RockFormField formGroupClasses="address-control" name="addresscontrol" :modelValue="fieldValue" :rules="fieldRules" >
<div class="control-wrapper">
<AddressControlBase v-model.lazy="modelValue" :rules="rules" v-bind="field" :disabled="disabled" />
<div>
<div class="form-group">
<TextBox placeholder="Address Line 1" v-model="internalValue.street1" validationTitle="Address Line 1" />
</div>
<div class="form-group">
<TextBox placeholder="Address Line 2" v-model="internalValue.street2" validationTitle="Address Line 2" />
</div>
<div class="form-row">
<div class="form-group col-sm-6">
<TextBox placeholder="City" v-model="internalValue.city" validationTitle="City" />
</div>
<div class="form-group col-sm-3">
<DropDownList :showBlankItem="false" v-model="internalValue.state" :items="stateOptions" validationTitle="State" />
</div>
<div class="form-group col-sm-3">
<TextBox placeholder="Zip" v-model="internalValue.postalCode" validationTitle="Zip" />
</div>
</div>
</div>
</div>
</RockFormField>
`
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ namespace Rock.Rest.Controllers
/// <summary>
/// SnippetTypes REST API
/// </summary>
[RestControllerGuid( "0B662577-923C-4212-A7F8-E8026E35CB99" )]
[RestControllerGuid( "7F3E79E0-FEB0-47EF-8BF8-037D2C250033" )]
public partial class SnippetTypesController : Rock.Rest.ApiController<Rock.Model.SnippetType>
{
/// <summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ namespace Rock.Rest.Controllers
/// <summary>
/// Snippets REST API
/// </summary>
[RestControllerGuid( "2FE6C7D9-C59F-40E8-8D4C-0BD798AA798C" )]
[RestControllerGuid( "E9E3C097-49C2-4991-A6E0-E5FC560E2459" )]
public partial class SnippetsController : Rock.Rest.ApiController<Rock.Model.Snippet>
{
/// <summary>
Expand Down
74 changes: 56 additions & 18 deletions RockWeb/Webhooks/TwilioSms.ashx
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,13 @@ using System;
using System.Web;
using System.Linq;
using System.Net;
using System.Text;
using Rock;
using Rock.Communication.SmsActions;
using Rock.Communication;
using Rock.Data;
using Rock.Model;
using Rock.SystemKey;

/// <summary>
/// This the Twilio Webwook that processes incoming SMS messages thru the SMS Pipeline. See https://community.rockrms.com/Rock/BookContent/8#smstwilio
Expand Down Expand Up @@ -55,6 +58,34 @@ public class TwilioSmsAsync : IHttpAsyncHandler

class TwilioSmsResponseAsync : TwilioDefaultResponseAsync
{
private TransportComponent _component;

/// <summary>
/// Gets the Twilio transport component from the container.
/// </summary>
private TransportComponent TwilioTransportComponent
{
get
{
if ( _component == null )
{
var entityTypeGuid = new Guid( "CF9FD146-8623-4D9A-98E6-4BD710F071A4" );
foreach ( var serviceEntry in TransportContainer.Instance.Components )
{
var component = serviceEntry.Value.Value;
var entityType = Rock.Web.Cache.EntityTypeCache.Get( component.GetType() );
if ( entityType != null && entityType.Guid.Equals( entityTypeGuid ) )
{
_component = component;
break;
}
}
}

return _component;
}
}

/// <summary>
/// Initializes a new instance of the <see cref="TwilioSmsResponseAsync"/> class.
/// </summary>
Expand Down Expand Up @@ -90,29 +121,36 @@ class TwilioSmsResponseAsync : TwilioDefaultResponseAsync

int? numberOfAttachments = request.Params["NumMedia"].IsNotNullOrWhiteSpace() ? request.Params["NumMedia"].AsIntegerOrNull() : null;

if ( numberOfAttachments != null )
if ( numberOfAttachments != null && this.TwilioTransportComponent != null )
{
Guid imageGuid;
for ( int i = 0; i < numberOfAttachments.Value; i++ )
var accountSid = this.TwilioTransportComponent.GetAttributeValue( TwilioAttributeKey.Sid );
var authToken = this.TwilioTransportComponent.GetAttributeValue( TwilioAttributeKey.AuthToken );

if ( accountSid.IsNotNullOrWhiteSpace() && authToken.IsNotNullOrWhiteSpace() )
{
string imageUrl = request.Params[string.Format( "MediaUrl{0}", i )];
string mimeType = request.Params[string.Format( "MediaContentType{0}", i )];
imageGuid = Guid.NewGuid();
Guid imageGuid;
for ( int i = 0; i < numberOfAttachments.Value; i++ )
{
string imageUrl = request.Params[string.Format( "MediaUrl{0}", i )];
string mimeType = request.Params[string.Format( "MediaContentType{0}", i )];
imageGuid = Guid.NewGuid();

System.IO.Stream stream = null;
var httpWebRequest = ( HttpWebRequest ) HttpWebRequest.Create( imageUrl );
var httpWebResponse = ( HttpWebResponse ) httpWebRequest.GetResponse();
var httpWebRequest = ( HttpWebRequest ) HttpWebRequest.Create( imageUrl );
httpWebRequest.Headers["Authorization"] = "Basic " + Convert.ToBase64String(Encoding.Default.GetBytes(accountSid + ":" + authToken));

if ( httpWebResponse.ContentLength == 0 )
{
continue;
}
var httpWebResponse = ( HttpWebResponse ) httpWebRequest.GetResponse();

string fileExtension = Rock.Utility.FileUtilities.GetFileExtensionFromContentType( mimeType );
string fileName = string.Format( "SMS-Attachment-{0}-{1}.{2}", imageGuid, i, fileExtension );
stream = httpWebResponse.GetResponseStream();
var binaryFile = new BinaryFileService( rockContext ).AddFileFromStream( stream, mimeType, httpWebResponse.ContentLength, fileName, Rock.SystemGuid.BinaryFiletype.COMMUNICATION_ATTACHMENT, imageGuid );
message.Attachments.Add( binaryFile );
if ( httpWebResponse.ContentLength == 0 )
{
continue;
}

string fileExtension = Rock.Utility.FileUtilities.GetFileExtensionFromContentType( mimeType );
string fileName = string.Format( "SMS-Attachment-{0}-{1}.{2}", imageGuid, i, fileExtension );
var stream = httpWebResponse.GetResponseStream();
var binaryFile = new BinaryFileService( rockContext ).AddFileFromStream( stream, mimeType, httpWebResponse.ContentLength, fileName, Rock.SystemGuid.BinaryFiletype.COMMUNICATION_ATTACHMENT, imageGuid );
message.Attachments.Add( binaryFile );
}
}
}

Expand Down

0 comments on commit 3b81299

Please sign in to comment.