czwartek, 24 czerwca 2010

APEX 4.0 już jest !

Witam

Z wielką przyjemnością śpieszę poinformować że długo oczekiwana nowa wersja Oracle APEX jest już gotowa i możliwa do ściągnięcia. Tutaj można pobrać nową wersję.

Na szybko wymienię kilka nowości:

Websheet - to nowe podejście do tworzenia aplikacji. Teraz osoby nieznające SQL będą mogły z powodzeniem budować proste aplikacje raportujące.

AnyChart 5.1 - Nowy APEX posiada nową wersję tego wspaniałego narzędzia do tworzenia wykresów. Dodatkowo teraz jest możliwość tworzenia map :)

Nowe funkcje w Raportach interaktywnych - Dodano między innymi widok kalendarzowy, edycję danych na raporcie (inline), dodano funkcję "group by". Dodatkowo użytkownicy mogą subskrybować raporty poprzez e-mail. 

Plug-ins - Teraz każdy może tworzyć komponenty do APEX i dzięki prostym zabiegom może je udostępniać innym :)

Dynamiczne akcje - w nowym APEX nie będzie trzeba dużo się namęczyć aby stworzyć dynamiczne elementy strony. Właściwości items-ów (disable, hide itp) będa mogły zależeć od wartość w nich zawartych bądź w innych items-ach. Zmiany będzie można określać w sposób bardzo prosty bez potrzeby pisania kodu. 

To na szybko to co wydało mi się najciekawsze. Dziś czka mnie jeszcze pisanie nowej aplikacji na nowym APEX 4.0 więc pewnie w najbliższych dniach zamieszczę szczegółowe opisy nowych funkcjonalności.

Pozdrawiam
Piotr

środa, 23 czerwca 2010

Piotrek is APEX Developer Certified Expert !!

Tak tak, właśnie dzisiaj Piotrek dostał informację że zdał egzamin 1Z1-450-ENU Oracle Application Express 3.2: Developing Web Applications a co za tym idzie jest Oracle Application Express Developer Certified Expert.
W związku z tym w imieniu swoim i wszystkich czytelników Bloga składam wielkie GRATULACJE, szczególnie, że najprawdopodobniej jest pierwszym polskim APEX Developer Certified Expert.


Ten puchar nawet na czasie ; )

sobota, 19 czerwca 2010

APEX 4.0 Final Release Candidate

Właśnie znalazłem ciekawy wpis na Blogu Joel Kallman-a (Director, Software Development at Oracle America, Inc.):
"Dziś w nocy zpatchowałem apex.oracle.com do wersji 4.0.0.00.46. Jest to nasza propozycja do finalnej wersji (final release candite) oprogramowania.

Cytując za wikipedią release candidate /RC/) - "wydanie kandydujące, których może być nawet kilka, ale jeżeli nie zostanie w nim znalezione żadne istotne odstępstwo od planu wersji, zmienia się jedynie numer wersji na wyższy i uznaje wersję za stabilną."

Czyżby wersja finalna tuż tuż... : )

poniedziałek, 7 czerwca 2010

Schemat uwierzytelniania z własnymi komunikatami błędu

Witam

Po dłuższej przerwie wracam z tematem który został poruszony na ostatnich szkoleniach. Temat ten nie został rozwiązany, dlatego dzisiaj postaram się dokładnie go opisać. 

Podczas tworzenia własnych schematów uwierzytelniania często spotykanym problemem jest brak możliwości przekazywania stosownej informacji użytkownikowi. Często zdarza się, że użytkownik chcący zalogować się do naszej aplikacji nie ma do niej dostępu z innych powodów niż podanie złego hasła lub identyfikatora. Wypadałoby zatem poinformować użytkownika o problemach z jego kontem - blokada, brak płatności itp itd.  Niestety podstawowa funkcjonalność ogranicza się do stanu zero-jedynkowego. Na szczęście istnieją metody na zmianę stanu rzeczy poprzez prostą edycję funkcji uwierzytelniania i procesu Login na stronie Logowania. 

Tyle tytułem wstępu. Teraz do rzeczy.

