Add project files.

This commit is contained in:
jleung 2021-12-26 22:45:44 -08:00
parent 8aac8ac0ee
commit 6cea7b2aff
24 changed files with 1173 additions and 0 deletions

25
TwilioSMSReceiver.sln Normal file
View File

@ -0,0 +1,25 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.0.31912.275
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TwilioSMSReceiver", "TwilioSMSReceiver\TwilioSMSReceiver.csproj", "{223C45EA-FAAC-44B8-B7DF-5DAA257CB52E}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{223C45EA-FAAC-44B8-B7DF-5DAA257CB52E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{223C45EA-FAAC-44B8-B7DF-5DAA257CB52E}.Debug|Any CPU.Build.0 = Debug|Any CPU
{223C45EA-FAAC-44B8-B7DF-5DAA257CB52E}.Release|Any CPU.ActiveCfg = Release|Any CPU
{223C45EA-FAAC-44B8-B7DF-5DAA257CB52E}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {D5214D99-4465-4695-A647-C41517BC8E9D}
EndGlobalSection
EndGlobal

View File

@ -0,0 +1,117 @@
#nullable disable
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using TwilioSMSReceiver;
using TwilioSMSReceiver.Models;
namespace TwilioSMSReceiver.Controllers
{
[Route("api/[controller]")]
[ApiController]
public class MSTeamsWebHooksController : ControllerBase
{
private readonly SMSDbCtx _context;
public MSTeamsWebHooksController(SMSDbCtx context, IWebHostEnvironment environment)
{
_context = context;
if (!environment.IsDevelopment())
{
throw new InvalidOperationException("Not supported in production mode");
}
}
// GET: api/MSTeamsWebHooks
[HttpGet]
public async Task<ActionResult<IEnumerable<MSTeamsWebHook>>> GetMSTeamsWebHooks()
{
return await _context.MSTeamsWebHooks.ToListAsync();
}
// GET: api/MSTeamsWebHooks/5
[HttpGet("{id}")]
public async Task<ActionResult<MSTeamsWebHook>> GetMSTeamsWebHook(int id)
{
var mSTeamsWebHook = await _context.MSTeamsWebHooks.FindAsync(id);
if (mSTeamsWebHook == null)
{
return NotFound();
}
return mSTeamsWebHook;
}
// PUT: api/MSTeamsWebHooks/5
// To protect from overposting attacks, see https://go.microsoft.com/fwlink/?linkid=2123754
[HttpPut("{id}")]
public async Task<IActionResult> PutMSTeamsWebHook(int id, MSTeamsWebHook mSTeamsWebHook)
{
if (id != mSTeamsWebHook.Id)
{
return BadRequest();
}
_context.Entry(mSTeamsWebHook).State = EntityState.Modified;
try
{
await _context.SaveChangesAsync();
}
catch (DbUpdateConcurrencyException)
{
if (!MSTeamsWebHookExists(id))
{
return NotFound();
}
else
{
throw;
}
}
return NoContent();
}
// POST: api/MSTeamsWebHooks
// To protect from overposting attacks, see https://go.microsoft.com/fwlink/?linkid=2123754
[HttpPost]
public async Task<ActionResult<MSTeamsWebHook>> PostMSTeamsWebHook([FromForm]string teamsHookUrl)
{
var mSTeamsWebHook = new MSTeamsWebHook
{
WebHookUri = teamsHookUrl
};
_context.MSTeamsWebHooks.Add(mSTeamsWebHook);
await _context.SaveChangesAsync();
return CreatedAtAction("GetMSTeamsWebHook", new { id = mSTeamsWebHook.Id }, mSTeamsWebHook);
}
// DELETE: api/MSTeamsWebHooks/5
[HttpDelete("{id}")]
public async Task<IActionResult> DeleteMSTeamsWebHook(int id)
{
var mSTeamsWebHook = await _context.MSTeamsWebHooks.FindAsync(id);
if (mSTeamsWebHook == null)
{
return NotFound();
}
_context.MSTeamsWebHooks.Remove(mSTeamsWebHook);
await _context.SaveChangesAsync();
return NoContent();
}
private bool MSTeamsWebHookExists(int id)
{
return _context.MSTeamsWebHooks.Any(e => e.Id == id);
}
}
}

View File

@ -0,0 +1,91 @@
#nullable disable
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using Twilio.AspNet.Common;
using TwilioSMSReceiver;
using TwilioSMSReceiver.Interfaces;
using TwilioSMSReceiver.Models;
namespace TwilioSMSReceiver.Controllers
{
[Route("api/[controller]")]
[ApiController]
public class SMSReceiverController : ControllerBase
{
private readonly SMSDbCtx _context;
private readonly IEnumerable<IMessageHandler> _messageHandlers;
public SMSReceiverController(SMSDbCtx context, IEnumerable<IMessageHandler> messageHandlers)
{
_context = context;
_messageHandlers = messageHandlers;
}
// GET: api/SMSReceiver
[HttpGet]
public async Task<ActionResult<IEnumerable<SMSModel>>> GetSMSMessages()
{
return await _context.SMSMessages.Include(b => b.MMSContent).ToListAsync();
}
// GET: api/SMSReceiver/5
[HttpGet("{id}")]
public async Task<ActionResult<SMSModel>> GetSMSModel(int id)
{
var sMSModel = await _context.SMSMessages.FindAsync(id);
if (sMSModel == null)
{
return NotFound();
}
return sMSModel;
}
// POST: api/SMSReceiver
// To protect from overposting attacks, see https://go.microsoft.com/fwlink/?linkid=2123754
[HttpPost]
public async Task<ActionResult<SMSModel>> PostSMSModel([FromForm]SmsRequest smsRequest, [FromForm] int? numMedia)
{
var mmsItems = new List<MMSModel>();
var message = new SMSModel
{
MessageContents = smsRequest.Body,
SenderNumber = smsRequest.From,
ReceivedNumber = smsRequest.To,
TimeReceived = DateTime.UtcNow
};
if (numMedia != null)
{
for (var i = 0; i < numMedia; i++)
{
var uri = Request.Form[$"MediaUrl{i}"];
mmsItems.Add(new MMSModel { OriginalMMSData = uri });
}
message.MMSContent = mmsItems;
}
_context.SMSMessages.Add(message);
await _context.SaveChangesAsync();
List<Task> _HandleAllMessages = new List<Task>();
foreach (var handler in _messageHandlers)
{
_HandleAllMessages.Add(handler.RelaySms(message));
}
return Ok();
}
private bool SMSModelExists(int id)
{
return _context.SMSMessages.Any(e => e.Id == id);
}
}
}

View File

@ -0,0 +1,36 @@
#nullable disable
using TwilioSMSReceiver.Models;
namespace TwilioSMSReceiver.Interfaces
{
public abstract class BaseHandler : IMessageHandler
{
protected readonly SMSDbCtx sMSDbCtx;
protected readonly ILogger<BaseHandler> _logger;
protected readonly IServiceProvider _serviceProvider;
public BaseHandler(IServiceProvider serviceProvider)
{
_serviceProvider = serviceProvider;
sMSDbCtx = _serviceProvider.CreateScope().ServiceProvider.GetService<SMSDbCtx>();
_logger = _serviceProvider.CreateScope().ServiceProvider.GetService<ILogger<BaseHandler>>();
}
public virtual async Task<bool> RelaySms(SMSModel model)
{
if (sMSDbCtx.SMSMessages.Any(b => b.Id == model.Id))
{
var message =
sMSDbCtx.SMSMessages.Where(b => b.Id == model.Id).First();
if (!message.IsForwardedYet)
{
_logger.LogInformation($"Marking message with id {message.Id} as forwarded");
message.IsForwardedYet = true;
sMSDbCtx.SMSMessages.Update(message);
await sMSDbCtx.SaveChangesAsync();
return true;
}
}
return false;
}
}
}

View File

@ -0,0 +1,9 @@
using TwilioSMSReceiver.Models;
namespace TwilioSMSReceiver.Interfaces
{
public interface IMessageHandler
{
public Task<bool> RelaySms(SMSModel model);
}
}

View File

@ -0,0 +1,51 @@
using TwilioSMSReceiver.Models;
using TeamsHook.NET;
namespace TwilioSMSReceiver.Interfaces
{
public class MSTeamsHandler : BaseHandler
{
public MSTeamsHandler(IServiceProvider serviceProvider) : base(serviceProvider)
{
}
public override async Task<bool> RelaySms(SMSModel model)
{
var teams = sMSDbCtx.MSTeamsWebHooks;
if (!teams.Any())
{
_logger.LogWarning("Teams Webhook list is empty!");
return false;
}
List<Task> teamsPostRequests = new List<Task>();
foreach (var teamHook in teams)
{
try
{
var teamsClient = new TeamsHookClient();
var card = new MessageCard
{
Title = $"Incoming SMS from {model.SenderNumber}",
Summary = $"Sent to {model.ReceivedNumber}",
Text = $"{model.MessageContents}"
};
teamsPostRequests.Add(teamsClient.PostAsync(teamHook.WebHookUri, card));
} catch (Exception ex)
{
_logger.LogError($"Webhook with URL {teamHook.WebHookUri} failed to post. Exception here {ex}");
}
}
try
{
await Task.WhenAll(teamsPostRequests);
} catch (Exception ex)
{
_logger.LogError($"Webhook failure {ex}");
}
return await base.RelaySms(model);
}
}
}

View File

@ -0,0 +1,17 @@
using TwilioSMSReceiver.Models;
namespace TwilioSMSReceiver.Interfaces
{
public class SMTPHandler : BaseHandler
{
public SMTPHandler(IServiceProvider serviceProvider) : base(serviceProvider)
{
}
public override Task<bool> RelaySms(SMSModel model)
{
_logger.LogWarning("SMTP isn't implemented yet");
return Task.FromResult(false);
}
}
}

View File

@ -0,0 +1,52 @@
// <auto-generated />
using System;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Migrations;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
using TwilioSMSReceiver;
#nullable disable
namespace TwilioSMSReceiver.Migrations
{
[DbContext(typeof(SMSDbCtx))]
[Migration("20211227010718_InitialMigration")]
partial class InitialMigration
{
protected override void BuildTargetModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
modelBuilder.HasAnnotation("ProductVersion", "6.0.1");
modelBuilder.Entity("TwilioSMSReceiver.Models.SMSModel", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("INTEGER");
b.Property<string>("MMSContentPath")
.HasColumnType("TEXT");
b.Property<string>("MessageContents")
.HasColumnType("TEXT");
b.Property<string>("ReceivedNumber")
.IsRequired()
.HasColumnType("TEXT");
b.Property<string>("SenderNumber")
.IsRequired()
.HasColumnType("TEXT");
b.Property<DateTime>("TimeReceived")
.HasColumnType("TEXT");
b.HasKey("Id");
b.ToTable("SMSMessages");
});
#pragma warning restore 612, 618
}
}
}

