<commit_before>﻿@{
    var response = "";
    var gw = LcPayment.NewBraintreeGateway();

    if (!IsPost) {
        var challenge = Request["bt_challenge"];
        if (!String.IsNullOrWhiteSpace(challenge)) {
            response = gw.WebhookNotification.Verify(Request["bt_challenge"]);
        }
    } else {
        var signature = Request["bt_signature"];
        var payload = Request["bt_payload"];
        var notification = gw.WebhookNotification.Parse(signature, payload);

        // Detecting the channel (from the ID) and the domain on wich this page is executing
        // to stop processing on the case they don't match.
        // Since we have 4 channels and only 2 at Braintree -sandbox and production-, Braintree production
        // is linked for several of our channels: testing, staging and live; then any of them will
        // receive notifications but not all notifications are for them, this filtering just avoid treat
        // 'other channel' notifications.
        if (notification.MerchantAccount.Id.Contains("_dev_") && !Request.Url.Authority.Contains("dev."))
        {
            Response.End();
        }
        else if (notification.MerchantAccount.Id.Contains("_testing_") && !Request.Url.Authority.Contains("testing."))
        {
            Response.End();
        }
        else if (notification.MerchantAccount.Id.Contains("_staging_") && !Request.Url.Authority.Contains("staging."))
        {
            Response.End();
        }
        // ELSE any other case (localdev, live) is left 'as is' not requiring filtering, just localdev will never 
        // receive a webhook and live is the default one.
        // There is no chance to fall here if is not a *live* notification and this is not the main domain.

        // Doing the action that fits better:
        //

        // Marketplace Merchant Accounts
        if (notification.Kind == Braintree.WebhookKind.SUB_MERCHANT_ACCOUNT_APPROVED ||
            notification.Kind == Braintree.WebhookKind.SUB_MERCHANT_ACCOUNT_DECLINED) {
            LcPayment.RegisterProviderPaymentAccountCreationNotification(notification, signature, payload);
        }
        if (notification.Kind == Braintree.WebhookKind.SUB_MERCHANT_ACCOUNT_DECLINED) {
            var providerID = LcUtils.ExtractInt(notification.MerchantAccount.Id, 0);
            LcMessaging.SendMerchantAccountNotification(providerID);
        }

        // Payment Plan Subscription updates
        var planNotifications = new List<Braintree.WebhookKind>
        {
            Braintree.WebhookKind.SUBSCRIPTION_CANCELED,
            Braintree.WebhookKind.SUBSCRIPTION_EXPIRED,
            Braintree.WebhookKind.SUBSCRIPTION_WENT_ACTIVE,
            Braintree.WebhookKind.SUBSCRIPTION_WENT_PAST_DUE
            // Trial ended notification is not relevant (status is active before and after
            // and payment data the same; the actual relevant changes when that happens is
            // the payment charge, detected with the '_CHARGED_' notifications)
            //Braintree.WebhookKind.SUBSCRIPTION_TRIAL_ENDED
        };
        if (planNotifications.Contains(notification.Kind))
        {
            var userPlan = LcRest.UserPaymentPlan.GetBySubscriptionID(notification.Subscription.Id);
            if (userPlan == null)
            {
                throw new Exception("UserPaymentPlan subscription not found (" + notification.Subscription.Id + ")");
            }
            else
            {
                userPlan.UpdatedAtGateway(notification.Subscription, notification.Kind);
                LcRest.UserPaymentPlan.Set(userPlan);
            }
        }
        else if (notification.Kind == Braintree.WebhookKind.SUBSCRIPTION_CHARGED_SUCCESSFULLY)
        {
            
        }
        else if (notification.Kind == Braintree.WebhookKind.SUBSCRIPTION_CHARGED_UNSUCCESSFULLY)
        {

        }

        // Other...
    }
}
@response<commit_msg>Added payment webhook notifications to update of subscriptions since can denote status and data changes that other ones don't offer #191<commit_after>﻿@{
    var response = "";
    var gw = LcPayment.NewBraintreeGateway();

    if (!IsPost) {
        var challenge = Request["bt_challenge"];
        if (!String.IsNullOrWhiteSpace(challenge)) {
            response = gw.WebhookNotification.Verify(Request["bt_challenge"]);
        }
    } else {
        var signature = Request["bt_signature"];
        var payload = Request["bt_payload"];
        var notification = gw.WebhookNotification.Parse(signature, payload);

        // Detecting the channel (from the ID) and the domain on wich this page is executing
        // to stop processing on the case they don't match.
        // Since we have 4 channels and only 2 at Braintree -sandbox and production-, Braintree production
        // is linked for several of our channels: testing, staging and live; then any of them will
        // receive notifications but not all notifications are for them, this filtering just avoid treat
        // 'other channel' notifications.
        if (notification.MerchantAccount.Id.Contains("_dev_") && !Request.Url.Authority.Contains("dev."))
        {
            Response.End();
        }
        else if (notification.MerchantAccount.Id.Contains("_testing_") && !Request.Url.Authority.Contains("testing."))
        {
            Response.End();
        }
        else if (notification.MerchantAccount.Id.Contains("_staging_") && !Request.Url.Authority.Contains("staging."))
        {
            Response.End();
        }
        // ELSE any other case (localdev, live) is left 'as is' not requiring filtering, just localdev will never 
        // receive a webhook and live is the default one.
        // There is no chance to fall here if is not a *live* notification and this is not the main domain.

        // Doing the action that fits better:
        //

        // Marketplace Merchant Accounts
        if (notification.Kind == Braintree.WebhookKind.SUB_MERCHANT_ACCOUNT_APPROVED ||
            notification.Kind == Braintree.WebhookKind.SUB_MERCHANT_ACCOUNT_DECLINED) {
            LcPayment.RegisterProviderPaymentAccountCreationNotification(notification, signature, payload);
        }
        if (notification.Kind == Braintree.WebhookKind.SUB_MERCHANT_ACCOUNT_DECLINED) {
            var providerID = LcUtils.ExtractInt(notification.MerchantAccount.Id, 0);
            LcMessaging.SendMerchantAccountNotification(providerID);
        }

        // Payment Plan Subscription updates
        var planNotifications = new List<Braintree.WebhookKind>
        {
            // Status Changes
            Braintree.WebhookKind.SUBSCRIPTION_CANCELED,
            Braintree.WebhookKind.SUBSCRIPTION_EXPIRED,
            Braintree.WebhookKind.SUBSCRIPTION_WENT_ACTIVE,
            Braintree.WebhookKind.SUBSCRIPTION_WENT_PAST_DUE,
            // Payment Changes: it can change the status (past_due on unsuccessfully,
            // active on successfully if comes from past_due)
            // and subscription data (NextBilling info).
            Braintree.WebhookKind.SUBSCRIPTION_CHARGED_SUCCESSFULLY,
            Braintree.WebhookKind.SUBSCRIPTION_CHARGED_UNSUCCESSFULLY
            // Trial ended notification is not relevant (status is active before and after
            // and payment data the same; the actual relevant changes when that happens is
            // the payment charge, detected with the '_CHARGED_' notifications)
            //Braintree.WebhookKind.SUBSCRIPTION_TRIAL_ENDED
        };
        if (planNotifications.Contains(notification.Kind))
        {
            var userPlan = LcRest.UserPaymentPlan.GetBySubscriptionID(notification.Subscription.Id);
            if (userPlan == null)
            {
                throw new Exception("UserPaymentPlan subscription not found (" + notification.Subscription.Id + ")");
            }
            else
            {
                userPlan.UpdatedAtGateway(notification.Subscription, notification.Kind);
                LcRest.UserPaymentPlan.Set(userPlan);
            }
        }

        // Other...
    }
}
@response
{'fraction_non_alphanumeric': 0.08552793502338174, 'fraction_numerical': 0.0011075559931085406, 'mean_word_length': 2.3890742285237696, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 5, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '407313', 'n_tokens_mistral': 2145, 'n_tokens_neox': 2079, 'n_words': 553}