How to store a picture within Active Directory using Ruby in a Rail3App? - ruby-on-rails

All I want to do is to upload an image into the Active Directory. So far I can update any AD information but the image. I have tried to search for some idea but came up with nothing so far.
Do I have to encode an image in a certain way? Do I just ldap-replace the jpegPhoto attribute with a byte-string of the photo?
Any hint towards a solution would be great.
Thanks in advance!

First of all, there is an attribute in Active directory called thumbnailPhoto. According to this Microsoft article The thumbNailPhoto attribute contains octet string type data. The AD interprets octet string data as an array of bytes.
If you want a sample code in C# you can get something here.
On the theorical point of view you can also inject a photo with LDIF using tools like "B64" to code your image file in base 64.
Secondly, On my point of view a Directory is not a database.
So, even if the attribute exists (created by netscape according to the OID 2.16.840.1.113730.3.1.35), even if Microsoft explain us how to put a picture into Active Directory, I think that it's better to register an URL, or a path to a file from a file system into a Directory.
I have no idea of the impact on performance of AD if I load each entry with 40 Ko (average size of a thumbnail photo). But I know that if there are bad written programs on the network, I mean kind of program that load all the attributes when they search an entry into the directory, this will considerably load the network.
I hope it helps.
JP

I had this issue and was able to get it working by creating a File stream and passing it through to #ldap.replace_attribute as a binary file. i.e.
thumbnail_stream = open("path_to_file")
#ldap.replace_attribute USERS_DN, :thumbnailPhoto, File.binread(thumbnail_stream)
Where #ldap is an instance of net/ldap, bound to AD. i.e.
#ldap = Net::LDAP.new
#ldap.host = ''
#ldap.port = ''
#ldap.auth USERNAME, PASSWORD
#ldap.bind

Related

How can I preserve storage space and load time with Active Storage?

I have a user submission form that includes images. Originally I was using Carrierwave, but with that the image is sent to my server for processing first before being saved to Google Cloud Services, and if the image/s is/are too large, the request times out and the user just gets a server error.
So what I need is a way to upload directly to GCS. Active Storage seemed like the perfect solution, but I'm getting really confused about how hard compression seems to be.
An ideal solution would be to resize the image automatically upon upload, but there doesn't seem to be a way to do that.
A next-best solution would be to create a resized variant upon upload using something like #record.images.first.variant(resize_to_limit [xxx,xxx]) #using image_processing gem, but the docs seem to imply that a variant can only be created upon page load, which would obviously be extremely detrimental to load time, especially if there are many images. More evidence for this is that when I create a variant, it's not in my GCS bucket, so it clearly only exists in my server's memory. If I try
#record.images.first.variant(resize_to_limit [xxx,xxx]).service_url
I get a url back, but it's invalid. I get a failed image when I try to display the image on my site, and when I visit the url, I get these errors from GCS:
The specified key does not exist.
No such object.
so apparently I can't create a permanent url.
A third best solution would be to write a Google Cloud Function that automatically resizes the images inside Google Cloud, but reading through the docs, it appears that I would have to create a new resized file with a new url, and I'm not sure how I could replace the original url with the new one in my database.
To summarize, what I'd like to accomplish is to allow direct upload to GCS, but control the size of the files before they are downloaded by the user. My problems with Active Storage are that (1) I can't control the size of the files on my GCS bucket, leading to arbitrary storage costs, and (2) I apparently have to choose between users having to download arbitrarily large files, or having to process images while their page loads, both of which will be very expensive in server costs and load time.
It seems extremely strange that Active Storage would be set up this way and I can't help but think I'm missing something. Does anyone know of a way to solve either problem?
Here's what I did to fix this:
1- I upload the attachment that the user added directly to my service provider ( I use S3 ).
2- I add an after_commit job that calls a Sidekiq worker to generate the thumbs
3- My sidekiq worker ( AttachmentWorker ) calls my model's generate_thumbs method
4- generate_thumbs will loop through the different sizes that I want to generate for this file
Now, here's the tricky part:
def generate_thumbs
[
{ resize: '300x300^', extent: '300x300', gravity: :center },
{ resize: '600>' }
].each do |size|
self.file_url(size, true)
end
end
def file_url(size, process = false)
value = self.file # where file is my has_one_attached
if size.nil?
url = value
else
url = value.variant(size)
if process
url = url.processed
end
end
return url.service_url
end
In the file_url method, we will only call .processed if we pass process = true. I've experimented a lot with this method to have the best possible performance outcome out of it.
The .processed will check with your bucket if the file exists or not, and if not, it will generate your new file and upload it.
Also, here's another question that I have previously asked concerning ActiveStorage that can also help you: ActiveStorage & S3: Make files public
I absolutely don't know Active Storage. However, a good pattern for your use case is to resize the image when it come in. For this
Let the user store the image in Bucket1
When the file is created in Bucket1, an event is triggered. Plug a function on this event
The Cloud Functions resizes the image and store it into Bucket2
You can delete the image in Bucket1 at the end of the Cloud Function, or keep it few days or move it to cheaper storage (to keep the original image in case of issue). For this last 2 actions, you can use Life Cycle to delete of change the storage class of files.
Note: You can use the same Bucket (instead of Bucket1 and Bucket2), but an event to resize the image will be sent every time that a file is create in the bucket. You can use PubSub as middleware and add filter on it to trigger your function only with the file is created in the correct folder. I wrote an article on this

