// GET: sessions/teacher public ActionResult Teacher() { if (!this.GetUserIsTeacher()) { return(Redirect(Url.Action("Logout", "Account", null, "https"))); } HostingEnvironment.QueueBackgroundWorkItem(ct => ItalkiHelper.EnsureIsReady()); return(View()); }
public async Task <IHttpActionResult> PostBooking([FromBody] JObject json) { TimeUtils.ThrowIfClientTimeIsAmbiguous((string)json["localTime"], (int)json["localTimezoneOffset"]); var teacherUserId = (int)json["teacherUserId"]; var start = (DateTime)json["start"]; var end = (DateTime)json["end"]; var price = (decimal)json["price"]; var userId = this.GetUserId(); var teacher = SessionHelper.ItalkiTeachers.First(i => i.UserId == teacherUserId); var periods = await SessionHelper.GetTeacherPeriods(teacherUserId, true); var available = periods.Any(i => (i.Start <= start) && (i.End >= end)); if (!available) { throw new Exception(ItalkiHelper.TimeSlotUnavailableError); } /* Compensation is the mechanism by which previously completed work can be undone or compensated when a subsequent failure occurs. * The Compensation pattern is required in error situations when multiple atomic operations cannot be linked with classic transactions. */ // We cannot use a transaction in a heterogeneous storage mediums. An orphaned message on Azure Table is not a problem, we do not compensate it on error. The main message metadata is in the database anyway. var message = (string)json["message"]; var messageExtId = await SessionHelper.SaveMessageAndGetExtId(message); var sessionId = (await DapperHelper.QueryResilientlyAsync <int>("dbo.sesBookSession", new { UserId = userId, // who requests and pays Start = start, End = end, TeacherUserId = teacherUserId, Price = price, MessageExtId = messageExtId, }, CommandType.StoredProcedure)) .Single(); // We will write to the log. var partitionKey = KeyUtils.GetCurrentTimeKey(); // Book the session on Italki. try { long?sessionExtId = null; #if DEBUG sessionExtId = 0; #else var helper = new ItalkiHelper(); sessionExtId = await helper.BookSession(teacher.CourseId, start, teacher.ScheduleUrl, partitionKey); #endif if (sessionExtId.HasValue) { await DapperHelper.ExecuteResilientlyAsync("dbo.sesUpdateSessionExtId", new { SessionId = sessionId, ExtId = sessionExtId, }, CommandType.StoredProcedure); } } catch (Exception ex) { // Compensation on booking failure. // Clean up the session. DapperHelper.ExecuteResiliently("dbo.sesCancelSession", new { UserId = userId, SessionId = sessionId, ClearUsers = true, }, CommandType.StoredProcedure); throw new UserAlertException("Failed to book session", ex); } HostingEnvironment.QueueBackgroundWorkItem(async(ct) => await SendSmsMessage("Session request. Teacher " + teacherUserId.ToString(), partitionKey)); return(StatusCode(HttpStatusCode.NoContent)); }
// GET: sessions/ public ActionResult Index() { HostingEnvironment.QueueBackgroundWorkItem(ct => ItalkiHelper.EnsureIsReady()); return(View()); }