Developer Center

Saber.Vendor

If you are developing a plugin for Saber, please take the time to read and understand all of the documentation on this page. Saber.Vendor is a namespace within the Saber.Core NuGet package that allows developers to take advantage of various features within the Saber platform, including Controllers & REST Services, HTML Components, Security Keys, Data Sources, Website Settings, and Email Clients.


IVendorStartup

Interface used to execute vendor-specific code when the Saber application starts up. The two methods ConfigureServices and Configure are identical to the same two methods found in any ASP.NET Core web application project Startup.cs class.

public class Startup : IVendorStartup
{
public void ConfigureServices(IServiceCollection services)
{
//do stuff
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env, IConfigurationRoot config)
{
//do stuff
}
}

Saber's CORS plugin is a good example of how to use the IVendorStartup interface.


IVendorViewRenderer

Interface used to execute vendor-specific code when Saber renders a View. Attribute [ViewPath("/Views/Path/To/myfile.html")] is required on the class that inherits IVendorViewRenderer, which will determine when the Render method is being called to load the associated html file. Use this interface to add HTML to a View that contains the {{vendor}} element.

[ViewPath("/Views/AppSettings/appsettings.html")]
public class MyPlugin : IVendorViewRenderer
{
public void Render(Core.IRequest request, View view)
{
var myview = new View("/Vendor/MyPlugin/settings.html");
view["vendor"] += myview.Render();
}
}

In the example above, we append the rendered HTML of our settings.html view to the vendor element whenever Saber renders the /Views/AppSettings/appsettings.html View.

NOTE: It is important that you append the rendered HTML to the contents of the view["vendor"] object instead of replacing the contents because other vendors might have appended content to the same element beforehand. Saber supports the IVendorViewRenderer for all views within the application, and the following views include a {{vendor}} HTML variable so that vendors can extend the Editor UI.

Saber's Import Export plugin is a good example of how to use the IVendorViewRenderer interface.


IVendorController

Interface used to route page requests to vendor-specific controllers. Your class must inherit Controller as well as IVendorController in order to work properly.

NOTE: Make sure your controller names do not conflict with potential web pages that users will want to create for their website, such as: About, Contact, Blog, Wiki, Projects, Products, Team, Terms, PrivacyPolicy, Members, Landing, Store, Company, History, etc.

public class RSSReader : Controller, IVendorController
{
public override string Render(string body = "")
{
if (!CheckSecurity("view-rss")) { return AccessDenied(); }
var view = new View("/Vendors/RSS/reader.html");
view["feeds"] = RSS.RenderFeeds();
return view.Render();
}
}

The example above creates a controller that can be accessed by navigating to /rssreader within a Saber website from the web browser.

Saber's Import Export plugin is a good example of how to use the IVendorController interface.


IVendorService

Interface used to route web APIs to vendor-specific services. Your class must inherit Service as well as IVendorService in order to work properly.

public class ShoppingCart : Service, IVendorService
{
public string AddToCart(int productId)
{
if (!CheckSecurity("cart")) { return AccessDenied(); }
Query.ShoppingCart.Add(productId);
return Success();
}
}

The example above creates a service that can be accessed by executing the following JavaScript function.

S.ajax.post('ShoppingCart/AddToCart', {productId: myid}, (response) => { }, (err) => { });

Saber's Stress Test plugin is a good example of how to use the IVendorService interface.


IVendorKeys

Interface used to define a list of security keys that can be assigned to users in order to gain access to restricted features.

public class SecurityKeys : IVendorKeys
{
public string Vendor { get; set; } = "RSS Feed Reader";
public SecurityKey[] Keys { get; set; } = new SecurityKey[]
{
new SecurityKey(){Value = "manage-rss", Label = "Manage RSS Feeds", Description = "Add & Remove RSS feeds to read"},
new SecurityKey(){Value = "view-rss", Label = "View RSS Feeds", Description = "Read articles from your feed reader"}
};
}

After defining your security keys, you should use them within your IVendorController interface by using the following code:

if (!CheckSecurity("manage-rss")) { return AccessDenied(); }

NOTE: The website administrator (UserId:1) will automatically have access to all security keys, and all other users will have to be given permission to have access to specific security keys.

Saber's Import Export plugin is a good example of how to use the IVendorKeys interface.


IVendorHtmlComponents

An interface used to define a list of HTML components. When the user includes mustache variables within their .html files, Saber will try to match their mustache variables (e.g. {{page-list path:"store/products"}}) with your HTML component Key. If a match is found, Saber will execute the Render function and replace the mustache variable with rendered HTML provided by your plugin.

Check out the Page List plugin which utilizes the IVendorHtmlComponents interface to read mustache variables such as {{page-list path:"blog", length:"4"}} to render a list of pages that exist in the user's website.