Logic App retrieve values from custom created parameter names in a text file

having trouble with Logic App usage, so i am receiving a file with example text below and need to map them according to their tags. so for each tag they will go to different fields in my database. Keep in mind I cannot change the structure of the file, stays as is due to previous systems:
:2e:hello
:3t:there
:fy:people
What I do is pull the file from file storage and them i can access the content which are the values above. But what I need to do is check if i have ':2e:' and if so take its value which is 'there'.
Any suggestions?
thanks

Google Drive queryForFilesList not returning any results

I'm currently having issues with the iOS Google Drive SDK. I'm using GTLQueryDrive queryForFilesList to search for a file in my Google Drive. All the files I want have a path in the format directory-name/file-name. Since the SDK/API doesn't allow searching for files using a full path, I'm using the following query to ultimately get it's downloadUrl. I'm using a query in the following format:
((title = 'directory-name') AND ('root' in parents) AND (mimeType = 'application/vnd.google-apps.folder')) OR
((title = 'file-name') AND (not 'root' in parents) AND (mimeType != 'application/vnd.google-apps.folder'))
The first line is meant to find all directories in the root directory whose name matches mine, and the second line should match all files with the same name. This should return the directory i'm looking for, the file i'm looking for, and maybe some other stuff (e.g. files with the same name in other directories). I have some code to figure out which file is the correct one.
The problem I'm having is that sometimes I get no results from the query. This generally happens after I rename the file, and rename it back, or other things like that. The weird part is that if I run either of the two lines of the query independently, it returns correctly, but together they don't.
Any help would be greatly appreciated, and I would gladly provide more information if required.
And yes, I'm using the kGTLAuthScopeDrive scope.
The ideal solution would be if I could just search using a full path, so if there's a way to do this, then I'm not aware.
Unfortunately, I was unable to get this to work. And also unfortunately, Google does not provide an API to query for a full path. So I resorted to iterating over the path to get the directory IDs, and then when I get to the file, get its ID and download it. Although slightly more complex, my solution was based on this question and chosen answer: What's the right way to find files by "full path" in Google Drive API v2

How to dynamically generate url for image map in Oracle ApEx?

