Gossamer Forum
Home : Products : DBMan : Customization :

One of those problems that only Carol can answer?

Quote Reply
One of those problems that only Carol can answer?
I'd like to change in some way the structure of DBMan. I'd like to add a password field to each record and make people use this password when they want to modify the record or delete it. I know, obviously, that I have to add a password field in the cfg file. I am a bit lost about what I should do to allow people to modify and delete the record. I'd like to have a link that would take people to a screen that asks for ID and password, that compares that password with the one saved in the DB (I wouldn't encrypt the password) and then if the password matches let them modify or delete the record (that choice could be present in the screen, for example with a radio button). I am asking for a little help with the code. I don't know if a new subroutine should be added. I am not an expert in Perl, but I think that many would benefit from this modification of the code. Thanks in advance.
Quote Reply
Re: One of those problems that only Carol can answer? In reply to
Is there a reason that you can't just use the regular login routine? (There must be, or you wouldn't be asking. Smile )

Hmmmmmmm. This may take some "ponder" time.

So you want the password to be associated with the record and not the person, right? Will the users be logging in before they try to modify the record? Would one user be able to modify records that had different passwords?

For example, you might have several records with a password of "rover" and other records with a password of "fido." Would I, as a user possibly have the ability to modify both the "rover" and the "fido" records, or just one of them? And would I be using my "JPDeni" username to log in first, or would I be a default user?

I'm assuming the users wouldn't "own" the records, right?

Basically, then, the user would be doing a search. You could have a form like a search form that just had the password field in it.

You would also probably want to eliminate the option to do a search for "*" on that field.

As for more subroutines, you'll probably just need a couple of html subroutines. Let's call this "alter," for want of a better name.

You'd need a form for the search -- where they enter the password -- which would be "html_alter_search." Then you'd need a subroutine for the results of the search that had both the modify and the delete buttons on it. That would be "html_alter_form." From there, you could just use the regular modify and delete routines.

You can pretty much copy the code from html_modify_form and html_delete_form to create your radio buttons and checkboxes. It's easiest if you have two submit buttons in the html_alter_form -- one for delete and one for modify, especially if you're going to let them delete more than one record at a time. Otherwise you're going to have to create another subroutine in db.cgi that could get messy.

You will need to add a couple of lines to db.cgi sub main to take the users to the right page, but those aren't hard to do.

This should be enough to get you started. If you run into any trouble, I'll be glad to help.


------------------
JPD





Quote Reply
Re: One of those problems that only Carol can answer? In reply to
oops. I got disconnected in the midst of posting.


[This message has been edited by JPDeni (edited May 15, 1999).]
Quote Reply
Re: One of those problems that only Carol can answer? In reply to
MMmmmmmmmmmm... as far as I can see it seems to be a bit more difficult than I have thought. Maybe a different way should be better.
I could adapt the system if I could force people to fill in all their information when they register for an account. I only want each account to be linked to a record. I understand that I could remove the option "Add record" from the footer sub. I am not quite sure how to change the add_record subroutine (where people register for accounts). I feel that it writes onto the password file only, and I should add some instructions to write onto the .db file as well. I really don't know what to write, and I feel that it is just copying something from another subroutine. Hope I didn't get you crazy, I'm just a foreigner that might have some mistakes in his expressions. Thanks for da patience. Smile
Quote Reply
Re: One of those problems that only Carol can answer? In reply to
That's okay. Sometimes it's hard to fully explain what you want.

Just to be sure I understand this time -- you want to have the user sign up for an account and fill out the add form at the same time(?).

You can do that. What it would require is that you copy the routines that write the information to the password file into the add_record subroutine.

You would allow a default user, who had permission to add, but when you wrote to the password file, you would give the user permission only to modify and delete.

I'm working on something similar to that now, and I'll be glad to share it once I get things worked out.


------------------
JPD





Quote Reply
Re: One of those problems that only Carol can answer? In reply to
Lemme get this straight, before I dig into the mods. You suggest me to add the following code onto the add_record subroutine in db.cgi:

# If we've been passed in new_username, then we are adding a new user. Do
# some basic error checking and then add him into the password file.
$in{'new_username'} and do {
unless ((length($in{'new_username'}) >= 3) and (length($in{'new_username'}) <= 12) and ($in{'new_username'} =~ /^[a-zA-Z0-9]+$/)) {
$message = "Invalid username: $in{'new_username'}. Must only contain letters and numbers and be less then 12 and greater then 3 characters.";
last CASE;
}
unless ((length($in{'password'}) >= 3) and (length($in{'password'}) <= 12)) {
$message = "Invalid password: '$in{'password'}'. Must be less then 12 and greater then 3 characters.";
last CASE;
}
open (PASS, ">>$auth_pw_file") or &cgierr ("unable to open: $auth_pw_file.\nReason: $!");
if ($db_use_flock) {
flock(PASS, 2) or &cgierr("unable to get exclusive lock on $auth_pw_file.\nReason: $!");
}
my @salt_chars = ('A' .. 'Z', 0 .. 9, 'a' .. 'z', '.', '/');
my $salt = join '', @salt_chars[rand 64, rand 64];
my $encrypted = crypt($in{'password'}, $salt);
print PASS "$in{'new_username'}:$encrypted:$in{'per_view'}:$in{'per_add'}:$in{'per_del'}:$in{'per_mod'}:$in{'per_admin'}\n";
close PASS;


after the line:

print ID $in{$db_key}; # print ID $in{$db_key}; #

Then I should give the default auth_default to add and view, and set permission of auth_signup to modify and delete but not view. Apart of this I should also add a password field to the form that sends the data onto the add_record subroutine. I think that would do. What do you think about it? Am I missing something? Tank you Smile Smile Smile
Quote Reply
Re: One of those problems that only Carol can answer? In reply to
Oooops, wrote awful the last paragraph: read here

Then I should set auth_default_permissions to add and view, and set permission of auth_signup_permissions to modify, delete and view, but not add. Apart of this I should also add a password field to the form that sends the data onto the add_record subroutine. I think that would do. What do you think about it? Am I missing something? Tank you Smile Smile Smile Smile
Quote Reply
Re: One of those problems that only Carol can answer? In reply to
Pretty close. You need to do a little bit of work with it, but you're on the right track.

Be sure to change every instance of $in{'new_username'} and $in{'password'} to match the fields in your database.

I guess it is a little more than copying the code. Sorry. But I'm pleased that you found the right code to copy! Smile You said you didn't want the password to be encrypted. The lines below that are in italics are lines that encrypt the password. If you don't want the password encrypted, leave those lines out.

You'll want to do the error checking before you add the record, so add the following to sub validate_record,

Code:
# lines that are already in the script:
if ($in{'add_record'}) {
open (DB, "<$db_file_name") or &cgierr("error in validate_records. unable to open db file: $db_file_name.\nReason: $!"); if ($db_use_flock) { flock(DB, 1); }
LINE: while (<DB> ) {
(/^#/) and next LINE;
(/^\s*$/) and next LINE;
$line = $_; chomp ($line);
@data = &split_decode($line);
if ($data[$db_key_pos] eq $in{$db_key}) {
return "duplicate key error";
}
}
close DB;
 
# new lines to add
unless ((length($in{'new_username'}) >= 3) and (length($in{'new_username'}) <= 12) and ($in{'new_username'} =~ /^[a-zA-Z0-9]+$/)) {
push(@input_err, "new_username (Invalid username. Must only contain letters and numbers and be less then 12 and greater then 3 characters.)");
}
unless ((length($in{'password'}) >= 3) and (length($in{'password'}) <= 12)) {
push(@input_err, "password (Invalid password. Must be less then 12 and greater then 3 characters.)");
}
open (PASS, "<$auth_pw_file") or &cgierr ("unable to open: $auth_pw_file.\nReason: $!");
if ($db_use_flock) { flock(PASS, 1); }
while (<PASS> ) {
/^\Q$in{'new_username'}\E:/ and (push(@input_err, ("new_username already exists. Please try another.");
}
close PASS;
 
} # already in script

In sub add_record, delete the line

($auth_user_field >= 0) and ($in{$db_cols[$auth_user_field]} = $db_userid);

Then, to add info to the password file, add

Code:
# lines already in script
if ($db_key_track) {
open (ID, ">$db_id_file_name") or &cgierr("error in get_defaults. unable to open id file: $db_id_file_name.\nReason: $!");
if ($db_use_flock) {
flock(ID, 2) or &cgierr("unable to get exclusive lock on $db_id_file_name.\nReason: $!");
}
print ID $in{$db_key}; # update counter.
close ID; # automatically removes file lock
}
 
# new lines
open (PASS, ">>$auth_pw_file") or &cgierr ("unable to open: $auth_pw_file.\nReason: $!");
if ($db_use_flock) {
flock(PASS, 2) or &cgierr("unable to get exclusive lock on $auth_pw_file.\nReason: $!");
}
my @salt_chars = ('A' .. 'Z', 0 .. 9, 'a' .. 'z', '.', '/');
my $salt = join '', @salt_chars[rand 64, rand 64];
my $encrypted = crypt($in{'password'}, $salt);
$in{'password'} = $encrypted;

my $permissions = join (":", @auth_signup_permissions);
print PASS "$in{'new_username'}:$in{'password'}:$permissions\n";
close PASS;

You're going to want to be sure your users can't change their usernames and passwords when they modify their records. In html_record_form, use

Code:
|;
if ($per_add) {
print qq|[the fields for username and password|;
}
else {
print qq|
<input type="hidden" name="new_username" value=$rec{'new_username'}">
<input type="hidden" name="password" value=$rec{'password'}">
}

You still might get people who will try to change them anyway (although I'm not sure why they would).

In sub modify_record (db.cgi script) add

Code:
# lines already in script
if ($auth_user_field >= 0 and (!$per_admin or !$in{$db_cols[$auth_user_field]})) {
$in{$db_cols[$auth_user_field]} = $data[$auth_user_field];
 
# new line below
$in{'password'} = $data[2];
 
} # line already in script

Change the 2 above to the field number of the password file.

And, just to confirm the permissions, in the .cfg file set

$auth_allow_default = 1;
@auth_default_permissions = (1,1,0,0,0);
@auth_signup_permissions = (1,0,1,1,0);
$auth_modify_own = 1;

Be sure to set the $auth_user_field to the field number of your userid field.

I'll check this for syntax errors after I submit it, but I could miss something.


------------------
JPD


[This message has been edited by JPDeni (edited May 16, 1999).]
Quote Reply
Re: One of those problems that only Carol can answer? In reply to
Gosh, I'm having trouble with the add_record routine. It is adding info onto the password file but not onto the .db file. The validation goes alright, I mean, you enter wrong data and it will be rejected. I really find no error in the add_record routine, it's here. Any ideas what could be?

sub add_record {
# --------------------------------------------------------
# Adds a record to the database. First, validate_record is called
# to make sure the record is ok to add. If it is, then the record is
# encoded and added to the database and the user is sent to
# html_add_success, otherwise the user is sent to html_add_failure with
# an error message explaining why. The counter file is also updated to the
# next number.

my ($output, $status, $counter);
# Set the userid to the logged in user.
#borrada ($auth_user_field >= 0) and ($in{$db_cols[$auth_user_field]} = $db_userid);

# First we validate the record to make sure the addition is ok.
$status = &validate_record;

# We keep checking for the next available key, or until we've tried 50 times
# after which we give up.
while ($status eq "duplicate key error" and $db_key_track) {
return "duplicate key error" if ($counter++ > 50);
$in{$db_key}++;
$status = &validate_record;
}

if ($status eq "ok") {
open (DB, ">>$db_file_name") or &cgierr("error in add_record. unable to open database: $db_file_name.\nReason: $!");
if ($db_use_flock) {
flock(DB, 2) or &cgierr("unable to get exclusive lock on $db_file_name.\nReason: $!");
}
print DB &join_encode(%in);
close DB; # automatically removes file lock
# new lines
open (PASS, ">>$auth_pw_file") or &cgierr ("unable to open: $auth_pw_file.\nReason: $!");
if ($db_use_flock) {
flock(PASS, 2) or &cgierr("unable to get exclusive lock on $auth_pw_file.\nReason: $!");
}
my @salt_chars = ('A' .. 'Z', 0 .. 9, 'a' .. 'z', '.', '/');
my $salt = join '', @salt_chars[rand 64, rand 64];
my $encrypted = crypt($in{'password'}, $salt);
$in{'password'} = $encrypted;
my $permissions = join (":", @auth_signup_permissions);
print PASS "$in{'userid'}:$in{'password'}:$permissions\n";
close PASS;

if ($db_key_track) {
open (ID, ">$db_id_file_name") or &cgierr("error in get_defaults. unable to open id file: $db_id_file_name.\nReason: $!");
if ($db_use_flock) {
flock(ID, 2) or &cgierr("unable to get exclusive lock on $db_id_file_name.\nReason: $!");
}
print ID $in{$db_key}; # update counter.
close ID; # automatically removes file lock
}
&auth_logging("added record: $in{$db_key}") if ($auth_logging);
&html_add_success;
}
else {
&html_add_failure($status);
}
}


Well, the script is located in http://www.zidro.com/cgi-bin/dbman/db.cgi

For getting to the add_form I use the default user, that should be http://www.zidro.com/cgi-bin/dbman/db.cgi?uid=default&add_form=1

I can't sleep, Frown
Quote Reply
Re: One of those problems that only Carol can answer? In reply to
I was able to add a record and it did write to both files. The problem was that after adding the record, the record data didn't display. Every time I've seen that, it's been a problem with the $db_key. You might have the $db_key set to the wrong field name or you might have skipped or repeated a number somewhere in your field definition. Possibly you added or deleted a field, but didn't edit the existing records to match the new number of fields.

I noticed also a couple of problems with your select fields -- the country and the "signo." When I had a record rejected because a field wasn't filled in, those two fields were now blank. I'm not sure what the problem is, though. It could be that your countries and astrological signs are not all on one line in the .cfg file.


------------------
JPD





Quote Reply
Re: One of those problems that only Carol can answer? In reply to
I corrected the stuff about the country and "signo". The thing is I don't find mistakes in the cfg file, the $db_key seems to be setup alright. I left it as it was on the distribution file. Well, I know that the line that says

%rec = &get_record($in{$db_key});

I tried replacing ($in{$db_key}) for ($in{'ID'}) but it still did not work
when I tried to print $in{'ID'} it printed it, but when I tried to print $in{$db_key}) it did not print. This sounds weird to me.
Any clues? I left my default.cfg at http://www.zidro.com/dbman/default.cfg.txt
if you wish to see it. Tnx!
Quote Reply
Re: One of those problems that only Carol can answer? In reply to
You have been doing some good debugging. The fact that $in{$db_key} doesn't print is very interesting. Try printing just $db_key and see what you get.

At this point, that's all I can think of to do. Your .cfg file looks good.


------------------
JPD





Quote Reply
Re: One of those problems that only Carol can answer? In reply to
Well, tried that and it showed the correct field. Really strange what is happenning. Considering that I won't come up with an idea, I guess I'll just strip that piece of code away from my script. The rest of the script seems solid, I guess. I just would like to know why &html_record(&get_record($in{XXXXXX})) does not allow me to put the name of the field directly.
Quote Reply
Re: One of those problems that only Carol can answer? In reply to
The problem is not with

&html_record(&get_record($in{XXXXXX}))

The problem is that it's not recognizing $in{$db_key}.

It might not be a bad idea to take out the code and make sure everything works first. I'm not sure how you can add the new code in gradually, but you might be able to.

I've been able to get a similar thing to work for a client, so I know it can be done.

------------------
JPD