View File

@ -0,0 +1,36 @@
using System;
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace TwilioSMSReceiver.Migrations
{
public partial class InitialMigration : Migration
{
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.CreateTable(
name: "SMSMessages",
columns: table => new
{
Id = table.Column<int>(type: "INTEGER", nullable: false)
.Annotation("Sqlite:Autoincrement", true),
ReceivedNumber = table.Column<string>(type: "TEXT", nullable: false),
SenderNumber = table.Column<string>(type: "TEXT", nullable: false),
TimeReceived = table.Column<DateTime>(type: "TEXT", nullable: false),
MessageContents = table.Column<string>(type: "TEXT", nullable: true),
MMSContentPath = table.Column<string>(type: "TEXT", nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_SMSMessages", x => x.Id);
});
}
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropTable(
name: "SMSMessages");
}
}
}

View File

@ -0,0 +1,85 @@
// <auto-generated />
using System;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Migrations;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
using TwilioSMSReceiver;
#nullable disable
namespace TwilioSMSReceiver.Migrations
{
[DbContext(typeof(SMSDbCtx))]
[Migration("20211227015928_AddMMSData")]
partial class AddMMSData
{
protected override void BuildTargetModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
modelBuilder.HasAnnotation("ProductVersion", "6.0.1");
modelBuilder.Entity("TwilioSMSReceiver.Models.MMSModel", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("INTEGER");
b.Property<string>("OriginalMMSData")
.IsRequired()
.HasColumnType("TEXT");
b.Property<int>("SMSModelId")
.HasColumnType("INTEGER");
b.HasKey("Id");
b.HasIndex("SMSModelId");
b.ToTable("MMSModel");
});
modelBuilder.Entity("TwilioSMSReceiver.Models.SMSModel", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("INTEGER");
b.Property<string>("MessageContents")
.HasColumnType("TEXT");
b.Property<string>("ReceivedNumber")
.IsRequired()
.HasColumnType("TEXT");
b.Property<string>("SenderNumber")
.IsRequired()
.HasColumnType("TEXT");
b.Property<DateTime>("TimeReceived")
.HasColumnType("TEXT");
b.HasKey("Id");
b.ToTable("SMSMessages");
});
modelBuilder.Entity("TwilioSMSReceiver.Models.MMSModel", b =>
{
b.HasOne("TwilioSMSReceiver.Models.SMSModel", "ParentSMSMessage")
.WithMany("MMSContent")
.HasForeignKey("SMSModelId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("ParentSMSMessage");
});
modelBuilder.Entity("TwilioSMSReceiver.Models.SMSModel", b =>
{
b.Navigation("MMSContent");
});
#pragma warning restore 612, 618
}
}
}

