How to Bind Image from table in Orchard cms - orchardcms

We have seen the all image required to register in web.config but how can I bind the dynamic images coming from database . Is there any approach to handle that problem ?

If you store your images in database, will be binding to byte array in the model, you must add an action to retrieve this images, then return it as "FileContentResult", as following:
public FileResult GetImage(int imageId) {
ImageRecord imageRecord = _repo.Get(imageId);
if (imageRecord != null) {
return new FileContentResult(imageRecord.Image, imageRecord .MimeType);
}
else {
return null;
}
}
Hope this will help you.

Related

Writing my own image importer, pictures are not recognized as pictures after import

i am writing my own image import for my product catalog. I want to read the images from the local filesystem and store them in the configured assets folder. The import is very simple for now. Its one controller in the admin project and i trigger it by calling an url.
It is creating the files along with the folder structure and the files seem to have the same filesize, but somehow they get messed up along the way and they are not readable as images anymore (picture viewers wont open them). Any ideas why its being messed up ?
here the code:
#Controller("blImageImportController")
#RequestMapping("/imageimport")
public class ImageImportController extends AdminAbstractController {
#Value("${image.import.folder.location}")
private String importFolderLocation;
#Resource(name = "blStaticAssetService")
protected StaticAssetService staticAssetService;
#Resource(name = "blStaticAssetStorageService")
protected StaticAssetStorageService staticAssetStorageService;
#RequestMapping(method = {RequestMethod.GET})
public String chooseMediaForMapKey(HttpServletRequest request,
HttpServletResponse response,
Model model
) throws Exception {
File imageImportFolder = new File(importFolderLocation);
if (imageImportFolder.isDirectory()) {
Arrays.stream(imageImportFolder.listFiles()).forEach(directory ->
{
if (directory.isDirectory()) {
Arrays.stream(directory.listFiles()).forEach(this::processFile);
}
});
}
return "";
}
private void processFile(File file) {
FileInputStream fis = null;
try {
HashMap properties = new HashMap();
properties.put("entityType", "product");
properties.put("entityId", file.getParentFile().getName());
fis = new FileInputStream(file);
StaticAsset staticAsset = this.staticAssetService.createStaticAsset(fis, file.getName(), file.length(), properties);
this.staticAssetStorageService.createStaticAssetStorage(fis, staticAsset);
fis.close();
} catch (Exception e) {
} finally {
try {
if (fis != null)
fis.close();
} catch (IOException ex) {
ex.printStackTrace();
}
}
}
}
There is a check in the StaticAssetService to try to detect this as an image (see https://github.com/BroadleafCommerce/BroadleafCommerce/blob/b55848f/admin/broadleaf-contentmanagement-module/src/main/java/org/broadleafcommerce/cms/file/service/StaticAssetServiceImpl.java#L217-L220). If it detected this correctly, you should get back an ImageStaticAssetImpl in the result to that call.
The flipside of this is the controller that actually reads the file (the StaticAssetViewController that renders a StaticAssetView). One of the things that the StaticAssetView does is set a response header for mimeType which the browser uses to render. This is set by this piece in the StaticAssetStorageService: https://github.com/BroadleafCommerce/BroadleafCommerce/blob/b55848f837f26022a620f0c2c143eed7902ba3f1/admin/broadleaf-contentmanagement-module/src/main/java/org/broadleafcommerce/cms/file/service/StaticAssetStorageServiceImpl.java#L213. I suspect that is the root of your problem.
Also just a note, sending those properties is not necessary when you are uploading the file yourself. That is mainly used in the admin when you are uploading an image for a specific entity (like a product or a category).

Google Custom Search API - Search Results

I have somewhat lost touch with custom search engines ever since Google switched from its more legacy search engine api in favor of the google custom search api. I'm hoping someone might be able to tell me whether a (pretty simple) goal can be accomplished with the new framework, and potentially any starting help would be great.
Specifically, I am looking to write a program which will read in text from a text file, then use five words from said document in a google search - the point being to figure out how many results accrue from said search.
An example input/output would be:
Input: "This is my search term" -- quotations included in the search!
Output: there were 7 total results
Thanks so much, all, for your time/help
First you need to create a Google Custom Search project inside you google account.
From this project you must obtain a Custom Search Engine ID , known as cx parameter. You must also obtain a API key parameter. Both of these are available from your Google Custom Search API project inside your google account.
Then, if you prefer Java , here's a working example:
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
public class GoogleCustonSearchAPI {
public static void main(String[] args) throws Exception {
String key="your_key";
String qry="your_query";
String cx = "your_cx";
//Fetch urls
URL url = new URL(
"https://www.googleapis.com/customsearch/v1?key="+key+"&cx="+cx+"&q="+ qry +"&alt=json&queriefields=queries(request(totalResults))");
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setRequestMethod("GET");
conn.setRequestProperty("Accept", "application/json");
BufferedReader br = new BufferedReader(new InputStreamReader(
(conn.getInputStream())));
//Remove comments if you need to output in JSON format
/*String output;
System.out.println("Output from Server .... \n");
while ((output = br.readLine()) != null) {
System.out.println(output);
}*/
//Print the urls and domains from Google Custom Search String searchResult;
while ((searchResult = output.readLine()) != null) {
int startPos=searchResult.indexOf("\"link\": \"")+("\"link\": \"").length();
int endPos=searchResult.indexOf("\",");
if(searchResult.contains("\"link\": \"") && (endPos>startPos)){
String link=searchResult.substring(startPos,endPos);
if(link.contains(",")){
String tempLink = "\"";
tempLink+=link;
tempLink+="\"";
System.out.println(tempLink);
}
else{
System.out.println(link);
}
System.out.println(getDomainName(link));
}
}
conn.disconnect();
}
public static String getDomainName(String url) throws URISyntaxException {
URI uri = new URI(url);
String domain = uri.getHost();
return domain.startsWith("www.") ? domain.substring(4) : domain;
}
The "&queriefields=queries(request(totalResults))" is what makes the difference and gives sou what you need. But keep in mind that you can perform only 100 queries per day for free and that the results of Custom Search API are sometimes quite different from the those returned from Google.com search
If anybody would still need some example of CSE (Google Custom Search Engine) API, this is working method
public static List<Result> search(String keyword){
Customsearch customsearch= null;
try {
customsearch = new Customsearch(new NetHttpTransport(),new JacksonFactory(), new HttpRequestInitializer() {
public void initialize(HttpRequest httpRequest) {
try {
// set connect and read timeouts
httpRequest.setConnectTimeout(HTTP_REQUEST_TIMEOUT);
httpRequest.setReadTimeout(HTTP_REQUEST_TIMEOUT);
} catch (Exception ex) {
ex.printStackTrace();
}
}
});
} catch (Exception e) {
e.printStackTrace();
}
List<Result> resultList=null;
try {
Customsearch.Cse.List list=customsearch.cse().list(keyword);
list.setKey(GOOGLE_API_KEY);
list.setCx(SEARCH_ENGINE_ID);
Search results=list.execute();
resultList=results.getItems();
}
catch ( Exception e) {
e.printStackTrace();
}
return resultList;
}
This method returns List of Result Objects, so you can iterate through it
List<Result> results = new ArrayList<>();
try {
results = search(QUERY);
} catch (Exception e) {
e.printStackTrace();
}
for(Result result : results){
System.out.println(result.getDisplayLink());
System.out.println(result.getTitle());
// all attributes
System.out.println(result.toString());
}
I use gradle dependencies
dependencies {
compile 'com.google.apis:google-api-services-customsearch:v1-rev57-1.23.0'
}
Don't forget to define your own GOOGLE_API_KEY, SEARCH_ENGINE_ID (cx), QUERY and HTTP_REQUEST_TIMEOUT (ie private static final int HTTP_REQUEST_TIMEOUT = 3 * 600000;)

MVC 5 FileContentResult Action Result Permission and Redirect

I have an MVC 5 application that allows users to download files that are stored in the database. I am using the FileContentResult action method to do this.
I can restrict access to this method throughout the application, but a smart user can figure out the action URL and paste something like this (localhost:50000/Home/FileDownload?id=13) into their browser and have access to download any file by just changing the parameter.
I want to restrict users from doing this. Only allow the Administrator role AND users that have a specific permission that can only be determined by a database call to download files.
What I am looking for is that If an user uses the URL to download a file and does not have the proper permissions, I want to redirect the user with a message.
I would like to do something like the code below or similar, but I get the following error: Cannot implicitly convert type 'System.Web.Mvc.RedirectToRouteResult' to 'System.Web.Mvc.FileContentResult'
I understand that I can not use return RedirectToAction("Index") here, just looking for some ideas on how to handle this problem.
public FileContentResult FileDownload(int id)
{
//Check user has file download permission
bool UserHasPermission = Convert.ToInt32(context.CheckUserHasFileDownloadPermission(id)) == 0 ? false : true;
if (User.IsInRole("Administrator") || UserHasPermission)
{
//declare byte array to get file content from database and string to store file name
byte[] fileData;
string fileName;
//create object of LINQ to SQL class
//using LINQ expression to get record from database for given id value
var record = from p in context.UploadedFiles
where p.Id == id
select p;
//only one record will be returned from database as expression uses condtion on primary field
//so get first record from returned values and retrive file content (binary) and filename
fileData = (byte[])record.First().FileData.ToArray();
fileName = record.First().FileName;
//return file and provide byte file content and file name
return File(fileData, "text", fileName);
}
else
{
TempData["Message"] = "Record not found";
return RedirectToAction("Index");
}
}
Since both FileContentResult and RedirectToRouteResult are inherited from ActionResult, simply use ActionResult instead of FileContentResult for your action's return type:
public ActionResult FileDownload(int id)
{
if(IsUserCanDownloadFile()) // your logic here
{
// fetch the file
return File(fileData, "text", fileName);
}
return RedirectToAction("Index");
}
Or if you prefer attributes, you could write your very own authorize attribute to check permissions:
public class FileAccessAttribute : AuthorizeAttribute
{
private string _keyName;
public FileAccessAttribute (string keyName)
{
_keyName = keyName;
}
protected override bool AuthorizeCore(HttpContextBase httpContext)
{
// imagine you have a service which could check the Permission
return base.AuthorizeCore(httpContext)
|| (this.ContainsKey
&& _permissionService.CanDownload(httpContext.User.Identity.GetUserId(),
int.Parse(this.KeyValue.ToString()));
}
private bool ContainsKey
{
get
{
// for simplicity I just check route data
// in real world you might need to check query string too
return ((MvcHandler)HttpContext.Current.Handler).RequestContext
.RouteData.Values.ContainsKey(_keyName);
}
}
private object KeyValue
{
get
{
return ((MvcHandler)HttpContext.Current.Handler)
.RequestContext.RouteData.Values[_keyName];
}
}
}
Now you could decorate the custom attribute on your actions:
[FileAccess("id", Roles ="Administrator")]
public FileContentResult FileDownload(int id)
{
// fetch the file
return File(fileData, "text", fileName);
}

Orchard alternates based on Tag

I want to create alternates for content item based on its tag value.
For example, I want to create an alternate called List-ProjectionPage-tags-special
Searching the nets directs me to implement a new ShapeDisplayEvents
Thus, I have
public class TagAlternatesFactory : ShapeDisplayEvents
{
public TagAlternatesFactory()
{
}
public override void Displaying(ShapeDisplayingContext context)
{
}
}
In the Displaying method, I believe I need to check the contentItem off the context.Shape and create an alternate name based off of that (assuming it has the TagsPart added to the content item).
However, what do I do with it then? How do I add the name of the alternate? And is that all that's needed to create a new alternate type? Will orchard know to look for List-ProjectionPage-tags-special?
I took a cue from Bertrand's comment and looked at some Orchard source for direction.
Here's my implementation:
public class TagAlternatesFactory : ShapeDisplayEvents
{
public override void Displaying(ShapeDisplayingContext context)
{
context.ShapeMetadata.OnDisplaying(displayedContext =>
{
var contentItem = displayedContext.Shape.ContentItem;
var contentType = contentItem.ContentType;
var parts = contentItem.Parts as IEnumerable<ContentPart>;
if (parts == null) return;
var tagsPart = parts.FirstOrDefault(part => part is TagsPart) as TagsPart;
if (tagsPart == null) return;
foreach (var tag in tagsPart.CurrentTags)
{
displayedContext.ShapeMetadata.Alternates.Add(
String.Format("{0}__{1}__{2}__{3}",
displayedContext.ShapeMetadata.Type, (string)contentType, "tag", tag.TagName)); //See update
}
});
}
}
This allows an alternate view based on a tag value. So, if you have a project page that you want to apply a specific style to, you can simply create your alternate view with the name ProjectionPage_tag_special and anytime you want a projection page to use it, just add the special tag to it.
Update
I added the displayedContext.ShapeMetadata.Type to the alternate name so specific shapes could be overridden (like the List-ProjectionPage)

Finding control on SharePoint page

Im trying to locate an SPDataSource control located on my SharePoint page. I found the following code which probably works fine, I just don't know what to pass into it.
public static Control FindControlRecursive(Control Root, string Id)
{
if (Root.ID == Id)
return Root;
foreach (Control Ctl in Root.Controls)
{
Control FoundCtl = FindControlRecursive(Ctl, Id);
if (FoundCtl != null)
return FoundCtl;
}
return null;
}
I don't know how to have it search the whole page or at the very least the ContentPlaceHolder that the control is in.
edit
Looks like I have a more rudimentary issue here. Not sure how to explain but I'm not opening up the page before running my code. I'm opening the site via the following:
using (SPWeb web = thisSite.Site.OpenWeb("/siteurl/,true))
So when I try to find the page below I'm getting Object reference not set to instance of object.
var page = HttpContext.Current.Handler as Page;
Perhaps I'm going about this the wrong way, I'm in my infancy here so I'm just kind of stumbling along figuring stuff out!
What you got is actually not SharePoint specific, it's c# asp.net.
Anyway, you could call it like this
var page = HttpContext.Current.Handler as Page;
var control = page; // or put the element you know exist that omit (is a parent) of the element you want to find
var myElement = FindControlRecursive(control, "yourelement");
Most likely you'll need to cast the return as well
var myElement = (TextBox)FindControlRecursive(control, "yourelement");
// or
var myElement = FindControlRecursive(control, "yourelement") as TextBox;
There are however more efficient ways to write such a method, here is one simple example
public static Control FindControlRecursive(string id)
{
var page = HttpContext.Current.Handler as Page;
return FindControlRecursive(page, id);
}
public static Control FindControlRecursive(Control root, string id)
{
return root.ID == id ? root : (from Control c in root.Controls select FindControlRecursive(c, id)).FirstOrDefault(t => t != null);
}
Call it the same way as I suggested earlier.
If you are handling larger pages the methods above might be a bit slow, what you should do is aim for a method using generics instead. They are way faster than traditional methods.
Try this one
public static T FindControlRecursive<T>(Control control, string controlID) where T : Control
{
// Find the control.
if (control != null)
{
Control foundControl = control.FindControl(controlID);
if (foundControl != null)
{
// Return the Control
return foundControl as T;
}
// Continue the search
foreach (Control c in control.Controls)
{
foundControl = FindControlRecursive<T>(c, controlID);
if (foundControl != null)
{
// Return the Control
return foundControl as T;
}
}
}
return null;
}
You call it like this
var mytextBox = FindControlRecursive<TextBox>(Page, "mytextBox");

Resources