Should controller take "id" as PathVariable or should it take "page-id" - oop

We are trying to create SEO friendly roads. In this context, we decided to make changes to the url.
E.g: /141(id) --> /example-page-141
I argue that we should get the "id" value as PathVariable on the back-end side. Another solution is to take "/example-page-141" as #PathVariable and find 141 in it. Which is the right solution?
Solution
#GetMapping("/get/{id}")
public ResponseEntity<?> getProductDetail(#PathVariable Long id)
Product product = productService.getProductDetail(id);
return new ResponseEntity<>(product, HttpStatus.OK);
}
Solution
#GetMapping("/get/{id}")
public ResponseEntity<?> getProductDetail(#PathVariable String id) {
String[] bits = id.split("-");
Long idLong = Long.valueOf(bits[bits.length-1]);
Product product = productService.getProductDetail(idLong);
return new ResponseEntity<>(product, HttpStatus.OK);
}
What are the pros and cons of splitting from the backend or frontend?

I would go with Option 1. Why? because it keeps the splitting logic in the frontend where it belongs. SEO is way more related to frontend than with backend, and as such, you should hide this complexity from the backend service.
One additional benefit is that if at some point in time the ID prefix changes, you can keep the changes in one place (frontend) and not in both frontend and backend which would require syncing the changes so that the backend service continued to be able to respond to the requests (of course you could have an alternative for this, but bottom line is that you would need to touch two codebases instead of a single one).

There is no black or white answer here as there is no real harm in using any of them.
But, if you are going with the approach#2, you will be dealing with the followings:
You are tying the URL or the path param to have a fixed pattern i.e. x-x-x-<page_no>.
Also, unnecessary string processing overhead on the backend.
Choice is yours! :)

Related

DNN Hotcakes Server Side API for creating a Single Variant

I'm using Hotcakes Commerce and the e-commerce platform on my DNN site. I've been using the server side API for Hotcakes to transfer product information from one install of Hotcakes to a clean install of Hotcakes. Long story short, one of my database tables got modified somehow and not knowing how it will affect the platform in the future I needed to move all the product data to a clean install of the platform. I've accomplished most of what I needed through building a console application and using the server side API.
The last piece I need is to create the variant information for each product. The only methods I've seen in the server side API is ProductOptionsGenerateAllVariants().
Is there a way to create a single variant using the server-side API?
This is somewhat straightforward to do, assuming that you understand choices/options and variants - as well as the differences between the two.
For the uninitiated... A choice or option allows a customer to specify a different version of the same product, nothing more. An example of this might be changing a t-shirt color from blue to grey. Nothing else changes, except the color.
A variant is still a choice at its core, but it does an additional thing which is to possibly change the SKU and/or pricing. An example of this would be choosing the size of your screen when buying a laptop. The 17" screen will be more expensive than the 15" screen, inventory may be affected differently, and possibly a different SKU/model number entirely.
When you create a single variant, you'll need the correct information to do so, which having choices created, with their variant property set to true, and you'll then need to associate those to the product. That being said, in some stores, there could potentially be millions of possible variants for even a single product. So, as such, the code is not as clean as anyone would like, but an example is below.
using System;
using System.Collections.Generic;
using System.Linq;
using Hotcakes.Commerce.Catalog;
using Hotcakes.Commerce.Extensions;
// get an instance of the application
var HccApp = HccAppHelper.InitHccApp();
// get an instance of the product which you'd like to add a variant to
var product = HccApp.CatalogServices.Products.FindBySku("SAMPLE003");
// get a list of the options that can become variants
var variantOptions = product.Options.VariantsOnly();
// we'll fill this list with choices that we wish to make variants below
var selections = new List<OptionSelection>();
// repeat this line of code for each choice in the product that makes up this variant
// replace both of the parameters when adding the new OptionSelection, based on your use case
selections.Add(new OptionSelection(variantOptions[0].Bvin, "REPLACE THIS WITH THE INDIVIDUAL CHOICE BVIN"));
// create a new variant object
var newVariant = new Variant()
{
ProductId = product.Bvin
};
// specify the choices that make up this variant
newVariant.Selections.AddRange(selections);
// get the unique key to use to compare below
var variantKey = newVariant.UniqueKey();
// check to see if the variant already exists first
if (!product.Variants.Any(v => v.UniqueKey() == variantKey))
{
// create the single variant
HccApp.CatalogServices.ProductVariants.Create(newVariant);
}

Rally print stories with parent feature name in the card generated