View File

@ -0,0 +1,53 @@
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace TwilioSMSReceiver.Migrations
{
public partial class AddMMSData : Migration
{
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropColumn(
name: "MMSContentPath",
table: "SMSMessages");
migrationBuilder.CreateTable(
name: "MMSModel",
columns: table => new
{
Id = table.Column<int>(type: "INTEGER", nullable: false)
.Annotation("Sqlite:Autoincrement", true),
SMSModelId = table.Column<int>(type: "INTEGER", nullable: false),
OriginalMMSData = table.Column<string>(type: "TEXT", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_MMSModel", x => x.Id);
table.ForeignKey(
name: "FK_MMSModel_SMSMessages_SMSModelId",
column: x => x.SMSModelId,
principalTable: "SMSMessages",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateIndex(
name: "IX_MMSModel_SMSModelId",
table: "MMSModel",
column: "SMSModelId");
}
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropTable(
name: "MMSModel");
migrationBuilder.AddColumn<string>(
name: "MMSContentPath",
table: "SMSMessages",
type: "TEXT",
nullable: true);
}
}
}

View File

@ -0,0 +1,87 @@
// <auto-generated />
using System;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Migrations;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
using TwilioSMSReceiver;
#nullable disable
namespace TwilioSMSReceiver.Migrations
{
[DbContext(typeof(SMSDbCtx))]
[Migration("20211227022011_AddIsBroadcastedFlag")]
partial class AddIsBroadcastedFlag
{
protected override void BuildTargetModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
modelBuilder.HasAnnotation("ProductVersion", "6.0.1");
modelBuilder.Entity("TwilioSMSReceiver.Models.MMSModel", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("INTEGER");
b.Property<string>("OriginalMMSData")
.HasColumnType("TEXT");
b.Property<int>("SMSModelId")
.HasColumnType("INTEGER");
b.HasKey("Id");
b.HasIndex("SMSModelId");
b.ToTable("MMSModel");
});
modelBuilder.Entity("TwilioSMSReceiver.Models.SMSModel", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("INTEGER");
b.Property<bool>("IsForwardedYet")
.HasColumnType("INTEGER");
b.Property<string>("MessageContents")
.HasColumnType("TEXT");
b.Property<string>("ReceivedNumber")
.IsRequired()
.HasColumnType("TEXT");
b.Property<string>("SenderNumber")
.IsRequired()
.HasColumnType("TEXT");
b.Property<DateTime>("TimeReceived")
.HasColumnType("TEXT");
b.HasKey("Id");
b.ToTable("SMSMessages");
});
modelBuilder.Entity("TwilioSMSReceiver.Models.MMSModel", b =>
{
b.HasOne("TwilioSMSReceiver.Models.SMSModel", "ParentSMSMessage")
.WithMany("MMSContent")
.HasForeignKey("SMSModelId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("ParentSMSMessage");
});
modelBuilder.Entity("TwilioSMSReceiver.Models.SMSModel", b =>
{
b.Navigation("MMSContent");
});
#pragma warning restore 612, 618
}
}
}