public class HtmlComponents: IVendorHtmlComponents
{
public List<HtmlComponentModel> Bind()
{
return new List<HtmlComponentModel>{
new HtmlComponentModel() {
Key = "page-list",
Name = "Page List",
Description = "Display a list of webpages that belong to your website.",
Parameters = new Dictionary<string, HtmlComponentParameter>()
{
{
"path",
new HtmlComponentParameter()
{
Required = true,
DefaultValue = "",
Description = ""
}
},
{
"length",
new HtmlComponentParameter()
{
DefaultValue = "4",
Description = "Total webpages to display within the list."
}
}
},
Render = new Func<View, IRequest, Dictionary<string, string>, string, string, string, List<KeyValuePair<string, string>>>((view, request, args, data, prefix, key) =>
{
var results = new List<KeyValuePair<string, string>>();
var container = new View("/Vendors/PageList/container.html");
var item = new View("/Vendors/PageList/item.html");
int.TryParse(args["length"], out var length);
var path = args["path"];
var files = Directory.GetFiles(App.MapPath("/Content/pages/" + path), "*.html", SearchOption.AllDirectories);
var html = new StringBuilder();
var i = 0;
foreach (var file in files)
{
i++;
if(i < length){break;}
var config = PageInfo.GetPageConfig(file);
item.Clear();
item["title"] = config.title.body;
item["date-created"] = config.datecreated.ToShortDateString();
item["thumb"] = config.thumbnail;
item["description"] = config.description;
html.Append(item.Render());
}
results.Add(new KeyValuePair<string, string>(prefix + key, container.Render()));
return results;
})
}
};
}
}

The Bind method allows you to specify a list of HtmlComponentModel objects which defines each custom mustache variable that you wish to add to Saber.

The Key field is used to specify the mustache variable name to use in HTML (e.g. {{page-list}})

The Name field represents the human-readable version of the mustache variable name, which is displayed in tool tips, intellisense, and documentation for your mustache variable.

The Description field represents a short summary of what your mustache variable is used for, which is displayed in tool tips, intellisense, and documentation for your mustache variable.

The Parameters field is a dictionary of HtmlComponentParameter objects that represent a list of properties a user can include within the mustache variable. For example, {{page-list path:"blog", length:"4"}} includes the properties path and length.

The Render field represents a callback function that is executed to retrieve the raw, rendered HTML of your mustache variable whenever Saber needs to render a web page that includes one or more instances of your mustache variable in the page's HTML view and partial views. The callback function includes the following arguments:

The Render method for HtmlComponentModel returns a List<KeyValuePair<string, string>>>, which is a list of key/value pairs, where each key represents the unique mustache variable name (along with the prefix) to apply the rendered HTML to, and each value represents the raw, rendered HTML used to replace the unique mustache variable with. Because the return value is a list of key/value pairs, you are able to replace multiple mustache variables with raw HTML within the View if desired.

Saber's Page List plugin is a good example of how to use the IVendorHtmlComponents interface.


IVendorContentField

An interface used to render content fields within Saber's Page Content tab. If you are developing a custom mustache variable using IVendorHtmlComponents, then you can utilize the IVendorContentField interface to provide a custom content field to manage the user's content related to your custom mustache variable. For example, a photo gallery (e.g. {{photo-gallery length:"10"}}) would need a custom content field that allowed the user to manage (upload, sort, & remove) photos for their gallery.

[ContentField("photo-gallery")]
public class PhotoGalleryField: IVendorContentField
{
public string Render(Dictionary<string, string> parameters, string data, string id, IRequest request)
{
//do stuff...
}
}

The Render method is used to render the HTML of a content field within Saber's Page Content tab.

The parameters argument is a dictionary of key/value pairs associated with the particluar instance of a mustache variable on the user's HTML page. For example, {{page-list path:"blog"}} would produce one parameter with the key path and the value blog.

The data argument is a serialized object that represents the saved user data of your content field for a particular instance of a mustache variable on the user's HTML page.

The id argument represents the id of a hidden HTML input field located within Saber's Page Content tab that is used to store the saved user data on the client-side. The value of the hidden HTML input field is then used to save the user's data to a multilingual JSON file on the server-side. Make sure to update the value of the hidden HTML input field with your desired user data (using JavaScript) so that Saber can save your content field's user data correctly.

For example, use the JavaScript function below to save your user data:

[ContentField("photo-gallery")]
public class PhotoGalleryField: IVendorContentField
{
public string Render(Dictionary<string, string> parameters, string data, string id, IRequest request)
{
var rnd = new System.Random().Next();
var view = new View("/Vendors/PhotoGallery/content-field.html");
view["id"] = rnd;
view["script"] = "$('.field-button-" + rnd + ").on('click', () => {$('#" + id + "').val(myval['field-" + rnd + "']);});
return view.Render();
}
}