I've used Joel Krooswyk's Print All Backlog Story Cards solution for printing all stories in a backlog.
What I'd like to do is to extend this to have each card print the name of the parent feature that the card belongs to so I can print them all up and lay them on a table for a collaborative estimation session.
The issue is, I'm having trouble finding how to do it.
A snippet of his code in question:
queryArray[0] = {
key: CARD_TYPE,
type: 'hierarchicalrequirement',
query: '((Iteration.Name = "") AND (Release.Name = ""))',
fetch: 'Name,Iteration,Owner,FormattedID,PlanEstimate,ObjectID,Description,UserName',
order: 'Rank'
};
I can't seem to find the element to fetch!
Parent was listed on an example queries page(intended for use in the browser query functionality), with Parent.Name containing the actual text but so that hasn't worked - trying to find a reference that is clear about it seems to be eluding me.
I've looked at the type definition located at:
https://rally1.rallydev.com/slm/webservice/v2.0/typedefinition/?fetch=ObjectID&pagesize=100&pretty=true
Going to the hierarchical requirement's type definition from that page indicates it has a Parent field in one form or another.
I'm not even sure that that one will solve what I'm looking at.
A bit stuck, and I'm not sure what I'm trying to do is even possible with the hierarchical requirement object type.
Note: I assume even if I do find it I'll need to add some code to deal parentless stories- not worried about that though, that's easy enough to deal with once I find the actual value.
Many thanks to anyone who can help :)
I modified Joel's app to include PI/Feature's FormattedID to the cards when a story has a parent PI/Feature.
You may see the code in this github repo.
Parent field of a user story references another user story.
If you want to read a parent portfolio item of a user story, which is a Feature object, use Feature attribute or PortfolioItem attribute. Both will work:
if (data[i].PortfolioItem) {
//feature = data[i].PortfolioItem.FormattedID; //also works
//feature = data[i].Feature.Name; //also works
feature = data[i].Feature.FormattedID;
} else {
feature = "";
}
as long as the version of API is set in the code to 1.37 or above (up to 1.43).
PrintStoryCards app is AppSDK1 app.
1.33 is the latest version of AppSDK1.x
1.29, which the app is using is not aware of PortfoilioItems.
PortfolioItem was introduced in Rally in WS API version 1.37.
See API versioning section in the WS API documentation .
If you want to access Portfolio Items, or other features introduced in later versions of WS API up to 1.43 this syntax will allow it.
<script type="text/javascript" src="/apps/1.33/sdk.js?apiVersion=1.43"></script>
This has to be used with caution. One thing that definitely will break is around calculations of timebox start and end dates. That's why many legacy Rally App Catalog apps are still at 1.29.
This is due to changes in API Version 1.30.
Note that this method of setting a more advanced version of WS API for AppSDK1 does not work with v2.0 of WS API.
You should be able to add PortfolioItem to your fetch. Parent is the field used if the parent is a story. PortfolioItem is the field used if the parent is a Feature (or whatever your lowest level PI is).
Then in the results you can just get it like this:
var featureName = (story.PortfolioItem && story.PortfolioItem.Name) || 'None';

Ektron Workarea

I need to develop an application that extracts all the contents in Content Tab of the Ektron Workarea and I have to keep tree structure of folders (taxonomies,collections,forms,etc.) also.When I click the content I need to get the Content ID in the code behind also.I need to do all these in a single function.
I tried this requirement with the concept of content block widget in workarea.When we drag that widget and edit it a pop up will come and it displays the folders of work area in tree structure.But when I created an aspx page, put the same code and I browse that page I didn't get the tree structure of all contents.Only the main tabs(Folders,Taxonomies and search ) are visible.Then I drag the user control in the aspx page .But it also doest work.
So how will I solve the above problem.
Can I pull all the contents in tree structure from work area from the root using API codes?.Then can anyone please give the API code to solve?
Please anyone reply!
Assuming you are using 8.6 look here to start with:
http://reference.ektron.com/developer/framework/content/contentmanager/getlist.aspx
Update:
I think I misread your question the first time around. Allow me to expand on my answer a bit. My original answer with the web services assumes that you are rendering the content tree from some sort of "presentation tier" -- a different web site, a console app, or a WPF/WinForms app, etc.
You can get the recursive folder structure with something like this:
private FolderData GetFolderWithChildren(long folderId)
{
var folderApi = new Ektron.Cms.API.Folder();
var folderData = folderApi.GetFolder(folderId);
// This next method is marked as obsolete in v9.0;
// a newer overload is available in v9.0, but I
// don't know if it's available in v8.0
folderData.ChildFolders = folderApi.GetChildFolders(folderId, true);
}
I'm a little confused as to what exactly you're trying to accomplish. If you want to show the entire tree structure graphically, have you tried taking the code and markup from the edit view of the content widget and using it on your non-edit view?
I must say, your requirement that "I need to do all these in a single function" worries me a bit. Workarea content trees can get really large very quickly. If you're trying to load all of the folders and all the taxonomies and all the collections, etc. Then the user will likely be waiting a long time for the page to load, and you risk running into timeout issues.
-- Original Answer --
Ektron v8.0 doesn't have the 3-tier option, which is too bad because that would really make your job a lot easier. In v8.0, there are ASMX web services that you can reference, including:
/workarea/webservices/content.asmx
/workarea/webservices/webserviceapi/user/user.asmx
There are lots more than this; browse through the folders within /workarea/ to see what's available.
It's been a while since I've worked with these services, so I'm a little rusty...
Suppose you add references to those two services I listed above and name them ContentService and UserService. The first thing you'll want to do is set the authentication headers. Then you can call the service methods in much the same way as the old legacy apis.
var contentApi = new ContentService.Content();
contentApi.AuthenticationHeaderValue = new ContentService.AuthenticationHeader();
contentApi.AuthenticationHeaderValue.Username = username;
contentApi.AuthenticationHeaderValue.Password = password;
contentApi.AuthenticationHeaderValue.Domain = domain;
var userApi = new UserService.User();
userApi.AuthenticationHeaderValue = new UserService.AuthenticationHeader();
userApi.AuthenticationHeaderValue.Username = username;
userApi.AuthenticationHeaderValue.Password = password;
userApi.AuthenticationHeaderValue.Domain = domain;
var ud = userApi.GetUserbyUsername("jimmy456");
long folderID = 85;
bool recursive = true;
ContentData[] folderContent = contentApi.GetChildContent(folderID, recursive, "content_id");

