Пример #1
0
 // GET: sessions/teacher
 public ActionResult Teacher()
 {
     if (!this.GetUserIsTeacher())
     {
         return(Redirect(Url.Action("Logout", "Account", null, "https")));
     }
     HostingEnvironment.QueueBackgroundWorkItem(ct => ItalkiHelper.EnsureIsReady());
     return(View());
 }
Пример #2
0
        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));
        }
Пример #3
0
 // GET: sessions/
 public ActionResult Index()
 {
     HostingEnvironment.QueueBackgroundWorkItem(ct => ItalkiHelper.EnsureIsReady());
     return(View());
 }