-
Notifications
You must be signed in to change notification settings - Fork 9
Built in Controllers
There are two types of controllers in Exico Shopify Framework.
- Abstract Base Controllers.
- And the other type are the ones that ship with the ExicoShopifyApp template and already extend the base controllers; called default controllers.
Lets look at these two types of controllers in depth in this guide. It will help you understand the purpose of those controllers and give you an insight on when to use them and how to extend them if needed.
- ABaseController (source)
- ABaseAppUninstallController (source)
- ABaseShopifyController (source)
- ABaseHomeController (source)
- ABaseAuthorizedController (source)
- ABaseSubscriberController (source )
- ABaseMyProfileController (source)
- ABaseAccountController (source )
- ABaseAppDashBoardController (source)
- ABaseMandatoryWebHooksController (source)
- ABaseAdminController (source)
This is the root abstract base controller. It inherits directly from the AspNet core Controller. This base controller is responsible for injecting default ViewBag items. Inherit from this class if your controller doesn't need any authentication.
This controller has some interesting methods that might be useful for you.
protected virtual void AddOverrideViewsData() {}
If you need to add new or overwrite any default items of the ViewBag (or ViewData) then override this method and do it there.
public virtual void MyOnResultExecuted(ResultExecutedContext contex) { }
If you need to override the good old OnResultExecuted() then instead of overriding that override this.
public virtual void MyOnResultExecuting(ResultExecutingContext contex) { }
Override this method if you need to override OnResultExecuting().
public virtual void MyOnActionExecuting(ActionExecutingContext context) { }
Override the above method instead of overriding OnActionExecuting().
public virtual void MyOnActionExecuted(ActionExecutedContext context) { }
Override this above method instead of overriding OnActionExecuted().
This abstract base controller directly inherits from the ABaseController. It has couple of interesting methods. First one is
public virtual async Task<IActionResult> AppUninstalled(string userId)
This method is called by Shopify when a user (store) uninstalls your app. This method takes care of removing user (store) from the database. It doesn't delete any other user data unless and until those data in separate tables are linked with the user table with user id foreign keys.
One important thing to remember is, shopify expects a 200 (OK) from our app's side no matter what. That's why this method uses try catch extensively and handles error/exception gracefully and makes sure that a 200 (OK) is being returned to the Shopify server/caller NO MATTER WHAT.
However during the un-installation process it calls few virtual methods to give you a chance for doing additional tasks during the removal of the user (store) account. These methods are:
public virtual async Task UnInstallCompleted(AppUser user)
This is the very last method that is called at the end of the uninstall process. If you need to do some post uninstall cleanup then override this method and do it there.
public virtual async Task UserIsDeleted(AppUser user)
During the uninstallation process at some point when the user account is deleted and then this method is called immediately after the deletion. Override this method if you need to do some post user deletion work.
public virtual async Task CouldNotDeleteUser(AppUser user, Exception ex)
During the uninstallation process the user account is deleted. But if there is any problem deleting the user account then this event is raised. Override this method if you need to track the exception and do something in such situations.
public virtual async Task<bool> SendUninstallEmail(AppUser user)
At the end of uninstallation process when everything is done then this method is called. Note that it is called before the UnInstallCompleted(AppUser user)
This is one of the most important and complex controller. It inherits directly from the ABaseController. This controller takes care of the following important things
-
Handles the hand shaking with Shopify; that is when a user/store tries to access your app this controller kicks in and checks if that user is a valid paid user or not and then redirects to either dashboard or to any other pages depending on the status of the accessing user/store. For example if the user didn't complete the installation then this controller takes the user/store to that particular step of installation.
-
Presents the user with a list of subscription plan(s) to choose from and handles the plan selection.
-
Also handles subscription plan changing.
-
Handles the recurring charge, saves access token etc billing related tasks.
-
Handles canceled/denied payment and does appropriate redirections.
-
Sends out email after successful installation
-
Processes all web hooks defined in the appsettings (See Settings for details)
-
Manages permissions listed in the appsettings (See Settings for details)
Like all other classes/controllers this class is also comprehensively documented. Please go to the source code of this controller, you should not have too much trouble to understand it (Although you do not need to understand everything to use the framework. But it your choice)
Now there are couple of methods in this controller that I would like to highlight. You might want to override them in some situations
[Authorize, NonAction]
public virtual async Task DoPostInstallationTasks(AppUser user) { }
The default implementation is empty. But this is a very handy method that you might want to override if you need to do some stuffs right after the user successfully installed your app.
[Authorize, NonAction]
public virtual IActionResult RedirectAfterNewUserCancelledPayment(AppUser user)
This above method by default redirects a new user/store (first time installer) to the store admin panel if the store owner (user) cancels the payment during the installation. Override this if you need to redirects the user to somewhere else.
[Authorize, NonAction]
public virtual IActionResult RedirectAfterPlanChangePaymentDeclined()
This methods does exactly what the name suggest. By default it finds out the name of your dashboard from settings (see the DASHBOARD_CONTROLLER setting here ) and redirects to the dashboard index action. Also it shows a message to inform the user about what happened.
[Authorize, NonAction]
public virtual async Task UserChangedPlan(AppUser user, int newPlanId)
This is called after a successful subscription plan change by the user (store). By default the system sends out email to the email subscribers (see the SHOPIFY_EVENT_EMAIL_SUBSCRIBERS setting here ) about this event. You can do whatever you want by overriding it.
[Authorize, NonAction]
public virtual IActionResult RedirectAfterSuccessfulUpgrade(string upgradedPlanName)
By default it finds out the name of your dashboard from settings (see the DASHBOARD_CONTROLLER setting here ) and redirects to the app dashboard index action upon successful subscription plan upgrade. Also it shows a message to inform the user about what happened.
[Authorize, NonAction]
public virtual IActionResult RedirectAfterSuccessfullLogin()
By default it finds out the name of your dashboard from settings (see the DASHBOARD_CONTROLLER setting here ) and redirects to the app dashboard index action upon successful log in.Override it if you need to redirect a logged in user somewhere else.
Notice that this login is not happening through the login panel by manually entering user name and password rather this is automatic and implicit login handled by the system. It happens when the store owner clicks on your app from their Shopify store admin panel.
[NonAction]
public virtual async Task SendEmailsOnSuccessfullInstallation(AppUser user)
Default implementation Sends out two kinds of emails; one to admin and the second one is the welcome email to the the user (store owner) who installed the app. Override this if you need to have control over sending emails.
Welcome message content is configurable in the database settings. setting name is WELCOME_EMAIL_TEMPLATE. Know more about the database settings here.
Now there are some more methods in that ABaseShopifyController that might be interesting to you and you might want to override those as well. But for that I would suggest to go over the source code.
This controller is used to provide a landing page mainly for unpaid and not yet logged in users (stores). You do not need to be authenticated to view the landing page (home/index).
This controller extends the ABaseController and provides two interesting methods
public virtual async Task<ActionResult> Index()
This above method generates the home page.
public virtual async Task<IActionResult> Error()
This method generates the ErrorViewModel and renders the error view (XError.cshtml) if theres an error within the system during runtime.
You can always override any of these above two action methods if needed. Usually you do not need to override the Error() action method. But occasionally you might want to override the Index() method. An example can be, that you want anyone who access the app go to the dashboard directly, if authorized, else show the login screen.So in that case you might want to override the Index() method and do the redirect to the Dashboard/Index from the home controller's index.
This abstract base class ensures that any controller that extends it is only available to Authorized user (store). This controller itself inherits from ABaseController.
Note that authorized doesn't necessarily refer to a valid paid/subscribed user. For example a user who is half way through the installation process is AUTHORIZED but not a (yet) SUBSCRIBED user. Because that user may (at the end of the installation) simply deny the billing/charge and move on.
SIDE NOTE: In that case we will have an entry in the database of a user who didn't complete the installation. If the same user/store tries to install the app next time then the system won't recreate the user account again , rather it will use the same account and even resume the installation where it was left.
This abstract base controller extends the ABaseAuthorizedController. Extending *ABaseSubscriberController ** ensures that no one can access your controller unless it is a subscribed user. That is if you need to create a custom controller that should be accessed only by valid paid users (stores) then inherit from this class and you are done.
Probably this is the controller base class that you will be mostly dealing with when using the Exico Shopify Framework.
This controller extends from ABaseAuthorizedController. Two most important things that it does are Logs in and Logs off a user (store). Beside these two functionalities it has couple of non action virtual methods that you might want to override depending on your need. They are
public virtual async Task LogOffHappened(AppUser user)
This is called when a user is logged off. So if you want to do something when user logs off then override this method and do it there.
public virtual async Task LogInHappened(AppUser user)
This is one called when a user (store) logs into the app. So override it if you need to do something right after user(store) login.
public virtual async Task LoginErrorHappened(LoginViewModel data)
This one gets called in case of error during log in process. So override it if you need to know the details or take some actions in such scenarios.
Note that LogInHappened and LoginErrorHappened are called only when the user is logging using the login box entering user name and password manually. And not when the user is logging in implicitly (automatically) by clicking on the app name from the store admin which is handled by the ABaseShopifyController.
This base abstract controller inherits from ABaseSubscriberController.This base controller has methods for rendering support page, sending support emails and showing the index page where user will land right after logging in to the app. The related action methods are
public virtual async Task<IActionResult> Index()
public virtual async Task<IActionResult> Support()
Typically you do not have to override any method here. Here is the default look of the Index() method.
And here is the default support page. For most people this support page is more than enough.
But in case you want to change the look and feel of any of the pages above, visit the Customizing Views wiki page.
There are also more two interesting action method in this controller that deserve a little bit attention.
public virtual async Task<IActionResult> ConsiderUpgradingPlan()
This is called and a default view is rendered in cases where system detects that the current plan is not enough for the for a particular request. You can always redirect to this method from anywhere if you would like to tell user (store) that he/she should consider upgrading the app subscription plan.
public virtual async Task<IActionResult> PlanDoesNotAllow()
This is kind of like the previous one. But sometimes you just do not suggest the user to upgrade the plan, but want to be a bit straight forward and tell him request got cancelled 9to do something) because your plan doesn't support it.
This controller extends ABaseSubscriberController that means no one can access this controller except paid valid subscribed (to a valid billing plan) users (stores). It has two interesting action methods
public virtual async Task<ActionResult> Index()
This Index() method generates the the profile data (store name, billing info etc) of a subscribed user. The default look and feel of it is like below (but you can always customize it.)
public virtual async Task<ActionResult> ChangePlan(bool proceed = false)
ChangePan takes a user to the plan choice list and let them upgrade to a higher plan.
If the user is admin or the user IP is marked as Privileged IP (see the database settings) then the the user is able to downgrade the plan as well.
(TO DO)
This controller extends the ABaseAuthorizedController. So only authorized users can access this controller plus on top of it this controller enforces that the user who is authorized must be an ADMIN type user as well.
This controller should only be used if you are building an administration page or something that a regular store user should not be able to to do but an admin user.
This controller use these two following attributes
[Authorize(Roles = UserInContextHelper.ADMIN_ROLE)]
[ServiceFilter(typeof(IPAddressVerification),Order = IPAddressVerification.DEFAULT_ORDER)]
First one makes sure the user role is admin.
Second one makes sure that the accessing users IP address is listed as privileged IP address in the database settings.
When you create a project using the the ExicoShopifyApp template you get the following default controllers already created for you in the project's controllers folder.
- AccountController
- DashboardController
- HomeController
- MandatoryWebHookController
- MyProfileController
- ShopifyController
- UninstallController
These controllers already extends the Base Controller. So that you do not have to remember and extend them when you first create a Shopify store app project using the Exico Shopify Framework.
If you know the internals of the Base Controller then you already know these above controller's purpose and what methods to override in what situations.
Note that the name of these default controllers are not random. These are dictated in the database settings. For example the name of the ShopifyController coming from the database setting called SHOPIFY_CONTROLLER. Same goes for the AccountContrller is here because of the default value of the database setting called ACCOUNT_CONTROLLER. If you look at the database settings you will find more settings like the ones that I mentioned.
It is recommended that you do not change these settings values until unless there is a strong reason.