ASP.net MVC: Execute Razor from DB String?

I was thinking about giving end users the ability to drop Partial Views (controls) into the information being stored in the database. Is there a way to execute a string I get from the database as part of the Razor view?
Update (I forgot all about this)
I had asked this question previously (which lead me to create RazorEngine) Pulling a View from a database rather than a file
I know of at least two: RazorEngine, MvcMailer
I have a bias towards RazorEngine as it's one that I've worked on but I have a much simpler one at Github called RazorSharp (though it only supports c#)
These are all pretty easy to use.
RazorEngine:
string result = RazorEngine.Razor.Parse(razorTemplate, new { Name = "World" });
MvcMailer
I haven't used this one so I can't help.
RazorSharp
RazorSharp also supports master pages.
string result = RazorSharp.Razor.Parse(new { Name = "World" },
razorTemplate,
masterTemplate); //master template not required
Neither RazorSharp, nor RazorEngine support any of the Mvc helpers such as Html and Url. Since these libraries are supposed to exist outside of Mvc and thus require more work to get them to work with those helpers. I can't say anything about MvcMailer but I suspect the situation is the same.
Hope these help.

Connection strings for different users

How do I send two users coming from different company domains to different SQL databases to retrieve/store data? I use Application variables to store the connection strings and the Request.ServerVariables("LOGON_USER") variable is an effective way to get the domain name. Is the GLOBAL.AsA file to be modified? The table names are exactly the same in both databases, so I think changing the connection strings based on the user domain should do the trick.
User A with domain ABC --> Application("ConnecttoDB") send to database A
User B with domain XYZ --> Application("ConnecttoDB") send to database B
I have roughly 900+ classic ASP pages so I would really hate to add a bunch of IF-THEN's to choose the correct database in each page. All ideas are greatly appreciated!
UPDATE: To make things simple I'm envisioning one single Application variable (i.e.: ConnecttoDB) However, wouldn't its value be constantly changing every time a different user gets access and altering page results?
You can't use an Application variable since that's shared across all users. This would be a race condition. Instead you'll need to use the Session object to store the connection and then use that whenever you need to connect to the DB.
myDB=Server.CreateObject("ADODB.Connection")
StrConn = Session("ConnecttoDB")
myDB.Open StrConn
Here's one way of doing it:
I'm guessing that your classes for your web page codebehind files inheit the Page class. Create a new class file in your ASP.net project that inherits Page. Call it JorgePage. Then, make your codebehind file classes inherit JorgePage.
In JorgePage, write two functions:
private string getUsersDomain()
{
// returns the user's domain
}
protected string getUsersConnectionString()
{
switch (getUsersDomain().ToUpper())
{
case "ABC":
return Application("ConnecttoDB_ABC");
break;
case "xYZ":
return Application("ConnecttoDB_XYZ");
break;
}
}
Now, the function getUsersConnectionString() is available in the context of all your pages and returns the correct connection string. Furthermore, you have the code in only one place, so if you need to change the logic later, you can do so easily.
Given that you're using classic ASP, you can define a function to return the appropriate connection string in another .asp file and use the #include directive to add it to all your pages.