The scenario:
I have an ApEx page which pulls a record from a table. The record contains an id, the name of the chart (actually a filename) and the code for an image map as an NVARCHAR2 column called image_map.
When I render the page I have an embedded HTML region which pulls the image in using the #WORKSPACE_IMAGES#&P19_IMAGE. substitution as the src for the image.
Each chart has hot spots (defined in the image_map html markup) which point to other charts on the same ApEx page. I need to embed the:
Application ID (like &APP_ID.)
Session (like &APP_SESSION.)
My problem:
When I try to load the &APP_ID as part of the source into the database it pre-parses it and plugs in the value for the ApEx development app (e.g. 4500) instead of the actual target application (118).
Any help would be greatly appreciated.
Not a lot of feedback - guess I'm doing something atypical?
In case someone else is trying to do this, the workaround I ended up using was to have a javascript run and replace some custom replacement flags in the urls. The script is embedded in the template of the page and assigns the APEX magic fields to local variables, e.g.:
var my_app_id = '&APP_ID';
Not pretty, but it works...
Ok - I think I've left this open long enough... In the event that anyone else is trying to (mis)use apex in a similar way, it seems like the "apex way" is to use dynamic actions (which seem stable from 4.1.x) and then you can do your dynamic replace from there rather than embedding js in the page(s) themselves.
This seems to be the most maintainable, so I'll mark this as the answer - but if someone else has a better idea, I'm open to education!
I found it difficult to set a dynamic URL on a link to another page - directly - attempting to include the full URL as an individual link target doesn't work, at least in my simplistic world, I'm not an expert (as AJ said: any wisdom appreciated).
Instead, I set individual components of the url via the link, and a 'Before Header' PL/SQL process on the targeted page to combine the elements into a full url and assign it to the full url page-item:
APEX_UTIL.set_session_state(
'PG_FULL_URL',
'http...'||
v('PG_URL_COMPONENT1')||
v('PG_URL_COMPONENT2')||
'..etc..'
);
...where PG_FULL_URL is an item of Type 'Display Image', 'Based On' 'Image URL stored in Page Item Value'.
This is Apex 5.1 btw, I don't know if some of these options are new in this release.

CAB file API clarification

Since I'm not really seeing any content anywhere that doesn't point back to the original Microsoft documents on this matter, or source code that really doesn't seem to answer the questions I'm having, I thought I might ask a few things here. (Delphi tag is there because that's what my dev environment is on the code I'm making from this)
That said, I had a few questions the API document wasn't answering. First one: fdi_notify messages. What is "my responsibility" is in coding these: fdintCABINET_INFO: fdintPARTIAL_FILE: fdintNEXT_CABINET: fdintENUMERATE: ? I'll illustrate what I mean by an example. For fdintCLOSE_FILE_INFO, "my responsibility" is to Close a file related to handle given me, and set the file's date and time according to the data passed in fdi_notify.
I figure I'm missing something since my code isn't handling extracting spanned CAB files...any thoughts on how to do this?
What you're more than likely running into is that FDICopy only reads the cab you passed in. It will use fdintNEXT_CABINET to get spanned data for any files you extract in response to fdintCOPY_FILE, but it only calls fdintCOPY_FILE for files that start on that first cab.
To get a directory listing for the entire set, you need to call FDICopy in a loop. Every time you get a fdintCABINET_INFO event, save off the psz1 parameter (next cab name). When FDICopy returns, check that. If it's an empty string you're done, if not call FDICopy again with the next cab as the new path.
fdintCABINET_INFO: The only responsibility for this is returning 0 to continue processing. You can use the information provided (the path of the next cabinet, next disk, path name, nad set ID), but you don't need to.
fdintPARTIAL_FILE: Depending on how you're processing your cabs, you can probably ignore this. You'll only see it for the second and later images in a set, and it's to tell you that the particular entry is continued from a previous cab. If you started at the first cab in the set you'll have already seen an fdintCOPY_FILE for the file. If you're processing random .cabs, you won't really be able to use it either, since you won't have the start of the file to extract.
fdintNEXT_CABINET: You can use this to prompt the user for a new directory for the next cabinet, but for simple spanning support just return 0 if the passed in filename is valid or -1 if it isn't. If you return 0 and the cab isn't valid, or is the wrong one, this will get called again. The easiest approach (if you don't request a new disk/directory), is just to check pfdin^.fdie. If it's FDIError_None it's equal the first time being called for the requested cab, so you can return 0. If it's anything else it's already tried to open the requested cab at least once, so you can return -1 as an error.
fdintENUMERATE: I think you can ignore this. It isn't covered in the documentation, and the two cab libraries I've looked at don't use it. It may be a leftover from a previous API version.

Resources