Zakładam, że aplikacja posiada własny schemat uwierzytelniania, który pracuje na funkcji custom_auth. Funkcję uwierzytelniającą umieszczono poniżej:  

create or replace
FUNCTION CUSTOM_AUTH (p_username in number, p_password in VARCHAR2)
return BOOLEAN
is
l_stored_password varchar2(4000);
l_count number;
begin
select count(*) into l_count
from users where upper(usr_name) = upper(p_username);

IF l_count > 0 then
select usr_password into l_stored_password
from users where upper(usr_name) = upper(p_username);
if p_password = l_stored_password then
return TRUE;
else
return FALSE;
end if;
ELSE
return FALSE;
END IF;

end;

Funkcja ta sprawdza czy dany użytkownik istnieje w tabeli users a następnie konfrontuje hasło w bazie danych z hasłem podanym podczas logowania. W zależności od tego czy hasło jest zgodne czy tez nie zostaje zwrócona wartość TRUE lub FALSE. Na podstawie tej wartości APEX przedstawi naszemu użytkownikowi informację zawartą w Text Message 'INVALID_CREDENTIALS'. Czyli coś w rodzaju "Nieprawidłowe hasło. Spróbuj ponownie." 

Wszystko fajnie ale co jeśli wprowadzimy możliwość blokowania konta. Jeśli użytkownik wpisze 3 razy nieprawidłowe hasło to jego konto zostanie zablokowane. Zmieniamy więc funkcję tak aby przybrała następujący kształt:

create or replace
FUNCTION CUSTOM_AUTH (p_username in number, p_password in VARCHAR2)
return BOOLEAN
is
l_stored_password varchar2(4000);
l_count number;
blockX number;
begin

select count(*) into l_count
from users where upper(usr_name) = upper(p_username);

IF l_count > 0 then

select usr_password, usr_block into l_stored_password, blockX
from users where upper(usr_name) = upper(p_username);

if blockX <1 then
return FALSE;
end if;

if p_password = l_stored_password then
update users set usr_block=3
where upper(usr_name) = upper(p_username);
return TRUE;
else
update users set usr_block=usr_block-1
where upper(usr_name) = upper(p_username);
return FALSE;
end if;
ELSE
return FALSE;
END IF;

end;

Niby ok, ale użytkownik nie będzie wiedział o zablokowaniu konta. Co zatem należy zrobić aby stosowna informacja ukazała się na ekranie ?

Cała procedura składa się z kilku punktów, które kolejno polegają na dodaniu itemsa aplikacyjnego, zmiany procesu na stronie Login i 

1. Dodaj Item aplikacyjny AUTH_MESSAGE. W itemsie tym będzie przetrzymywana informacja dla użytkownika. Ważne aby zastrzec możliwość ustawiania wartości tej zmiennej z przeglądarki. Zaznacz opcję "Restricted" z listy Session State Protection.

2. Na stronie logowania dodaj nowy region typu HTML. Jako template regionu wybierz "No Template" natomiast w źródle wpisz "&AUTH_MESSAGE." Natomiast jako kondycje wyświetlania wybierz "Value of Item in Expression 1 Is NOT NULL" i wpisz w polu Expression1 wartość "AUTH_MESSAGE".  Region ten będzie odpowiadał za wyświetlanie informacji użytkownikowi. Kondycja zadba o to aby pokazywał się tylko w momencie gdy jest jakaś informacja do przekazania :)

3. Zmień Proces Login na stronie logowania na następujący:

declare
bresult BOOLEAN := FALSE;
begin


bresult := DBE_CUSTOM_AUTH(:P101_USERNAME,:P101_PASSWORD);

if bresult then

wwv_flow_custom_auth_std.post_login(
P_UNAME => :P101_USERNAME,
P_PASSWORD => :P101_PASSWORD,
P_SESSION_ID => v('APP_SESSION'),
P_FLOW_PAGE => :APP_ID||':'||nvl(:P101_PAGE_ID,'2')
);

else

owa_util.redirect_url('f?p=&APP_ID.:101:&SESSION.');
end if;
end;