View File

@ -0,0 +1,44 @@
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace TwilioSMSReceiver.Migrations
{
public partial class AddIsBroadcastedFlag : Migration
{
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AddColumn<bool>(
name: "IsForwardedYet",
table: "SMSMessages",
type: "INTEGER",
nullable: false,
defaultValue: false);
migrationBuilder.AlterColumn<string>(
name: "OriginalMMSData",
table: "MMSModel",
type: "TEXT",
nullable: true,
oldClrType: typeof(string),
oldType: "TEXT");
}
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropColumn(
name: "IsForwardedYet",
table: "SMSMessages");
migrationBuilder.AlterColumn<string>(
name: "OriginalMMSData",
table: "MMSModel",
type: "TEXT",
nullable: false,
defaultValue: "",
oldClrType: typeof(string),
oldType: "TEXT",
oldNullable: true);
}
}
}

View File

@ -0,0 +1,101 @@
// <auto-generated />
using System;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Migrations;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
using TwilioSMSReceiver;
#nullable disable
namespace TwilioSMSReceiver.Migrations
{
[DbContext(typeof(SMSDbCtx))]
[Migration("20211227034115_AddMSTeams")]
partial class AddMSTeams
{
protected override void BuildTargetModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
modelBuilder.HasAnnotation("ProductVersion", "6.0.1");
modelBuilder.Entity("TwilioSMSReceiver.Models.MMSModel", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("INTEGER");
b.Property<string>("OriginalMMSData")
.HasColumnType("TEXT");
b.Property<int>("SMSModelId")
.HasColumnType("INTEGER");
b.HasKey("Id");
b.HasIndex("SMSModelId");
b.ToTable("MMSMessages");
});
modelBuilder.Entity("TwilioSMSReceiver.Models.MSTeamsWebHook", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("INTEGER");
b.Property<string>("WebHookUri")
.HasColumnType("TEXT");
b.HasKey("Id");
b.ToTable("MSTeamsWebHooks");
});
modelBuilder.Entity("TwilioSMSReceiver.Models.SMSModel", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("INTEGER");
b.Property<bool>("IsForwardedYet")
.HasColumnType("INTEGER");
b.Property<string>("MessageContents")
.HasColumnType("TEXT");
b.Property<string>("ReceivedNumber")
.IsRequired()
.HasColumnType("TEXT");
b.Property<string>("SenderNumber")
.IsRequired()
.HasColumnType("TEXT");
b.Property<DateTime>("TimeReceived")
.HasColumnType("TEXT");
b.HasKey("Id");
b.ToTable("SMSMessages");
});
modelBuilder.Entity("TwilioSMSReceiver.Models.MMSModel", b =>
{
b.HasOne("TwilioSMSReceiver.Models.SMSModel", "ParentSMSMessage")
.WithMany("MMSContent")
.HasForeignKey("SMSModelId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("ParentSMSMessage");
});
modelBuilder.Entity("TwilioSMSReceiver.Models.SMSModel", b =>
{
b.Navigation("MMSContent");
});
#pragma warning restore 612, 618
}
}
}