The example above creates a rnd variable to use when defining HTML element class names & ids within the view since Saber might render mutliple content fields if the user creates mutliple instances of your mustache variable in their web page's HTML. The view["script"] object renders some JavaScript (that uses jQuery), which creates an event listener for a button click that updates the hidden HTML input field $('#" + id + "') value with the supplied user data myval['field-" + id + "'].

The request argument represents the IRequest instance for the current page request.

Saber's Photo Gallery plugin is a good example of how to use the IVendorContentField interface.


IVendorDataSources

Saber comes with a List component that users can add to their HTML web pages to display arrays of HTML content populated with information provided by a Data Source. Vendor plugins are able to define data sources which contain rows of information, where each row is comprised of a Dictionary<string, string> and is used to render each item in the list component using one or more Partial Views.

Note that each Dictionary<string, string> should contain the same keys in order to serve consistant data to the List component.


IVendorWebsiteSettings

An interface used to add an accordion to Saber's website settings tab. The accordion is used to display website-related settings for your plugin.

public class WebsiteSettings : IVendorWebsiteSettings
{
public string Name { get; set; } = "Import/Export Website";
public string Render(IRequest request)
{
var html = new StringBuilder();
var access = false;
if (request.CheckSecurity("import")) {
html.Append(Cache.LoadFile(App.MapPath("/Vendors/ImportExport/import.html")));
access = true;
}
if (request.CheckSecurity("export"))
{
html.Append(Cache.LoadFile(App.MapPath("/Vendors/ImportExport/export.html")));
access = true;
}
if (access)
{
request.AddScript("/editor/vendors/importexport/importexport.js");
}
return html.ToString();
}
}

Saber's Import Export plugin is a good example of how to use the IVendorWebsiteSettings interface.


IVendorEmailClient

An interface used to define an email client and its parameters in order to connect to a remote email service and send emails to website users. Saber comes with an SMTP email client by default, so this interface would be used to connect to other services such as SendGrid or MailChimp.

public class MyEmailClient : IVendorEmailClient
{
public string Id { get; set; } = "my-client";
public string Name { get; set; } = "My Client";
public Dictionary<string, EmailClientParameter> Parameters { get; set; } = new Dictionary<string, EmailClientParameter>()
{
{"service",
new EmailClientParameter()
{
DataType = EmailClientDataType.List,
Name = "Service",
Description = "",
ListOptions = new string[]
{
"Gmail", "Hotmail", "Yahoo", "ProtonMail"
}
}
},
{"use-ssl",
new EmailClientParameter()
{
DataType = EmailClientDataType.Boolean,
Name = "Use SSL",
Description = ""
}
},
{"username",
new EmailClientParameter()
{
DataType = EmailClientDataType.UserOrEmail,
Name = "Username",
Description = ""
}
},
{"password",
new EmailClientParameter()
{
DataType = EmailClientDataType.Password,
Name = "Password",
Description = ""
}
},
};
public Dictionary<string, string> GetConfig()
{
//get parameters from JSON config file
}
public void Init()
{
//initialize email client when Saber starts
}
public void SaveConfig(Dictionary<string, string> parameters)
{
//save parameters to JSON config file
}
public void Send(MailMessage message, Func<string> GetRFC2822)
{
//connect to service and send email
}
}

IVendorEmails

An interface used to define a list of email actions. Email actions can be customized within Saber's website settings tab by selecting which email client to use when sending an email for a specific action (such as the signup or forgotpass actions), and if allowed, you can also supply a user-defined subject line for the email. This interface should be used if your plugin needs the ability to send emails to users.

public class MyEmails : IVendorEmails
{
public EmailType[] Types { get; set; } = new EmailType[]
{
new EmailType()
{
Key = "checkout",
Name = "Check Out",
Description = "An email sent after a user orders one or more products",
TemplateFile = "checkout.html",
UserDefinedSubject = true
},
new EmailType()
{
Key = "subscribe",
Name = "Subscribe",
Description = "An email sent after a user subscribes to one or more services",
TemplateFile = "subscribe.html",
UserDefinedSubject = true
}
};
}

After setting up your email actions using IVendorEmails, use the following methods to send an email to your users.

var message = Core.Email.Create(new MailAddress(user.email, user.name), subject, body);
Core.Email.Send(message, "checkout");

When sending emails through Saber, you cannot define the From address since that field should be defined as a parameter within the IVendorEmailClient interface. The website administrator would then configure their email client with their desired From address.