Merge pull request 'dotnet' (#1) from dotnet into master
Reviewed-on: phoenix/textsender-api#1
This commit is contained in:
@@ -0,0 +1,5 @@
|
|||||||
|
.vscode
|
||||||
|
appsettings.Development.json
|
||||||
|
*.json
|
||||||
|
bin
|
||||||
|
obj
|
||||||
@@ -0,0 +1,67 @@
|
|||||||
|
using TextSender_API.Models;
|
||||||
|
|
||||||
|
namespace TextSender_API.Controllers;
|
||||||
|
|
||||||
|
public class ContactManagement
|
||||||
|
{
|
||||||
|
#region Fields
|
||||||
|
private IConfiguration _config;
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
|
||||||
|
#region Constructors
|
||||||
|
public ContactManagement(IConfiguration config)
|
||||||
|
{
|
||||||
|
this._config = config;
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
|
||||||
|
#region Methods
|
||||||
|
// Queues the contact file to be processed latter
|
||||||
|
public ContactCreationQueue QueueContact(IFormFile file)
|
||||||
|
{
|
||||||
|
var queue = new ContactCreationQueue();
|
||||||
|
queue.Processed = false;
|
||||||
|
var directory = this._config["Paths:ContactQueueDirectory"];
|
||||||
|
|
||||||
|
if (directory!.ElementAt(directory!.Length - 1) != '/')
|
||||||
|
{
|
||||||
|
directory.Append('/');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!System.IO.Directory.Exists(directory))
|
||||||
|
{
|
||||||
|
queue.Status = "Missing directory";
|
||||||
|
// Directory does not exist
|
||||||
|
return queue;
|
||||||
|
}
|
||||||
|
|
||||||
|
var length = 16;
|
||||||
|
var chars = "ABCDEF0123456789";
|
||||||
|
var random = new Random();
|
||||||
|
var filename = new string(Enumerable.Repeat(chars, length).Select(s =>
|
||||||
|
s[random.Next(s.Length)]).ToArray());
|
||||||
|
var extension = ".txt";
|
||||||
|
|
||||||
|
var contactPath = $"{directory}/{filename}{extension}";
|
||||||
|
queue.Filepath = contactPath;
|
||||||
|
|
||||||
|
if (System.IO.File.Exists(contactPath))
|
||||||
|
{
|
||||||
|
// Already exists
|
||||||
|
queue.Status = "File exists";
|
||||||
|
return queue;
|
||||||
|
}
|
||||||
|
|
||||||
|
queue.Status = "Created";
|
||||||
|
|
||||||
|
using (var filestream = new FileStream(contactPath, FileMode.Create))
|
||||||
|
{
|
||||||
|
file.CopyTo(filestream);
|
||||||
|
}
|
||||||
|
|
||||||
|
return queue;
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
@@ -0,0 +1,88 @@
|
|||||||
|
using Microsoft.AspNetCore.Authorization;
|
||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
|
||||||
|
using TextSender_API.Models;
|
||||||
|
using TextSender_API.Repositories;
|
||||||
|
|
||||||
|
namespace TextSender_API.Controllers;
|
||||||
|
|
||||||
|
[Authorize]
|
||||||
|
[ApiController]
|
||||||
|
[Route("api/v1/contact/queue")]
|
||||||
|
public class ContactQueueCreationController : ControllerBase
|
||||||
|
{
|
||||||
|
#region Fields
|
||||||
|
private IConfiguration _config;
|
||||||
|
private readonly ILogger<ContactQueueCreationController> _logger;
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
|
||||||
|
#region Constructors
|
||||||
|
|
||||||
|
public ContactQueueCreationController(ILogger<ContactQueueCreationController> logger, IConfiguration config)
|
||||||
|
{
|
||||||
|
this._logger = logger;
|
||||||
|
this._config = config;
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Methods
|
||||||
|
[HttpPost("upload"), DisableRequestSizeLimit]
|
||||||
|
public IActionResult Upload([FromForm(Name = "file")] List<IFormFile> contactFile,
|
||||||
|
[FromForm(Name = "user_id")] string userID)
|
||||||
|
{
|
||||||
|
// Save the file on the filesystem to be processed by a separate
|
||||||
|
// system
|
||||||
|
var response = new CreateQueueResponse();
|
||||||
|
var connString = this._config.GetConnectionString("MongoDBURI");
|
||||||
|
var userRepo = new UsersRepository(connString!);
|
||||||
|
var queueRepo = new ContactCreationQueueRepository(connString!);
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var ctMgr = new ContactManagement(this._config);
|
||||||
|
var user = userRepo.Exists(userID);
|
||||||
|
|
||||||
|
if (!user.Item1)
|
||||||
|
{
|
||||||
|
return NotFound(response);
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var file in contactFile)
|
||||||
|
{
|
||||||
|
var queue = ctMgr.QueueContact(file);
|
||||||
|
queue.UserId = user.Item2.Id;
|
||||||
|
queue.DateCreated = DateTime.Now;
|
||||||
|
queueRepo.Create(queue);
|
||||||
|
|
||||||
|
response.Data.Add(queue);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
this._logger.LogError($"An error occurred: {ex.Message}");
|
||||||
|
}
|
||||||
|
|
||||||
|
return Ok(response);
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
|
||||||
|
#region Responses
|
||||||
|
public class CreateQueueResponse
|
||||||
|
{
|
||||||
|
#region Properties
|
||||||
|
[JsonProperty("data")]
|
||||||
|
public List<ContactCreationQueue> Data { get; set; }
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Constructors
|
||||||
|
public CreateQueueResponse()
|
||||||
|
{
|
||||||
|
this.Data = new List<ContactCreationQueue>();
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
@@ -0,0 +1,94 @@
|
|||||||
|
using Microsoft.AspNetCore.Authorization;
|
||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
|
||||||
|
using TextSender_API.Models;
|
||||||
|
using TextSender_API.Repositories;
|
||||||
|
|
||||||
|
namespace TextSender_API.Controllers;
|
||||||
|
|
||||||
|
[Authorize]
|
||||||
|
[ApiController]
|
||||||
|
[Route("api/v1/contact")]
|
||||||
|
public class ContactsController : ControllerBase
|
||||||
|
{
|
||||||
|
#region Fields
|
||||||
|
private IConfiguration _config;
|
||||||
|
private readonly ILogger<ContactsController> _logger;
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
|
||||||
|
#region Constructors
|
||||||
|
|
||||||
|
public ContactsController(ILogger<ContactsController> logger, IConfiguration config)
|
||||||
|
{
|
||||||
|
this._logger = logger;
|
||||||
|
this._config = config;
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Methods
|
||||||
|
[HttpPost("new"), DisableRequestSizeLimit]
|
||||||
|
public IActionResult CreateContact([FromBody] Contact contact)
|
||||||
|
{
|
||||||
|
var response = new CreateContactResponse();
|
||||||
|
var connString = this._config.GetConnectionString("MongoDBURI");
|
||||||
|
var userRepo = new UsersRepository(connString!);
|
||||||
|
var contactsRepo = new ContactsRepository(connString!);
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var contacts = contactsRepo.RetrieveAll();
|
||||||
|
var users = userRepo.RetrieveAllUsers();
|
||||||
|
|
||||||
|
if (users.Count() == 0)
|
||||||
|
{
|
||||||
|
return BadRequest(response);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (contacts.Count() > 0)
|
||||||
|
{
|
||||||
|
if (contacts.Exists(c => c.PhoneNumber!.Equals(contact.PhoneNumber)) ||
|
||||||
|
string.IsNullOrEmpty(contact.UserID))
|
||||||
|
{
|
||||||
|
// The Contact already exists
|
||||||
|
return BadRequest(response);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!userRepo.Exists(contact.UserID!).Item1)
|
||||||
|
{
|
||||||
|
return BadRequest(response);
|
||||||
|
}
|
||||||
|
|
||||||
|
contact.DateCreated = DateTime.Now;
|
||||||
|
contactsRepo.Create(contact);
|
||||||
|
response.Data.Add(contact);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
this._logger.LogError($"An error occurred: {ex.Message}");
|
||||||
|
}
|
||||||
|
|
||||||
|
return Ok(response);
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
|
||||||
|
#region Responses
|
||||||
|
public class CreateContactResponse
|
||||||
|
{
|
||||||
|
#region Properties
|
||||||
|
[JsonProperty("data")]
|
||||||
|
public List<Contact> Data { get; set; }
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Constructors
|
||||||
|
public CreateContactResponse()
|
||||||
|
{
|
||||||
|
this.Data = new List<Contact>();
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
@@ -0,0 +1,64 @@
|
|||||||
|
using System.Security.Cryptography;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
using TextSender_API.Models;
|
||||||
|
using TextSender_API.Repositories;
|
||||||
|
|
||||||
|
namespace TextSender_API.Controllers;
|
||||||
|
|
||||||
|
public class PasswordVerification
|
||||||
|
{
|
||||||
|
#region Fiends
|
||||||
|
private UsersRepository _userRepo;
|
||||||
|
private SaltRepository _saltRepo;
|
||||||
|
private int _keySize = 64;
|
||||||
|
private int _iterations = 350000;
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Constructors
|
||||||
|
public PasswordVerification(UsersRepository userRepo, SaltRepository saltRepo)
|
||||||
|
{
|
||||||
|
this._userRepo = userRepo;
|
||||||
|
this._saltRepo = saltRepo;
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Methods
|
||||||
|
public bool VerifyPassword(User user, string password)
|
||||||
|
{
|
||||||
|
var salt = this._saltRepo.Retrieve(user.Id!);
|
||||||
|
var hashedPassword = this.HashPassword(user, salt, password);
|
||||||
|
|
||||||
|
return hashedPassword.Equals(user.Password);
|
||||||
|
}
|
||||||
|
public Salt CreateSalt(User user)
|
||||||
|
{
|
||||||
|
var salt = new Salt();
|
||||||
|
salt.Key = RandomNumberGenerator.GetBytes(this._keySize);
|
||||||
|
|
||||||
|
return salt;
|
||||||
|
}
|
||||||
|
|
||||||
|
public string HashPassword(User user, Salt salt, string password = "")
|
||||||
|
{
|
||||||
|
var hashAlgorithm = HashAlgorithmName.SHA512;
|
||||||
|
var dbHashedPassword = user.Password;
|
||||||
|
|
||||||
|
if (!string.IsNullOrEmpty(password))
|
||||||
|
{
|
||||||
|
user.Password = password;
|
||||||
|
}
|
||||||
|
|
||||||
|
var hash = Rfc2898DeriveBytes.Pbkdf2(
|
||||||
|
Encoding.UTF8.GetBytes(user.Password!),
|
||||||
|
salt.Key!,
|
||||||
|
this._iterations,
|
||||||
|
hashAlgorithm,
|
||||||
|
this._keySize);
|
||||||
|
|
||||||
|
user.Password = dbHashedPassword;
|
||||||
|
|
||||||
|
return Convert.ToHexString(hash);
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
@@ -0,0 +1,228 @@
|
|||||||
|
using System.IdentityModel.Tokens;
|
||||||
|
using System.IdentityModel.Tokens.Jwt;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Security.Claims;
|
||||||
|
using System.Security.Cryptography;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
using Microsoft.IdentityModel.Tokens;
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
|
||||||
|
using TextSender_API.Models;
|
||||||
|
using TextSender_API.Repositories;
|
||||||
|
|
||||||
|
namespace TextSender_API.Controllers;
|
||||||
|
|
||||||
|
[ApiController]
|
||||||
|
[Route("api/v1/user")]
|
||||||
|
public class UsersController : ControllerBase
|
||||||
|
{
|
||||||
|
#region Fields
|
||||||
|
private readonly ILogger<UsersController> _logger;
|
||||||
|
private IConfiguration _config;
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
|
||||||
|
#region Constructors
|
||||||
|
|
||||||
|
public UsersController(ILogger<UsersController> logger, IConfiguration config)
|
||||||
|
{
|
||||||
|
this._logger = logger;
|
||||||
|
this._config = config;
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Methods
|
||||||
|
private string AllScopes()
|
||||||
|
{
|
||||||
|
var allScopes = new List<String>()
|
||||||
|
{
|
||||||
|
"create:contact"
|
||||||
|
};
|
||||||
|
|
||||||
|
var scopes = string.Empty;
|
||||||
|
|
||||||
|
for (var i = 0; i < allScopes.Count; i++)
|
||||||
|
{
|
||||||
|
if (i == allScopes.Count - 1)
|
||||||
|
{
|
||||||
|
scopes += allScopes[i];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
scopes += allScopes[i] + " ";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return scopes;
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<Claim> Payload()
|
||||||
|
{
|
||||||
|
var expLimit = 30;
|
||||||
|
var currentDate = DateTime.Now;
|
||||||
|
var expiredDate = currentDate.AddMinutes(expLimit);
|
||||||
|
var issued = Math.Floor((currentDate - DateTime.UnixEpoch).TotalSeconds);
|
||||||
|
var expires = Math.Floor((expiredDate - DateTime.UnixEpoch).TotalSeconds);
|
||||||
|
var issuer = this._config["JWT:Issuer"];
|
||||||
|
var audience = this._config["JWT:Audience"];
|
||||||
|
var subject = this._config["JWT:Subject"];
|
||||||
|
|
||||||
|
var claim = new List<System.Security.Claims.Claim>()
|
||||||
|
{
|
||||||
|
new System.Security.Claims.Claim("scope", AllScopes(), "string"),
|
||||||
|
new System.Security.Claims.Claim(JwtRegisteredClaimNames.Exp, expiredDate.ToString(), "string"),
|
||||||
|
new System.Security.Claims.Claim(JwtRegisteredClaimNames.Aud, audience!),
|
||||||
|
new System.Security.Claims.Claim(JwtRegisteredClaimNames.Iss, issuer!),
|
||||||
|
new Claim(JwtRegisteredClaimNames.Sub, subject!)
|
||||||
|
};
|
||||||
|
|
||||||
|
return claim;
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpPost("login")]
|
||||||
|
public IActionResult Login([FromBody] User userRequest)
|
||||||
|
{
|
||||||
|
var response = new LoginResponse();
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var connString = this._config.GetConnectionString("MongoDBURI");
|
||||||
|
var userRepo = new UsersRepository(connString!);
|
||||||
|
var saltRepo = new SaltRepository(connString!);
|
||||||
|
var pwdVerify = new PasswordVerification(userRepo, saltRepo);
|
||||||
|
var result = userRepo.Exists(userRequest);
|
||||||
|
|
||||||
|
if (result.Item1 && pwdVerify.VerifyPassword(result.Item2, userRequest.Password!))
|
||||||
|
{
|
||||||
|
var user = result.Item2;
|
||||||
|
var token = new Token();
|
||||||
|
token.Issued = DateTime.Now;
|
||||||
|
token.UserId = user.Id;
|
||||||
|
token.TokenType = "JWT";
|
||||||
|
|
||||||
|
var payload = Payload();
|
||||||
|
payload.Add(new System.Security.Claims.Claim("user_id", user.Id!, ClaimValueTypes.String));
|
||||||
|
|
||||||
|
var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(this._config["JWT:Secret"]!));
|
||||||
|
var signIn = new SigningCredentials(key, SecurityAlgorithms.HmacSha256);
|
||||||
|
|
||||||
|
var tok = new JwtSecurityToken(
|
||||||
|
this._config["JWT:Issuer"],
|
||||||
|
this._config["JWT:Audience"],
|
||||||
|
payload,
|
||||||
|
expires: DateTime.UtcNow.AddMinutes(30),
|
||||||
|
signingCredentials: signIn);
|
||||||
|
|
||||||
|
token.AccessToken = new JwtSecurityTokenHandler().WriteToken(tok);
|
||||||
|
|
||||||
|
var expClaim = payload.FirstOrDefault(cl =>
|
||||||
|
{
|
||||||
|
return cl.Type.Equals("exp");
|
||||||
|
});
|
||||||
|
|
||||||
|
if (expClaim != null)
|
||||||
|
{
|
||||||
|
var expiredDate = DateTime.Parse(expClaim!.Value);
|
||||||
|
var exp = Math.Floor((expiredDate - DateTime.UnixEpoch).TotalSeconds);
|
||||||
|
}
|
||||||
|
|
||||||
|
response.Data.Add(token);
|
||||||
|
Ok(response);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return NotFound(response);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
this._logger.LogError($"An error occurred: {ex.Message}");
|
||||||
|
}
|
||||||
|
|
||||||
|
return Ok(response);
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpPost("register"), DisableRequestSizeLimit]
|
||||||
|
public IActionResult Upload([FromBody] User userRequest)
|
||||||
|
{
|
||||||
|
var response = new RegisterUserResponse();
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var connString = this._config.GetConnectionString("MongoDBURI");
|
||||||
|
var userRepo = new UsersRepository(connString!);
|
||||||
|
var saltRepo = new SaltRepository(connString!);
|
||||||
|
var allUsers = userRepo.RetrieveAllUsers();
|
||||||
|
var result = allUsers.Exists(ea => ea.Username!.Equals(userRequest.Username));
|
||||||
|
|
||||||
|
if (!result)
|
||||||
|
{
|
||||||
|
var pwdVerify = new PasswordVerification(userRepo, saltRepo);
|
||||||
|
var salt = pwdVerify.CreateSalt(userRequest);
|
||||||
|
var hashedPassword = pwdVerify.HashPassword(userRequest, salt);
|
||||||
|
|
||||||
|
this._logger.LogInformation("Creating user");
|
||||||
|
userRequest.Password = hashedPassword;
|
||||||
|
userRequest.DateCreated = DateTime.Now;
|
||||||
|
userRepo.CreateUser(userRequest);
|
||||||
|
|
||||||
|
response.Data.Add(userRequest);
|
||||||
|
|
||||||
|
salt.UserId = userRequest.Id;
|
||||||
|
saltRepo.Create(salt);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
this._logger.LogInformation("User already exists");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
this._logger.LogError($"An error occurred: {ex.Message}");
|
||||||
|
}
|
||||||
|
|
||||||
|
return Ok(response);
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Responses
|
||||||
|
public class LoginResponse
|
||||||
|
{
|
||||||
|
#region Properties
|
||||||
|
[JsonProperty("data")]
|
||||||
|
public List<Token> Data { get; set; }
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Constructors
|
||||||
|
public LoginResponse()
|
||||||
|
{
|
||||||
|
this.Data = new List<Token>();
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Methods
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
|
||||||
|
public class RegisterUserResponse
|
||||||
|
{
|
||||||
|
#region Properties
|
||||||
|
[JsonProperty("data")]
|
||||||
|
public List<User> Data { get; set; }
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Constructors
|
||||||
|
public RegisterUserResponse()
|
||||||
|
{
|
||||||
|
this.Data = new List<User>();
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Methods
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
@@ -0,0 +1,53 @@
|
|||||||
|
using System;
|
||||||
|
|
||||||
|
using MongoDB.Bson;
|
||||||
|
using MongoDB.Bson.Serialization.Attributes;
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
|
||||||
|
namespace TextSender_API.Models;
|
||||||
|
|
||||||
|
public class Contact
|
||||||
|
{
|
||||||
|
#region Properties
|
||||||
|
[BsonId]
|
||||||
|
[BsonRepresentation(BsonType.ObjectId)]
|
||||||
|
[JsonProperty("id")]
|
||||||
|
public string? Id { get; set; }
|
||||||
|
[BsonElement("firstname")]
|
||||||
|
[JsonProperty("firstname")]
|
||||||
|
public string? Firstname { get; set; }
|
||||||
|
[BsonElement("lastname")]
|
||||||
|
[JsonProperty("lastname")]
|
||||||
|
public string? Lastname { get; set; }
|
||||||
|
[BsonElement("phonenumber")]
|
||||||
|
[JsonProperty("phonenumber")]
|
||||||
|
public string? PhoneNumber { get; set; }
|
||||||
|
[BsonElement("date_created")]
|
||||||
|
[JsonProperty("date_created")]
|
||||||
|
public DateTime DateCreated { get; set; }
|
||||||
|
// [BsonRepresentation(BsonType.ObjectId)]
|
||||||
|
[BsonElement("user_id")]
|
||||||
|
[JsonProperty("user_id")]
|
||||||
|
public string? UserID { get; set; }
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public class ContactCreationQueue
|
||||||
|
{
|
||||||
|
#region Properties
|
||||||
|
[BsonId]
|
||||||
|
[BsonRepresentation(BsonType.ObjectId)]
|
||||||
|
public string? Id { get; set; }
|
||||||
|
[BsonElement("filepath")]
|
||||||
|
public string? Filepath { get; set; }
|
||||||
|
[BsonElement("status")]
|
||||||
|
public string? Status { get; set; }
|
||||||
|
[BsonElement("user_id")]
|
||||||
|
public string? UserId { get; set; }
|
||||||
|
[BsonElement("date_created")]
|
||||||
|
public DateTime? DateCreated { get; set; }
|
||||||
|
[BsonElement("processed")]
|
||||||
|
public bool? Processed { get; set; }
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
using System;
|
||||||
|
|
||||||
|
namespace TextSender_API.Models;
|
||||||
|
|
||||||
|
public class Text
|
||||||
|
{
|
||||||
|
#region Properties
|
||||||
|
public int TextID { get; set; }
|
||||||
|
public string? Subject { get; set; }
|
||||||
|
public string? Message { get; set; }
|
||||||
|
public int UserID { get; set; }
|
||||||
|
public DateTime DateCreated { get; set; }
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
using System;
|
||||||
|
|
||||||
|
namespace TextSender_API.Models;
|
||||||
|
|
||||||
|
public class TextQueue
|
||||||
|
{
|
||||||
|
#region Properties
|
||||||
|
public int TextQueueID { get; set; }
|
||||||
|
public string? Status { get; set; }
|
||||||
|
public string? ContactPhoneNumber { get; set; }
|
||||||
|
public int TextID { get; set; }
|
||||||
|
public int UserID { get; set; }
|
||||||
|
public DateTime DateCreated { get; set; }
|
||||||
|
public DateTime ExecutionDate { get; set; }
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
using Newtonsoft.Json;
|
||||||
|
|
||||||
|
namespace TextSender_API.Models;
|
||||||
|
|
||||||
|
public class Token
|
||||||
|
{
|
||||||
|
#region Properties
|
||||||
|
[JsonProperty("access_token")]
|
||||||
|
public string? AccessToken { get; set; }
|
||||||
|
[JsonProperty("token_type")]
|
||||||
|
public string? TokenType { get; set; }
|
||||||
|
[JsonProperty("issued")]
|
||||||
|
public DateTime? Issued { get; set; }
|
||||||
|
[JsonProperty("id")]
|
||||||
|
public string? UserId { get; set; }
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
@@ -0,0 +1,46 @@
|
|||||||
|
using MongoDB.Bson;
|
||||||
|
using MongoDB.Bson.Serialization.Attributes;
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
|
||||||
|
namespace TextSender_API.Models;
|
||||||
|
|
||||||
|
public class User
|
||||||
|
{
|
||||||
|
#region Properties
|
||||||
|
[BsonId]
|
||||||
|
[BsonRepresentation(BsonType.ObjectId)]
|
||||||
|
[JsonProperty("id")]
|
||||||
|
public string? Id { get; set; }
|
||||||
|
[BsonElement("firstname")]
|
||||||
|
[JsonProperty("firstname")]
|
||||||
|
public string? Firstname { get; set; }
|
||||||
|
[BsonElement("lastname")]
|
||||||
|
[JsonProperty("lastname")]
|
||||||
|
public string? Lastname { get; set; }
|
||||||
|
[BsonElement("phonenumber")]
|
||||||
|
[JsonProperty("phone_number")]
|
||||||
|
public string? PhoneNumber { get; set; }
|
||||||
|
[BsonElement("username")]
|
||||||
|
[JsonProperty("username")]
|
||||||
|
public string? Username { get; set; }
|
||||||
|
[BsonElement("password")]
|
||||||
|
[JsonProperty("password")]
|
||||||
|
public string? Password { get; set; }
|
||||||
|
[BsonElement("datecreated")]
|
||||||
|
[JsonProperty("date_created")]
|
||||||
|
public DateTime? DateCreated { get; set; }
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
|
||||||
|
public class Salt
|
||||||
|
{
|
||||||
|
#region Properties
|
||||||
|
[BsonId]
|
||||||
|
[BsonRepresentation(BsonType.ObjectId)]
|
||||||
|
public string? Id { get; set; }
|
||||||
|
[BsonElement("key")]
|
||||||
|
public byte[]? Key { get; set; }
|
||||||
|
[BsonElement("user_id")]
|
||||||
|
public string? UserId { get; set; }
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
+63
@@ -0,0 +1,63 @@
|
|||||||
|
using System.Text;
|
||||||
|
|
||||||
|
using Microsoft.AspNetCore.Authentication.JwtBearer;
|
||||||
|
using Microsoft.AspNetCore.Builder;
|
||||||
|
using Microsoft.AspNetCore.Hosting;
|
||||||
|
using Microsoft.Extensions.Configuration;
|
||||||
|
using Microsoft.IdentityModel.Tokens;
|
||||||
|
|
||||||
|
using TextSender_API.Repositories;
|
||||||
|
|
||||||
|
var builder = WebApplication.CreateBuilder(args);
|
||||||
|
|
||||||
|
// Add services to the container.
|
||||||
|
|
||||||
|
builder.Services.AddControllers();
|
||||||
|
builder.Services.AddControllers().AddNewtonsoftJson();
|
||||||
|
|
||||||
|
// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
|
||||||
|
builder.Services.AddEndpointsApiExplorer();
|
||||||
|
builder.Services.AddSwaggerGen();
|
||||||
|
|
||||||
|
builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme).AddJwtBearer(options =>
|
||||||
|
{
|
||||||
|
options.RequireHttpsMetadata = false;
|
||||||
|
options.SaveToken = true;
|
||||||
|
options.TokenValidationParameters = new TokenValidationParameters()
|
||||||
|
{
|
||||||
|
ValidateIssuer = true,
|
||||||
|
ValidateAudience = true,
|
||||||
|
ValidAudience = builder.Configuration["JWT:Audience"],
|
||||||
|
ValidIssuer = builder.Configuration["JWT:Issuer"],
|
||||||
|
RequireExpirationTime = false,
|
||||||
|
ValidateIssuerSigningKey = false,
|
||||||
|
IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(builder.Configuration["JWT:Secret"]!))
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
// var connectionString = builder.Configuration.GetConnectionString("MongoDBURI");
|
||||||
|
|
||||||
|
|
||||||
|
var app = builder.Build();
|
||||||
|
|
||||||
|
// Configure the HTTP request pipeline.
|
||||||
|
if (app.Environment.IsDevelopment())
|
||||||
|
{
|
||||||
|
app.UseSwagger();
|
||||||
|
app.UseSwaggerUI();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
app.UseHttpsRedirection();
|
||||||
|
|
||||||
|
app.UseAuthentication();
|
||||||
|
app.UseRouting();
|
||||||
|
app.UseAuthorization();
|
||||||
|
app.UseEndpoints(endpoints =>
|
||||||
|
{
|
||||||
|
endpoints.MapControllers();
|
||||||
|
});
|
||||||
|
|
||||||
|
// app.MapControllers();
|
||||||
|
|
||||||
|
app.Run();
|
||||||
@@ -0,0 +1,41 @@
|
|||||||
|
{
|
||||||
|
"$schema": "https://json.schemastore.org/launchsettings.json",
|
||||||
|
"iisSettings": {
|
||||||
|
"windowsAuthentication": false,
|
||||||
|
"anonymousAuthentication": true,
|
||||||
|
"iisExpress": {
|
||||||
|
"applicationUrl": "http://localhost:22514",
|
||||||
|
"sslPort": 44361
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"profiles": {
|
||||||
|
"http": {
|
||||||
|
"commandName": "Project",
|
||||||
|
"dotnetRunMessages": true,
|
||||||
|
"launchBrowser": true,
|
||||||
|
"launchUrl": "swagger",
|
||||||
|
"applicationUrl": "http://localhost:5168",
|
||||||
|
"environmentVariables": {
|
||||||
|
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"https": {
|
||||||
|
"commandName": "Project",
|
||||||
|
"dotnetRunMessages": true,
|
||||||
|
"launchBrowser": true,
|
||||||
|
"launchUrl": "swagger",
|
||||||
|
"applicationUrl": "https://localhost:7154;http://localhost:5168",
|
||||||
|
"environmentVariables": {
|
||||||
|
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"IIS Express": {
|
||||||
|
"commandName": "IISExpress",
|
||||||
|
"launchBrowser": true,
|
||||||
|
"launchUrl": "swagger",
|
||||||
|
"environmentVariables": {
|
||||||
|
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -5,7 +5,11 @@ An API used to send texts messages to multiple contacts.
|
|||||||
## Getting started
|
## Getting started
|
||||||
|
|
||||||
Installing dependencies
|
Installing dependencies
|
||||||
`npm install`
|
```BASH
|
||||||
|
dotnet restore
|
||||||
|
```
|
||||||
|
|
||||||
Running server
|
Running server
|
||||||
`node app.js`
|
```BASH
|
||||||
|
dotnet run
|
||||||
|
```
|
||||||
|
|||||||
@@ -0,0 +1,11 @@
|
|||||||
|
|
||||||
|
namespace TextSender_API.Repositories;
|
||||||
|
|
||||||
|
public class BaseRepository
|
||||||
|
{
|
||||||
|
#region Fields
|
||||||
|
protected string? _connectionString;
|
||||||
|
protected string _databaseName = "textSender";
|
||||||
|
protected string? _tableName;
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
@@ -0,0 +1,131 @@
|
|||||||
|
using MongoDB.Driver;
|
||||||
|
|
||||||
|
using TextSender_API.Models;
|
||||||
|
|
||||||
|
namespace TextSender_API.Repositories;
|
||||||
|
|
||||||
|
|
||||||
|
public class ContactCreationQueueRepository : BaseRepository
|
||||||
|
{
|
||||||
|
#region Fields
|
||||||
|
private readonly IMongoCollection<ContactCreationQueue> _bookCollection;
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
|
||||||
|
#region Constructors
|
||||||
|
public ContactCreationQueueRepository(string connectionString)
|
||||||
|
{
|
||||||
|
this._connectionString = connectionString;
|
||||||
|
this._tableName = "contactCreationQueue";
|
||||||
|
var client = this.InitializeClient();
|
||||||
|
this._bookCollection = client.GetDatabase(this._databaseName).GetCollection<ContactCreationQueue>(this._tableName);
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Metods
|
||||||
|
public Tuple<bool, ContactCreationQueue> Exists(string id)
|
||||||
|
{
|
||||||
|
var allQueue = this.RetrieveAll();
|
||||||
|
var result = allQueue.FirstOrDefault(q => q.Id!.Equals(id));
|
||||||
|
|
||||||
|
if (result != null)
|
||||||
|
{
|
||||||
|
return new Tuple<bool, ContactCreationQueue>(true, result!);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return new Tuple<bool, ContactCreationQueue>(false, new ContactCreationQueue());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Create(ContactCreationQueue queue)
|
||||||
|
{
|
||||||
|
this._bookCollection.InsertOne(queue);
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<ContactCreationQueue> RetrieveAll()
|
||||||
|
{
|
||||||
|
return this._bookCollection.Find(_ => true).ToList();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Update(ContactCreationQueue queue)
|
||||||
|
{
|
||||||
|
var filter = Builders<ContactCreationQueue>.Filter.Eq(q => q.Id, queue.Id);
|
||||||
|
this._bookCollection.ReplaceOne(filter, queue);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Delete(ContactCreationQueue queue)
|
||||||
|
{
|
||||||
|
var filter = Builders<ContactCreationQueue>.Filter.Eq(q => q.Id, queue.Id);
|
||||||
|
this._bookCollection.DeleteOne(filter);
|
||||||
|
}
|
||||||
|
|
||||||
|
private MongoClient InitializeClient()
|
||||||
|
{
|
||||||
|
return new MongoClient(this._connectionString);
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public class ContactsRepository : BaseRepository
|
||||||
|
{
|
||||||
|
#region Fields
|
||||||
|
private readonly IMongoCollection<Contact> _bookCollection;
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
|
||||||
|
#region Constructors
|
||||||
|
public ContactsRepository(string connectionString)
|
||||||
|
{
|
||||||
|
this._connectionString = connectionString;
|
||||||
|
this._tableName = "contacts";
|
||||||
|
var client = this.InitializeClient();
|
||||||
|
this._bookCollection = client.GetDatabase(this._databaseName).GetCollection<Contact>(this._tableName);
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Metods
|
||||||
|
public Tuple<bool, Contact> Exists(string id)
|
||||||
|
{
|
||||||
|
var allContacts= this.RetrieveAll();
|
||||||
|
var result = allContacts.FirstOrDefault(c => c.Id!.Equals(id));
|
||||||
|
|
||||||
|
if (result != null)
|
||||||
|
{
|
||||||
|
return new Tuple<bool, Contact>(true, result!);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return new Tuple<bool, Contact>(false, new Contact());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Create(Contact contact)
|
||||||
|
{
|
||||||
|
this._bookCollection.InsertOne(contact);
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<Contact> RetrieveAll()
|
||||||
|
{
|
||||||
|
return this._bookCollection.Find(_ => true).ToList();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Update(Contact contact)
|
||||||
|
{
|
||||||
|
var filter = Builders<Contact>.Filter.Eq(c => c.Id, contact.Id);
|
||||||
|
this._bookCollection.ReplaceOne(filter, contact);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Delete(Contact contact)
|
||||||
|
{
|
||||||
|
var filter = Builders<Contact>.Filter.Eq(c => c.Id, contact.Id);
|
||||||
|
this._bookCollection.DeleteOne(filter);
|
||||||
|
}
|
||||||
|
|
||||||
|
private MongoClient InitializeClient()
|
||||||
|
{
|
||||||
|
return new MongoClient(this._connectionString);
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
@@ -0,0 +1,136 @@
|
|||||||
|
using MongoDB.Driver;
|
||||||
|
|
||||||
|
using TextSender_API.Models;
|
||||||
|
|
||||||
|
namespace TextSender_API.Repositories;
|
||||||
|
|
||||||
|
|
||||||
|
public class UsersRepository : BaseRepository
|
||||||
|
{
|
||||||
|
#region Fields
|
||||||
|
private readonly IMongoCollection<User> _bookCollection;
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
|
||||||
|
#region Constructors
|
||||||
|
public UsersRepository(string connectionString)
|
||||||
|
{
|
||||||
|
this._connectionString = connectionString;
|
||||||
|
this._tableName = "users";
|
||||||
|
var client = this.InitializeClient();
|
||||||
|
this._bookCollection = client.GetDatabase(this._databaseName).GetCollection<User>(this._tableName);
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Metods
|
||||||
|
public Tuple<bool, User> Exists(User user)
|
||||||
|
{
|
||||||
|
var allUsers = this.RetrieveAllUsers();
|
||||||
|
var result = allUsers.FirstOrDefault(ea => ea.Username!.Equals(user.Username));
|
||||||
|
|
||||||
|
if (result != null)
|
||||||
|
{
|
||||||
|
return new Tuple<bool, User>(true, result!);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return new Tuple<bool, User>(false, new User());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public Tuple<bool, User> Exists(string userId)
|
||||||
|
{
|
||||||
|
var allUsers = this.RetrieveAllUsers();
|
||||||
|
var result = allUsers.FirstOrDefault(ea => ea.Id!.Equals(userId));
|
||||||
|
|
||||||
|
if (result != null)
|
||||||
|
{
|
||||||
|
return new Tuple<bool, User>(true, result!);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return new Tuple<bool, User>(false, new User());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void CreateUser(User user)
|
||||||
|
{
|
||||||
|
this._bookCollection.InsertOne(user);
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<User> RetrieveAllUsers()
|
||||||
|
{
|
||||||
|
return this._bookCollection.Find(_ => true).ToList();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Update(User user)
|
||||||
|
{
|
||||||
|
var filter = Builders<User>.Filter.Eq(u => u.Id, user.Id);
|
||||||
|
this._bookCollection.ReplaceOne(filter, user);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Delete(User user)
|
||||||
|
{
|
||||||
|
var filter = Builders<User>.Filter.Eq(u => u.Id, user.Id);
|
||||||
|
this._bookCollection.DeleteOne(filter);
|
||||||
|
}
|
||||||
|
|
||||||
|
private MongoClient InitializeClient()
|
||||||
|
{
|
||||||
|
return new MongoClient(this._connectionString);
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public class SaltRepository : BaseRepository
|
||||||
|
{
|
||||||
|
#region Fields
|
||||||
|
private readonly IMongoCollection<Salt> _bookCollection;
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
|
||||||
|
#region Constructors
|
||||||
|
public SaltRepository(string connectionString)
|
||||||
|
{
|
||||||
|
this._connectionString = connectionString;
|
||||||
|
this._tableName = "salt";
|
||||||
|
var client = this.InitializeClient();
|
||||||
|
this._bookCollection = client.GetDatabase(this._databaseName).GetCollection<Salt>(this._tableName);
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Metods
|
||||||
|
public void Create(Salt salt)
|
||||||
|
{
|
||||||
|
this._bookCollection.InsertOne(salt);
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<Salt> RetrieveAll()
|
||||||
|
{
|
||||||
|
return this._bookCollection.Find(_ => true).ToList();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Salt Retrieve(string userId)
|
||||||
|
{
|
||||||
|
return this._bookCollection.Find(s => s.UserId!.Equals(userId)).FirstOrDefault();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Update(Salt salt)
|
||||||
|
{
|
||||||
|
var filter = Builders<Salt>.Filter.Eq(u => u.Id, salt.Id);
|
||||||
|
this._bookCollection.ReplaceOne(filter, salt);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Delete(Salt salt)
|
||||||
|
{
|
||||||
|
var filter = Builders<Salt>.Filter.Eq(u => u.Id, salt.Id);
|
||||||
|
this._bookCollection.DeleteOne(filter);
|
||||||
|
}
|
||||||
|
|
||||||
|
private MongoClient InitializeClient()
|
||||||
|
{
|
||||||
|
return new MongoClient(this._connectionString);
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk.Web">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<TargetFramework>net7.0</TargetFramework>
|
||||||
|
<Nullable>enable</Nullable>
|
||||||
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
|
<RootNamespace>TextSender_API</RootNamespace>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="7.0.11" />
|
||||||
|
<PackageReference Include="Microsoft.AspNetCore.Mvc.NewtonsoftJson" Version="7.0.11" />
|
||||||
|
<PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="7.0.11" />
|
||||||
|
<PackageReference Include="MongoDB.Driver" Version="2.21.0" />
|
||||||
|
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
|
||||||
|
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.5.0" />
|
||||||
|
<PackageReference Include="System.IdentityModel.Tokens.Jwt" Version="7.0.2" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
</Project>
|
||||||
@@ -1,74 +0,0 @@
|
|||||||
require('./models.js')
|
|
||||||
|
|
||||||
const express = require('express')
|
|
||||||
const app = express()
|
|
||||||
const port = 3000
|
|
||||||
|
|
||||||
app.use(express.json())
|
|
||||||
|
|
||||||
// User Routes
|
|
||||||
app.post('/api/v1/user/new', (req, res) => {
|
|
||||||
res.send('Posting')
|
|
||||||
console.log(req.body)
|
|
||||||
|
|
||||||
// const usr = new User()
|
|
||||||
|
|
||||||
let username = req.body['username']
|
|
||||||
|
|
||||||
// usr.username = username
|
|
||||||
|
|
||||||
console.log(`Username: ${username}`)
|
|
||||||
})
|
|
||||||
|
|
||||||
// User routes
|
|
||||||
// TODO: Not implemented
|
|
||||||
app.post('/api/v1/login', (req, res) => {
|
|
||||||
res.send('Implement');
|
|
||||||
})
|
|
||||||
|
|
||||||
// Text Routes
|
|
||||||
// Add a new text
|
|
||||||
// TODO: Not implemented
|
|
||||||
app.post('/api/v1/text/new', (req, res) => {
|
|
||||||
res.send('Create new text')
|
|
||||||
})
|
|
||||||
|
|
||||||
// Retrieve texts
|
|
||||||
// TODO: Not implemented
|
|
||||||
app.get('/api/v1/text', (req, res) => {
|
|
||||||
res.send('Create new text')
|
|
||||||
})
|
|
||||||
|
|
||||||
// Queue a text for sending
|
|
||||||
// TODO: Not implemented
|
|
||||||
app.post('/api/v1/text/queue', (req, res) => {
|
|
||||||
res.send('Queue text')
|
|
||||||
})
|
|
||||||
|
|
||||||
// Create contact
|
|
||||||
// TODO: Not implemented
|
|
||||||
app.post('/api/v1/contacts/new', (req, res) => {
|
|
||||||
res.send('Creating contact')
|
|
||||||
})
|
|
||||||
|
|
||||||
// Retrieving contacts
|
|
||||||
// TODO: Not implemented
|
|
||||||
app.get('/api/v1/contacts', (req, res) => {
|
|
||||||
res.send('Retrieving contact')
|
|
||||||
})
|
|
||||||
|
|
||||||
// Editing a contact
|
|
||||||
// TODO: Not implemented
|
|
||||||
app.patch('/api/v1/contacts', (req, res) => {
|
|
||||||
res.send('Editing contact')
|
|
||||||
})
|
|
||||||
|
|
||||||
// Deleting a contact
|
|
||||||
// TODO: Not implemented
|
|
||||||
app.delete('/api/v1/contacts', (req, res) => {
|
|
||||||
res.send('Delete contact')
|
|
||||||
})
|
|
||||||
|
|
||||||
app.listen(port, () => {
|
|
||||||
console.log(`textsender-api listening on port ${port}`)
|
|
||||||
})
|
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
{
|
||||||
|
"Logging": {
|
||||||
|
"LogLevel": {
|
||||||
|
"Default": "Information",
|
||||||
|
"Microsoft.AspNetCore": "Warning"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"JWT": {
|
||||||
|
"Audience": "",
|
||||||
|
"Issuer": "",
|
||||||
|
"Secret": "",
|
||||||
|
"Subject": ""
|
||||||
|
},
|
||||||
|
"Paths": {
|
||||||
|
"ContactQueueDirectory": "/home/user/path/"
|
||||||
|
},
|
||||||
|
"ConnectionStrings": {
|
||||||
|
"MongoDBURI": "mongodb+srv://<username>:<password>@cluster0.abc.mongodb.net/?retryWrites=true&w=majority"
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
{
|
||||||
|
"Logging": {
|
||||||
|
"LogLevel": {
|
||||||
|
"Default": "Information",
|
||||||
|
"Microsoft.AspNetCore": "Warning"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"AllowedHosts": "*",
|
||||||
|
"JWT": {
|
||||||
|
"Audience": "",
|
||||||
|
"Issuer": "",
|
||||||
|
"Secret": "",
|
||||||
|
"Subject": ""
|
||||||
|
},
|
||||||
|
"Paths": {
|
||||||
|
"ContactQueueDirectory": "/home/user/path/"
|
||||||
|
},
|
||||||
|
"ConnectionStrings": {
|
||||||
|
"MongoDBURI": "mongodb+srv://<username>:<password>@cluster0.abc.mongodb.net/?retryWrites=true&w=majority"
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,14 +0,0 @@
|
|||||||
const mongoose = require('mongoose');
|
|
||||||
|
|
||||||
const Schema = mongoose.Schema;
|
|
||||||
const ObjectId = Schema.ObjectId;
|
|
||||||
|
|
||||||
const User = new Schema({
|
|
||||||
userID: { type: String },
|
|
||||||
firstName: { type: String },
|
|
||||||
lastName: { type: String },
|
|
||||||
phoneNumber: { type: String },
|
|
||||||
username: { type: String },
|
|
||||||
password: { type: String },
|
|
||||||
dateCreated: { type: Date, default: Date.now }
|
|
||||||
});
|
|
||||||
@@ -1,16 +0,0 @@
|
|||||||
{
|
|
||||||
"name": "textsender-api",
|
|
||||||
"version": "0.1.0",
|
|
||||||
"description": "Web API for queueing text message notifications",
|
|
||||||
"main": "index.js",
|
|
||||||
"scripts": {
|
|
||||||
"test": "echo \"Error: no test specified\" && exit 1"
|
|
||||||
},
|
|
||||||
"author": "kdeng00",
|
|
||||||
"license": "ISC",
|
|
||||||
"dependencies": {
|
|
||||||
"express": "^4.18.2",
|
|
||||||
"mongodb": "^5.3.0",
|
|
||||||
"mongoose": "^7.0.5"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
|
||||||
|
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||||
|
# Visual Studio Version 17
|
||||||
|
VisualStudioVersion = 17.5.002.0
|
||||||
|
MinimumVisualStudioVersion = 10.0.40219.1
|
||||||
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TextSender-API", "TextSender-API.csproj", "{AD184BBA-C715-4112-95A9-530F05323BEE}"
|
||||||
|
EndProject
|
||||||
|
Global
|
||||||
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
|
Debug|Any CPU = Debug|Any CPU
|
||||||
|
Release|Any CPU = Release|Any CPU
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||||
|
{AD184BBA-C715-4112-95A9-530F05323BEE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{AD184BBA-C715-4112-95A9-530F05323BEE}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{AD184BBA-C715-4112-95A9-530F05323BEE}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{AD184BBA-C715-4112-95A9-530F05323BEE}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(SolutionProperties) = preSolution
|
||||||
|
HideSolutionNode = FALSE
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||||
|
SolutionGuid = {70126048-DECC-43EE-9956-2CEF937B7AA1}
|
||||||
|
EndGlobalSection
|
||||||
|
EndGlobal
|
||||||
Reference in New Issue
Block a user