View File

@ -0,0 +1,91 @@
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace TwilioSMSReceiver.Migrations
{
public partial class AddMSTeams : Migration
{
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropForeignKey(
name: "FK_MMSModel_SMSMessages_SMSModelId",
table: "MMSModel");
migrationBuilder.DropPrimaryKey(
name: "PK_MMSModel",
table: "MMSModel");
migrationBuilder.RenameTable(
name: "MMSModel",
newName: "MMSMessages");
migrationBuilder.RenameIndex(
name: "IX_MMSModel_SMSModelId",
table: "MMSMessages",
newName: "IX_MMSMessages_SMSModelId");
migrationBuilder.AddPrimaryKey(
name: "PK_MMSMessages",
table: "MMSMessages",
column: "Id");
migrationBuilder.CreateTable(
name: "MSTeamsWebHooks",
columns: table => new
{
Id = table.Column<int>(type: "INTEGER", nullable: false)
.Annotation("Sqlite:Autoincrement", true),
WebHookUri = table.Column<string>(type: "TEXT", nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_MSTeamsWebHooks", x => x.Id);
});
migrationBuilder.AddForeignKey(
name: "FK_MMSMessages_SMSMessages_SMSModelId",
table: "MMSMessages",
column: "SMSModelId",
principalTable: "SMSMessages",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
}
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropForeignKey(
name: "FK_MMSMessages_SMSMessages_SMSModelId",
table: "MMSMessages");
migrationBuilder.DropTable(
name: "MSTeamsWebHooks");
migrationBuilder.DropPrimaryKey(
name: "PK_MMSMessages",
table: "MMSMessages");
migrationBuilder.RenameTable(
name: "MMSMessages",
newName: "MMSModel");
migrationBuilder.RenameIndex(
name: "IX_MMSMessages_SMSModelId",
table: "MMSModel",
newName: "IX_MMSModel_SMSModelId");
migrationBuilder.AddPrimaryKey(
name: "PK_MMSModel",
table: "MMSModel",
column: "Id");
migrationBuilder.AddForeignKey(
name: "FK_MMSModel_SMSMessages_SMSModelId",
table: "MMSModel",
column: "SMSModelId",
principalTable: "SMSMessages",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
}
}
}

View File

@ -0,0 +1,99 @@
// <auto-generated />
using System;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
using TwilioSMSReceiver;
#nullable disable
namespace TwilioSMSReceiver.Migrations
{
[DbContext(typeof(SMSDbCtx))]
partial class SMSDbCtxModelSnapshot : ModelSnapshot
{
protected override void BuildModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
modelBuilder.HasAnnotation("ProductVersion", "6.0.1");
modelBuilder.Entity("TwilioSMSReceiver.Models.MMSModel", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("INTEGER");
b.Property<string>("OriginalMMSData")
.HasColumnType("TEXT");
b.Property<int>("SMSModelId")
.HasColumnType("INTEGER");
b.HasKey("Id");
b.HasIndex("SMSModelId");
b.ToTable("MMSMessages");
});
modelBuilder.Entity("TwilioSMSReceiver.Models.MSTeamsWebHook", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("INTEGER");
b.Property<string>("WebHookUri")
.HasColumnType("TEXT");
b.HasKey("Id");
b.ToTable("MSTeamsWebHooks");
});
modelBuilder.Entity("TwilioSMSReceiver.Models.SMSModel", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("INTEGER");
b.Property<bool>("IsForwardedYet")
.HasColumnType("INTEGER");
b.Property<string>("MessageContents")
.HasColumnType("TEXT");
b.Property<string>("ReceivedNumber")
.IsRequired()
.HasColumnType("TEXT");
b.Property<string>("SenderNumber")
.IsRequired()
.HasColumnType("TEXT");
b.Property<DateTime>("TimeReceived")
.HasColumnType("TEXT");
b.HasKey("Id");
b.ToTable("SMSMessages");
});
modelBuilder.Entity("TwilioSMSReceiver.Models.MMSModel", b =>
{
b.HasOne("TwilioSMSReceiver.Models.SMSModel", "ParentSMSMessage")
.WithMany("MMSContent")
.HasForeignKey("SMSModelId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("ParentSMSMessage");
});
modelBuilder.Entity("TwilioSMSReceiver.Models.SMSModel", b =>
{
b.Navigation("MMSContent");
});
#pragma warning restore 612, 618
}
}
}

