Given a minimal example of a Coldfusion rest service (named "FileStore"):
component
restpath = ""
rest = true
{
remote void function getFile(
required string path restargsource = "Path"
)
httpmethod = "GET"
restpath = "{path}"
{
var file = FileReadBinary( "/some/path/to/local/files/#path#" );
var mimetype = customFunctionToGetMimeType( getFileFromPath( path ) );
cfcontent( variable = file, type = mimetype );
}
}
This will match paths:
/rest/FileStore/file1.pdf
/rest/FileStore/file2.jpg
But if you try sub-directories - i.e.
/rest/FileStore/subdir1/file3.xml
/rest/FileStore/subdir2/subsubdir1/file4.raw
It returns HTTP status 404 Not Found (as, I'm assuming, it cannot find a matching REST service).
Is there a way to get the rest path to match all sub-paths?
Use URI Rewriting to perform a redirect remove the slashes from the path.
An example in Apache (taken from this answer) would be:
RewriteEngine on
RewriteRule ^(/rest/FileStore/[^/]*)/([^/]*/.*)$ $1__$2 [N]
RewriteRule ^(/rest/FileStore/[^/]*)/([^/]*)$ $1__$2 [R=302]
The first rule will replace the first slash (with __) if there are multiple slashes in the path (and repeat); the second rule will replace the final slash and perform a (temporary) redirect.
In the service you can then re-rewrite the path to include the slashes.
remote void function getFile(
required string path restargsource = "Path"
)
httpmethod = "GET"
restpath = "{path}"
{
var actual_path = Replace( path, "__", "/", "ALL" );
var file = FileReadBinary( "/some/path/to/local/files/#actual_path#" );
var filename = getFileFromPath( actual_path );
var mimetype = customFunctionToGetMimeType( filename );
cfheader( name = "content-disposition", value = "inline; filename=#filename#" );
cfcontent( variable = file, type = mimetype );
}
There are several issues with this:
If you are navigating through files which contain relative path links to other files in different sub-directories then the URI rewriting breaks these links.
If the original path contains the string used to replace slashes then this will break the file path.
Write a REST service for each level of the subdirectory and, internally, point it back to the original service.
remote void function getSubdir1File(
required string subdir1 restargsource = "Path",
required string file restargsource = "Path"
)
httpmethod = "GET"
restpath = "{subdir1}/{file}"
{
getFile( subdir1 & '/' & file );
}
remote void function getSubdir2File(
required string subdir1 restargsource = "Path",
required string subdir2 restargsource = "Path",
required string file restargsource = "Path"
)
httpmethod = "GET"
restpath = "{subdir1}/{subdir2}/{file}"
{
getFile( subdir1 & '/' & subdir2 & '/' & file );
}
Repeating ad-nauseum until you get to a sufficient depth that you've covered 99.9999%/sufficient of the use cases.
This addresses the issues with URI rewriting (allows relative path links within files and for file names to use all non-slash characters).
It is not DRY.
If you get a file in a directory beyond the implemented depth then it will not be found. (Although it could be coupled with URI rewriting to allow the file to be found even if it does then break internal links for these limited cases.)
Jersey (JAX-RS), which is what ColdFusion appears to use under the hood for its REST services, allows regular expressions in its #PATH notation.
Using a regular expression to match all characters (restpath = "{path:.*}") then you can simply match all sub-paths:
component
restpath = ""
rest = true
{
remote void function getFile(
required string path restargsource = "Path"
)
httpmethod = "GET"
restpath = "{path:.*}"
{
var file = FileReadBinary( "/some/path/to/local/files/#path#" );
var mimetype = customFunctionToGetMimeType( getFileFromPath( path ) );
cfcontent( variable = file, type = mimetype );
}
}
Thanks to this answer for the inspiration
Related
I am creating a vscode extension that does some custom auto-completing of files paths.
I want to take what the user has typed, and if that value resolves to a folder in the workspace, I want to list all the files in that folder for auto-complete.
For example, given:
a workspace located at: /home/me/my-vs-project
with files:
/home/me/my-vs-project/assets/dog.png
/home/me/my-vs-project/assets/cat.jpeg
If I type in 'assets' or './assets' into vscode, the extension should be able to provide me an autocomplete list of:
'./assets/dog.png'
'./assets/cat.png'
Here's a snippet of the code that doesn't work (returns 0 results)..
let inputAsWorkspaceRelativeFolder = getInput(document, position); // for example, would return: '/home/me/my-vs-project/assets' for input of './assets'
let glob = inputAsWorkspaceRelativeFolder + '/*';
vscode.workspace.findFiles(glob, null, 100).then((uris: vscode.Uri[] ) => {
uris.forEach((uri: vscode.Uri) => {
console.log(uri);
});
});
For some reason, the above code is returning 0 uris though. Thoughts on how I have to format the glob to make this happen? and/or if there is a better approach?
I was able to do this using vscode.RelativePattern -- I'm sure I could've done it using generic GlobPatterns but im still not clear what the findFiles(..) consider the 'root' when matching files; RelativePattern is explicitly relative to the workspace root.
let workspaceFolder: vscode.WorkspaceFolder | undefined = vscode.workspace.getWorkspaceFolder(document.uri);
if (!workspaceFolder || document.isUntitled) {
return undefined;
}
// Workspace folder: /home/me/my-project
let workspaceFolderPath: string = workspaceFolder.uri.path;
let relativeSearchFolderPrefix = path.normalize(path.dirname(document.uri.path) + '/' + searchText);
relativeSearchFolderPrefix = path.relative(workspaceFolderPath, relativeSearchFolderPrefix);
let relativePattern: vscode.RelativePattern = new vscode.RelativePattern(
workspaceFolderPath,
relativeSearchFolderPrefix + '/**/*.{png,jpeg,jpg,gif}');
return vscode.workspace.findFiles(globPattern, null, 50).then((uris: vscode.Uri[] ) => {
let relativePaths: string[] = [];
uris.forEach((uri: vscode.Uri) => {
relativePaths.push(path.relative(current, uri.path));
});
// trivial custom function that turns an array of strings into CompletionItems
return getCompletionItems(relativePaths, vscode.CompletionItemKind.File);
});
😊👋🏻
I think you wronged the glob.
I found this intresting wiki about Glob pattern composition.
let inputAsWorkspaceRelativeFolder = 'asset'; // for example, would return: '/home/me/my-vs-project/assets' for input of './assets'
//https://github.com/ev3dev/vscode-ev3dev-browser/wiki/Glob-Patterns
let glob = '**/'+inputAsWorkspaceRelativeFolder+'/*.*';//or +'/{*.png,*.jpeg}';
Or you can use the node built-in fs
import * as fs from 'fs';
fs.readdir(inputAsWorkspaceRelativeFolder, (err, files: string[]) => {
files.forEach((file: path) => {
const uri = vscode.Uri.file(file);
console.log(uri);
});
});
More simple, if you want to get all the files in the asset folder and don't want to filter for extension.
My requirement is actually pretty simple, I want to write a file and open it in vscode. But I can't get this to work:
var content = rec[rt.fields[field]];
var filePath = path.join(vscode.workspace.rootPath, selected.label + '.' + field);
fs.writeFileSync(filePath, content, 'utf8');
var openPath = vscode.Uri.parse(filePath);
vscode.workspace.openTextDocument(openPath).then(doc => {
vscode.window.showTextDocument(doc);
});
I get the following error message and have no idea what that should mean:
cannot open c:%5CUsers%5Cmak%5C.sneditor%5Csoftpointdev1.service-now.com%5CRMCostPlanHelper.js. Detail: No model with uri 'c:%5CUsers%5Cmak%5C.sneditor%5Csoftpointdev1.service-now.com%5CRMCostPlanHelper.js' nor a resolver for the scheme 'c'.
As soon as a posted this Question I found out the answer ^^
You have to use vscode.Uri.file not vscode.Uri.parse
const content = 'exampleContent';
const filePath = path.join(vscode.workspace.rootPath, 'fileName.extension');
fs.writeFileSync(filePath, content, 'utf8');
const openPath = vscode.Uri.file(filePath);
vscode.workspace.openTextDocument(openPath).then(doc => {
vscode.window.showTextDocument(doc);
});
I also encountered a similar problem. You can also solve your problem by doing the following:
var content = rec[rt.fields[field]];
var filePath = path.join(vscode.workspace.rootPath, selected.label + '.' + field);
fs.writeFileSync(filePath, content, 'utf8');
var openPath = vscode.Uri.parse("file:///" + filePath); //A request file path
vscode.workspace.openTextDocument(openPath).then(doc => {
vscode.window.showTextDocument(doc);
});
I'm using Zend_Navigation' reading fron xml.
I want to add to the menu created from it an additional parameter (got it from the request for the first page).
e.g
if the first page is mysite.com/pages/page1?Id=42
then
clicking on the menu would add the "?Id=42" to each link.
Easiest way to do this is by extending the Zend_Controller_Action_Helper_Url class, and adding the query string to the parent::url() result. Than, you need to inject your url helper into the mvc page, by calling Zend_Navigation_Page_Mvc::setUrlHelper($yourUrlHelper).
Example of a query string supported url helper:
class My_Helper_Url extends Zend_Controller_Action_Helper_Url
{
public function url($urlOptions = array(), $name = null, $reset = false, $encode = true)
{
$queryString = $this->getRequest()->getServer('QUERY_STRING');
return parent::url($urlOptions, $name, $reset, $encode) .
($queryString ? '?' . $queryString : '');
}
}
Here is my problem.
I use a dynamic connection string for my Entity Framework context.
//In Web Config
add key="DataSource" value="WIN-QBRH0MJL8IT\ISS" />
//In my EntityFactory.cs
public static DBEntities GetEntity()
{
var scsb = new SqlConnectionStringBuilder();
scsb.DataSource = ConfigurationManager.AppSettings["DataSource"];
scsb.InitialCatalog = "db1";
scsb.MultipleActiveResultSets = true;
scsb.IntegratedSecurity = true;
if (HttpContext.Current.Session["DBName"] == null)
{
HttpContext.Current.Response.Redirect("/Account/Step1");
}
else
{
scsb.InitialCatalog = HttpContext.Current.Session["DBName"].ToString();
}
var builder = new EntityConnectionStringBuilder();
builder.Metadata = "metadata=~/bin/Models/DBModel.csdl|~/bin/Models/DBModel.ssdl|~/bin/Models/DBModel.msl";
builder.Provider = "System.Data.SqlClient";
builder.ProviderConnectionString = scsb.ConnectionString;
DBEntities db = new DBEntities(builder.ConnectionString);
return db;
}
I Know the problem is for this line :
builder.Metadata =
"metadata=~/bin/Models/DBModel.csdl|~/bin/Models/DBModel.ssdl|~/bin/Models/DBModel.msl";
I check and the csdl, ssdl, msl are in /mvcinfosite/bin/Models/.csdl,.ssdl,.msl
The configuration for my edmx is:
Metadata Artifact Processing : Copy to Output Directory
Here is the full error
The specified metadata path is not valid. A valid path must be either
an existing directory, an existing file with extension '.csdl',
'.ssdl', or '.msl', or a URI that identifies an embedded resources
Thanks
Try to remove ~ character and use valid relative path to your app root. I think it is not able to work with this special character used on in ASP.NET application.
i would like to access some built in properties(like author,last modified date,etc.) of an open xml word doc file. i would like to use open xml sdk2.0 for this purpose. so i wonder if there is any class or any way i could programmatically access these builtin properties.
An explanation of the following method can be found here, but pretty much you need to pass in the properties that you want to get out of the core.xml file to this method and it will return the value:
public static string WDRetrieveCoreProperty(string docName, string propertyName)
{
// Given a document name and a core property, retrieve the value of the property.
// Note that because this code uses the SelectSingleNode method,
// the search is case sensitive. That is, looking for "Author" is not
// the same as looking for "author".
const string corePropertiesSchema = "http://schemas.openxmlformats.org/package/2006/metadata/core-properties";
const string dcPropertiesSchema = "http://purl.org/dc/elements/1.1/";
const string dcTermsPropertiesSchema = "http://purl.org/dc/terms/";
string propertyValue = string.Empty;
using (WordprocessingDocument wdPackage = WordprocessingDocument.Open(docName, true))
{
// Get the core properties part (core.xml).
CoreFilePropertiesPart corePropertiesPart = wdPackage.CoreFilePropertiesPart;
// Manage namespaces to perform XML XPath queries.
NameTable nt = new NameTable();
XmlNamespaceManager nsManager = new XmlNamespaceManager(nt);
nsManager.AddNamespace("cp", corePropertiesSchema);
nsManager.AddNamespace("dc", dcPropertiesSchema);
nsManager.AddNamespace("dcterms", dcTermsPropertiesSchema);
// Get the properties from the package.
XmlDocument xdoc = new XmlDocument(nt);
// Load the XML in the part into an XmlDocument instance.
xdoc.Load(corePropertiesPart.GetStream());
string searchString = string.Format("//cp:coreProperties/{0}", propertyName);
XmlNode xNode = xdoc.SelectSingleNode(searchString, nsManager);
if (!(xNode == null))
{
propertyValue = xNode.InnerText;
}
}
return propertyValue;
}
You can also use the packaging API:
using System.IO.Packaging.Package;
[...]
using (var package = Package.Open(path))
{
package.PackageProperties.Creator = Environment.UserName;
package.PackageProperties.LastModifiedBy = Environment.UserName;
}
That works also for other open XML formats like power point.
package.Save();
Then
package.closed;
I think that Is the best way.