W procesie tym na początku sprawdzane jest czy użytkownik podał prawidłowe dane do logowania. Jeśli tak to zostanie uruchomiona standardowa procedura logowania. Jeśli nie to użytkownik zostanie przekierowany na stronę 101 (logowania).

4. Na końcu trzeba tylko zająć się zmienną AUTH_MESSAGE. Wypełnianiem tej wartości zajmie się funkcja uwierzytelniająca. 

create or replace
FUNCTION CUSTOM_AUTH (p_username in number, p_password in VARCHAR2)
return BOOLEAN
is
l_stored_password varchar2(4000);
l_count number;
blockX number;
begin
select count(*) into l_count
from users where upper(usr_name) = upper(p_username);

IF l_count > 0 then
select usr_password, usr_block into l_stored_password, blockX
from users where upper(usr_name) = upper(p_username);

if blockX <1 then
apex_util.set_session_state('LOGIN_MESSAGE','Twoje konto zostało zablokowane.
Skontaktuj się z administratorem !');
return FALSE;
end if;

if p_password = l_stored_password then
update users set usr_block=3
where upper(usr_name) = upper(p_username);
return TRUE;
else
update users set usr_block=usr_block-1
where upper(usr_name) = upper(p_username);
apex_util.set_session_state('LOGIN_MESSAGE','Nieprawidowe Haslo lub id !!!');
return FALSE;
end if;
ELSE

apex_util.set_session_state('LOGIN_MESSAGE','Nieprawidowe Haslo lub id !!!');
return FALSE;
END IF;

end;

W funkcji zastosowano fukncje APEX Api która ustawia wartość podanego Itemsa aplikcaji. W tym przypadku jest to Items AUTH_MESSAGE. 

Wystarczy zatem zapisać funkcję aby sprawdzić rezultat.

Na końcu można się pokusić o zmianę wyglądu naszego komunikatu tak aby był identyczny z tym w Template strony. Dla mojego Tematu Graficznego będzie to wyglądało tak:

<div class="t16notification" id="MESSAGE">
<img src="#IMAGE_PREFIX#delete.gif" onclick="$x_Remove('MESSAGE')" style="float:right;" class="pb" alt="" />
&AUTH_MESSAGE.
</div>

Gotowe. Teraz można dodawać inne opcje które pozwolą na poinformowanie uzytkownika o wszystkim co nas trapi i uwiera. Ba! Można pokusić się o personalizację komunikatu :) jak nizej:

sobota, 5 czerwca 2010

APEX.oracle.com zmigrowany do APEX 4.0

Właśnie dziś największa na świecie instancja APEX (apex.oracle.com) została zmigrowana do wersji 4.0 Jest to kolejny krok ku premierze wersji produkcyjnej.



Co to oznacza dla nas, czyli zwykłych użytkowników apex-a i instancji apex.oracle.com ? Mając workspace w apex.oracle.com można śmiało tworzyć aplikacje w wersji 4.0 i nawet jak będą wprowadzane dodatkowe zmiany przed oficjalną premierą to nie powinniśmy już się obawiać o kompatybilność z wersją ostateczną.

wtorek, 1 czerwca 2010

Checkbox - zaznaczanie całej kolumny

Czy nie mieliście czasem potrzeby dodania ręcznie w nagłówku kolumny raportu checkboxa po zaznaczeniu, którego wszystkie pozostałe chceckboxy w kolumnie też się zaznaczą ? Chodzi o identyczną funkcjonalność jaka jest tworzona podczas budowy tabular formsa dla akcji Delete.

Żeby to wykonać należy wejść do sekcji Report Attributes a następnie w nagłówku kolumny raportu (w kolumnie Heading) wprowadzić następujący kod:

<input onclick="$f_CheckFirstColumn(this)" type="Checkbox">

Jeżeli pole w kolumnie Heading jest nieaktywne należy powyżej zaznaczyć Heading type: Custom. Jeżeli zamiast Checkboxa zobaczymy wklejony przed chwilą kod html należy zmienić w danej kolumnie Column Attributes/Display As na Standard Report Column.

Po tym małym zabiegu mamy w nagłówku checkboxa z podłączoną do niego funkcją javascriptową wywołującą akcję zaznaczenia pozostałych checkboxów w kolumnie : )