View File

@ -0,0 +1,36 @@
#nullable disable
using Microsoft.EntityFrameworkCore;
using System.ComponentModel.DataAnnotations;
namespace TwilioSMSReceiver.Models
{
public class SMSModel
{
[Key]
public int Id { get; set; }
[Required]
public string ReceivedNumber { get; set; }
[Required]
public string SenderNumber { get; set; }
public DateTime TimeReceived { get; set; }
public string? MessageContents { get; set; }
public ICollection<MMSModel> MMSContent { get; set; }
public bool IsForwardedYet { get; set; }
}
public class MMSModel
{
[Key]
public int Id { get; set; }
public int SMSModelId { get; set; }
public SMSModel ParentSMSMessage { get; set; }
public string OriginalMMSData { get; set; }
}
public class MSTeamsWebHook
{
public int Id { get; set; }
public string WebHookUri { get; set; }
}
}

View File

@ -0,0 +1,36 @@
using Microsoft.EntityFrameworkCore;
using TwilioSMSReceiver;
using TwilioSMSReceiver.Interfaces;
var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
builder.Services.AddControllers().AddNewtonsoftJson(x => x.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore);
// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
builder.Services.AddDbContext<SMSDbCtx>(options => {
options.UseSqlite(builder.Configuration.GetConnectionString("SmsDBCtx"));
});
builder.Services.AddScoped<IMessageHandler, MSTeamsHandler>();
builder.Services.AddScoped<IMessageHandler, SMTPHandler>();
builder.Services.AddLogging();
//builder.Services.AddSingleton<IMessageHandler>();
var app = builder.Build();
// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
app.UseSwagger();
app.UseSwaggerUI();
}
app.UseHttpsRedirection();
app.UseAuthorization();
app.MapControllers();
app.Run();

View File

@ -0,0 +1,31 @@
{
"$schema": "https://json.schemastore.org/launchsettings.json",
"iisSettings": {
"windowsAuthentication": false,
"anonymousAuthentication": true,
"iisExpress": {
"applicationUrl": "http://localhost:17821",
"sslPort": 44325
}
},
"profiles": {
"TwilioSMSReceiver": {
"commandName": "Project",
"dotnetRunMessages": true,
"launchBrowser": true,
"launchUrl": "swagger",
"applicationUrl": "https://[::]:7078;http://[::]:5078",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
},
"IIS Express": {
"commandName": "IISExpress",
"launchBrowser": true,
"launchUrl": "swagger",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
}
}
}

View File

@ -0,0 +1,16 @@
using Microsoft.EntityFrameworkCore;
using TwilioSMSReceiver.Models;
namespace TwilioSMSReceiver
{
public class SMSDbCtx : DbContext
{
public SMSDbCtx(DbContextOptions options) : base(options)
{
}
public DbSet<SMSModel> SMSMessages { get;set; }
public DbSet<MMSModel> MMSMessages { get;set; }
public DbSet<MSTeamsWebHook> MSTeamsWebHooks { get;set; }
}
}

View File

@ -0,0 +1,27 @@
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.Mvc.NewtonsoftJson" Version="6.0.1" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="6.0.1">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="6.0.1" />
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="6.0.1" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="6.0.1">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Microsoft.VisualStudio.Web.CodeGeneration.Design" Version="6.0.1" />
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.2.3" />
<PackageReference Include="TeamsHook.NET" Version="0.1.0.18" />
<PackageReference Include="Twilio.AspNet.Common" Version="5.68.3" />
</ItemGroup>
</Project>

View File

@ -0,0 +1,13 @@
namespace TwilioSMSReceiver
{
public class WeatherForecast
{
public DateTime Date { get; set; }
public int TemperatureC { get; set; }
public int TemperatureF => 32 + (int)(TemperatureC / 0.5556);
public string? Summary { get; set; }
}
}

View File

@ -0,0 +1,8 @@
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
}
}

View File

@ -0,0 +1,12 @@
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
},
"ConnectionStrings": {
"SmsDbCtx": "Data Source=smsdbctx.sqlite"
},
"AllowedHosts": "*"
}