mirror of
https://github.com/abapGit/abapGit.git
synced 2025-05-01 12:20:51 +08:00
Refactor page diff: Introduce subclass for patch (#3283)
* Introduce zcl_abapgit_gui_page_patch as subclass of zcl_abapgit_gui_page_diff introduce pop-method on GUI stack fix linter + raising exception when gui stack emp introduce zcl_abapgit_gui_page_patch more add fix linter remove go back to patch after commit fix linter remove bookmark for stage page remove pop src/ui/core/zcl_abapgit_gui.clas.abap src/zcl_abapgit_repo_online.clas.abap * refactor: move more logic to render_line_split_ro * refactor move logic to render_diff_head_after_stat * add logic to render_table_head_non_unified * extract render_table_head_unified * extract of is_patch_possible calculation * fix linter * move hotkey to patch * refactor and rename to get_normalized_fname_with_p Co-authored-by: Lars Hvam <larshp@hotmail.com>
This commit is contained in:
parent
7f6fd532ee
commit
803ca23176
File diff suppressed because it is too large
Load Diff
|
@ -1,113 +0,0 @@
|
|||
*"* use this source file for your ABAP unit test classes
|
||||
|
||||
CLASS ltcl_patch DEFINITION FINAL FOR TESTING
|
||||
DURATION SHORT
|
||||
RISK LEVEL HARMLESS.
|
||||
|
||||
PRIVATE SECTION.
|
||||
METHODS:
|
||||
get_patch_data_add FOR TESTING RAISING cx_static_check,
|
||||
get_patch_data_remove FOR TESTING RAISING cx_static_check,
|
||||
invalid_patch_missing_file FOR TESTING RAISING cx_static_check,
|
||||
invalid_patch_missing_index FOR TESTING RAISING cx_static_check.
|
||||
|
||||
ENDCLASS.
|
||||
|
||||
CLASS zcl_abapgit_gui_page_diff DEFINITION LOCAL FRIENDS ltcl_patch.
|
||||
|
||||
CLASS ltcl_patch IMPLEMENTATION.
|
||||
|
||||
METHOD get_patch_data_add.
|
||||
|
||||
DATA: lv_file_name TYPE string,
|
||||
lv_line_index TYPE string.
|
||||
|
||||
zcl_abapgit_gui_page_diff=>get_patch_data(
|
||||
EXPORTING
|
||||
iv_patch = |patch_line_zcl_test_git_add_p.clas.abap_0_19|
|
||||
IMPORTING
|
||||
ev_filename = lv_file_name
|
||||
ev_line_index = lv_line_index ).
|
||||
|
||||
cl_abap_unit_assert=>assert_equals(
|
||||
exp = |zcl_test_git_add_p.clas.abap|
|
||||
act = lv_file_name ).
|
||||
|
||||
cl_abap_unit_assert=>assert_equals(
|
||||
exp = |19|
|
||||
act = lv_line_index ).
|
||||
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD get_patch_data_remove.
|
||||
|
||||
DATA: lv_file_name TYPE string,
|
||||
lv_line_index TYPE string.
|
||||
|
||||
zcl_abapgit_gui_page_diff=>get_patch_data(
|
||||
EXPORTING
|
||||
iv_patch = |patch_line_ztest_patch.prog.abap_0_39|
|
||||
IMPORTING
|
||||
ev_filename = lv_file_name
|
||||
ev_line_index = lv_line_index ).
|
||||
|
||||
cl_abap_unit_assert=>assert_equals(
|
||||
exp = |ztest_patch.prog.abap|
|
||||
act = lv_file_name ).
|
||||
|
||||
cl_abap_unit_assert=>assert_equals(
|
||||
exp = |39|
|
||||
act = lv_line_index ).
|
||||
|
||||
ENDMETHOD.
|
||||
|
||||
|
||||
METHOD invalid_patch_missing_file.
|
||||
|
||||
DATA: lv_file_name TYPE string,
|
||||
lv_line_index TYPE string,
|
||||
lx_error TYPE REF TO zcx_abapgit_exception.
|
||||
|
||||
TRY.
|
||||
zcl_abapgit_gui_page_diff=>get_patch_data(
|
||||
EXPORTING
|
||||
iv_patch = |patch_39|
|
||||
IMPORTING
|
||||
ev_filename = lv_file_name
|
||||
ev_line_index = lv_line_index ).
|
||||
|
||||
cl_abap_unit_assert=>fail( ).
|
||||
|
||||
CATCH zcx_abapgit_exception INTO lx_error.
|
||||
cl_abap_unit_assert=>assert_equals(
|
||||
exp = |Invalid patch|
|
||||
act = lx_error->get_text( ) ).
|
||||
ENDTRY.
|
||||
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD invalid_patch_missing_index.
|
||||
|
||||
DATA: lv_file_name TYPE string,
|
||||
lv_line_index TYPE string,
|
||||
lx_error TYPE REF TO zcx_abapgit_exception.
|
||||
|
||||
TRY.
|
||||
zcl_abapgit_gui_page_diff=>get_patch_data(
|
||||
EXPORTING
|
||||
iv_patch = |patch_ztest_patch.prog.abap|
|
||||
IMPORTING
|
||||
ev_filename = lv_file_name
|
||||
ev_line_index = lv_line_index ).
|
||||
|
||||
cl_abap_unit_assert=>fail( ).
|
||||
|
||||
CATCH zcx_abapgit_exception INTO lx_error.
|
||||
cl_abap_unit_assert=>assert_equals(
|
||||
exp = |Invalid patch|
|
||||
act = lx_error->get_text( ) ).
|
||||
ENDTRY.
|
||||
|
||||
ENDMETHOD.
|
||||
|
||||
ENDCLASS.
|
|
@ -10,7 +10,6 @@
|
|||
<CLSCCINCL>X</CLSCCINCL>
|
||||
<FIXPT>X</FIXPT>
|
||||
<UNICODE>X</UNICODE>
|
||||
<WITH_UNIT_TESTS>X</WITH_UNIT_TESTS>
|
||||
</VSEOCLASS>
|
||||
</asx:values>
|
||||
</asx:abap>
|
||||
|
|
791
src/ui/zcl_abapgit_gui_page_patch.clas.abap
Normal file
791
src/ui/zcl_abapgit_gui_page_patch.clas.abap
Normal file
|
@ -0,0 +1,791 @@
|
|||
CLASS zcl_abapgit_gui_page_patch DEFINITION
|
||||
PUBLIC
|
||||
INHERITING FROM zcl_abapgit_gui_page_diff
|
||||
CREATE PUBLIC .
|
||||
|
||||
PUBLIC SECTION.
|
||||
INTERFACES:
|
||||
zif_abapgit_gui_page_hotkey.
|
||||
|
||||
METHODS:
|
||||
constructor
|
||||
IMPORTING
|
||||
iv_key TYPE zif_abapgit_persistence=>ty_repo-key
|
||||
is_file TYPE zif_abapgit_definitions=>ty_file OPTIONAL
|
||||
is_object TYPE zif_abapgit_definitions=>ty_item OPTIONAL
|
||||
iv_patch_mode TYPE abap_bool OPTIONAL
|
||||
RAISING
|
||||
zcx_abapgit_exception,
|
||||
|
||||
zif_abapgit_gui_event_handler~on_event REDEFINITION.
|
||||
|
||||
CLASS-METHODS:
|
||||
get_patch_data
|
||||
IMPORTING
|
||||
iv_patch TYPE string
|
||||
EXPORTING
|
||||
ev_filename TYPE string
|
||||
ev_line_index TYPE string
|
||||
RAISING
|
||||
zcx_abapgit_exception.
|
||||
|
||||
PROTECTED SECTION.
|
||||
METHODS:
|
||||
render_content REDEFINITION,
|
||||
scripts REDEFINITION,
|
||||
add_menu_end REDEFINITION,
|
||||
add_menu_begin REDEFINITION,
|
||||
render_table_head_non_unified REDEFINITION,
|
||||
render_beacon_begin_of_row REDEFINITION,
|
||||
render_diff_head_after_state REDEFINITION,
|
||||
insert_nav REDEFINITION,
|
||||
render_line_split_row REDEFINITION.
|
||||
|
||||
|
||||
PRIVATE SECTION.
|
||||
TYPES:
|
||||
ty_patch_action TYPE string .
|
||||
|
||||
CONSTANTS:
|
||||
BEGIN OF c_actions,
|
||||
stage TYPE string VALUE 'patch_stage',
|
||||
refresh TYPE string VALUE 'patch_refresh',
|
||||
refresh_local TYPE string VALUE 'patch_refresh_local',
|
||||
refresh_local_object TYPE string VALUE 'patch_refresh_local_object',
|
||||
END OF c_actions,
|
||||
BEGIN OF c_patch_action,
|
||||
add TYPE ty_patch_action VALUE 'add',
|
||||
remove TYPE ty_patch_action VALUE 'remove',
|
||||
END OF c_patch_action .
|
||||
|
||||
DATA:
|
||||
mo_stage TYPE REF TO zcl_abapgit_stage,
|
||||
mv_section_count TYPE i,
|
||||
mv_pushed TYPE abap_bool.
|
||||
|
||||
METHODS:
|
||||
render_patch
|
||||
IMPORTING
|
||||
io_html TYPE REF TO zcl_abapgit_html
|
||||
iv_filename TYPE string
|
||||
is_diff_line TYPE zif_abapgit_definitions=>ty_diff
|
||||
iv_fstate TYPE char1
|
||||
iv_index TYPE sy-tabix
|
||||
RAISING
|
||||
zcx_abapgit_exception,
|
||||
|
||||
render_patch_head
|
||||
IMPORTING
|
||||
io_html TYPE REF TO zcl_abapgit_html
|
||||
is_diff TYPE ty_file_diff,
|
||||
|
||||
start_staging
|
||||
IMPORTING
|
||||
it_postdata TYPE cnht_post_data_tab
|
||||
RAISING
|
||||
zcx_abapgit_exception,
|
||||
|
||||
apply_patch_from_form_fields
|
||||
IMPORTING
|
||||
it_postdata TYPE cnht_post_data_tab
|
||||
RAISING
|
||||
zcx_abapgit_exception,
|
||||
|
||||
restore_patch_flags
|
||||
IMPORTING
|
||||
it_diff_files_old TYPE tt_file_diff
|
||||
RAISING
|
||||
zcx_abapgit_exception,
|
||||
|
||||
add_to_stage
|
||||
RAISING
|
||||
zcx_abapgit_exception,
|
||||
|
||||
refresh
|
||||
IMPORTING
|
||||
iv_action TYPE clike
|
||||
RAISING
|
||||
zcx_abapgit_exception,
|
||||
|
||||
refresh_full
|
||||
RAISING
|
||||
zcx_abapgit_exception,
|
||||
|
||||
refresh_local
|
||||
RAISING
|
||||
zcx_abapgit_exception,
|
||||
|
||||
refresh_local_object
|
||||
IMPORTING
|
||||
iv_action TYPE clike
|
||||
RAISING
|
||||
zcx_abapgit_exception,
|
||||
|
||||
apply_patch_all
|
||||
IMPORTING
|
||||
iv_patch TYPE string
|
||||
iv_patch_flag TYPE abap_bool
|
||||
RAISING
|
||||
zcx_abapgit_exception,
|
||||
|
||||
are_all_lines_patched
|
||||
IMPORTING
|
||||
it_diff TYPE zif_abapgit_definitions=>ty_diffs_tt
|
||||
RETURNING
|
||||
VALUE(rv_are_all_lines_patched) TYPE abap_bool,
|
||||
|
||||
apply_patch_for
|
||||
IMPORTING
|
||||
iv_filename TYPE string
|
||||
iv_line_index TYPE string
|
||||
iv_patch_flag TYPE abap_bool
|
||||
RAISING
|
||||
zcx_abapgit_exception,
|
||||
|
||||
get_diff_object
|
||||
IMPORTING
|
||||
iv_filename TYPE string
|
||||
RETURNING
|
||||
VALUE(ro_diff) TYPE REF TO zcl_abapgit_diff
|
||||
RAISING
|
||||
zcx_abapgit_exception,
|
||||
|
||||
get_diff_line
|
||||
IMPORTING
|
||||
io_diff TYPE REF TO zcl_abapgit_diff
|
||||
iv_line_index TYPE string
|
||||
RETURNING
|
||||
VALUE(rs_diff) TYPE zif_abapgit_definitions=>ty_diff
|
||||
RAISING
|
||||
zcx_abapgit_exception,
|
||||
|
||||
is_every_changed_line_patched
|
||||
RETURNING
|
||||
VALUE(rv_everything_patched) TYPE abap_bool,
|
||||
|
||||
is_patch_line_possible
|
||||
IMPORTING
|
||||
is_diff_line TYPE zif_abapgit_definitions=>ty_diff
|
||||
iv_fstate TYPE char1
|
||||
RETURNING
|
||||
VALUE(rv_is_patch_line_possible) TYPE abap_bool.
|
||||
|
||||
|
||||
|
||||
ENDCLASS.
|
||||
|
||||
|
||||
|
||||
CLASS zcl_abapgit_gui_page_patch IMPLEMENTATION.
|
||||
|
||||
METHOD constructor.
|
||||
|
||||
super->constructor(
|
||||
iv_key = iv_key
|
||||
is_file = is_file
|
||||
is_object = is_object ).
|
||||
|
||||
" While patching we always want to be in split mode
|
||||
CLEAR: mv_unified.
|
||||
CREATE OBJECT mo_stage.
|
||||
|
||||
ms_control-page_menu = build_menu( ).
|
||||
|
||||
ENDMETHOD.
|
||||
|
||||
|
||||
METHOD add_menu_end.
|
||||
|
||||
io_menu->add( iv_txt = 'Stage'
|
||||
iv_act = c_actions-stage
|
||||
iv_id = 'stage'
|
||||
iv_typ = zif_abapgit_html=>c_action_type-dummy
|
||||
) ##NO_TEXT.
|
||||
|
||||
ENDMETHOD.
|
||||
|
||||
|
||||
METHOD zif_abapgit_gui_event_handler~on_event.
|
||||
|
||||
CASE iv_action.
|
||||
WHEN c_actions-stage.
|
||||
|
||||
start_staging( it_postdata ).
|
||||
|
||||
CREATE OBJECT ei_page TYPE zcl_abapgit_gui_page_commit
|
||||
EXPORTING
|
||||
io_repo = mo_repo
|
||||
io_stage = mo_stage.
|
||||
ev_state = zcl_abapgit_gui=>c_event_state-new_page.
|
||||
|
||||
WHEN OTHERS.
|
||||
|
||||
FIND FIRST OCCURRENCE OF REGEX |^{ c_actions-refresh }| IN iv_action.
|
||||
IF sy-subrc = 0.
|
||||
|
||||
apply_patch_from_form_fields( it_postdata ).
|
||||
refresh( iv_action ).
|
||||
ev_state = zcl_abapgit_gui=>c_event_state-re_render.
|
||||
|
||||
ELSE.
|
||||
|
||||
super->zif_abapgit_gui_event_handler~on_event(
|
||||
EXPORTING
|
||||
iv_action = iv_action
|
||||
iv_prev_page = iv_prev_page
|
||||
iv_getdata = iv_getdata
|
||||
it_postdata = it_postdata
|
||||
IMPORTING
|
||||
ei_page = ei_page
|
||||
ev_state = ev_state ).
|
||||
|
||||
ENDIF.
|
||||
|
||||
ENDCASE.
|
||||
|
||||
ENDMETHOD.
|
||||
|
||||
|
||||
METHOD start_staging.
|
||||
|
||||
apply_patch_from_form_fields( it_postdata ).
|
||||
add_to_stage( ).
|
||||
|
||||
ENDMETHOD.
|
||||
|
||||
|
||||
METHOD apply_patch_from_form_fields.
|
||||
|
||||
DATA: lv_string TYPE string,
|
||||
lt_fields TYPE tihttpnvp,
|
||||
lv_add TYPE string,
|
||||
lv_remove TYPE string.
|
||||
|
||||
CONCATENATE LINES OF it_postdata INTO lv_string.
|
||||
lt_fields = zcl_abapgit_html_action_utils=>parse_fields( lv_string ).
|
||||
|
||||
zcl_abapgit_html_action_utils=>get_field( EXPORTING iv_name = c_patch_action-add
|
||||
it_field = lt_fields
|
||||
CHANGING cg_field = lv_add ).
|
||||
|
||||
zcl_abapgit_html_action_utils=>get_field( EXPORTING iv_name = c_patch_action-remove
|
||||
it_field = lt_fields
|
||||
CHANGING cg_field = lv_remove ).
|
||||
|
||||
apply_patch_all( iv_patch = lv_add
|
||||
iv_patch_flag = abap_true ).
|
||||
|
||||
apply_patch_all( iv_patch = lv_remove
|
||||
iv_patch_flag = abap_false ).
|
||||
|
||||
ENDMETHOD.
|
||||
|
||||
|
||||
METHOD restore_patch_flags.
|
||||
|
||||
DATA:
|
||||
lt_diff_old TYPE zif_abapgit_definitions=>ty_diffs_tt.
|
||||
|
||||
FIELD-SYMBOLS:
|
||||
<ls_diff_file> TYPE ty_file_diff,
|
||||
<ls_diff_file_old> TYPE ty_file_diff,
|
||||
<ls_diff_old> TYPE zif_abapgit_definitions=>ty_diff.
|
||||
|
||||
LOOP AT mt_diff_files ASSIGNING <ls_diff_file>.
|
||||
|
||||
READ TABLE it_diff_files_old ASSIGNING <ls_diff_file_old>
|
||||
WITH KEY secondary
|
||||
COMPONENTS path = <ls_diff_file>-path
|
||||
filename = <ls_diff_file>-filename.
|
||||
IF sy-subrc <> 0.
|
||||
CONTINUE. " e.g. new objects
|
||||
ENDIF.
|
||||
|
||||
lt_diff_old = <ls_diff_file_old>-o_diff->get( ).
|
||||
|
||||
LOOP AT lt_diff_old ASSIGNING <ls_diff_old>
|
||||
WHERE patch_flag = abap_true.
|
||||
|
||||
<ls_diff_file>-o_diff->set_patch_by_old_diff(
|
||||
is_diff_old = <ls_diff_old>
|
||||
iv_patch_flag = abap_true ).
|
||||
|
||||
ENDLOOP.
|
||||
|
||||
ENDLOOP.
|
||||
|
||||
ENDMETHOD.
|
||||
|
||||
|
||||
METHOD add_to_stage.
|
||||
|
||||
DATA: lt_diff TYPE zif_abapgit_definitions=>ty_diffs_tt,
|
||||
lv_something_patched TYPE abap_bool,
|
||||
ls_status TYPE zif_abapgit_definitions=>ty_result,
|
||||
lv_patch TYPE xstring,
|
||||
lo_git_add_patch TYPE REF TO zcl_abapgit_git_add_patch.
|
||||
|
||||
FIELD-SYMBOLS: <ls_diff_file> TYPE ty_file_diff.
|
||||
|
||||
LOOP AT mt_diff_files ASSIGNING <ls_diff_file>.
|
||||
|
||||
IF <ls_diff_file>-o_diff IS NOT BOUND.
|
||||
" When we deal with binary files we don't have a diff object.
|
||||
" There's nothing to do because they cannot be patched
|
||||
CONTINUE.
|
||||
ENDIF.
|
||||
|
||||
lt_diff = <ls_diff_file>-o_diff->get( ).
|
||||
|
||||
READ TABLE lt_diff TRANSPORTING NO FIELDS
|
||||
WITH KEY patch_flag = abap_true.
|
||||
CHECK sy-subrc = 0.
|
||||
|
||||
lv_something_patched = abap_true.
|
||||
|
||||
CREATE OBJECT lo_git_add_patch
|
||||
EXPORTING
|
||||
it_diff = <ls_diff_file>-o_diff->get( ).
|
||||
|
||||
lv_patch = lo_git_add_patch->get_patch_binary( ).
|
||||
|
||||
IF <ls_diff_file>-lstate = 'D' AND are_all_lines_patched( lt_diff ) = abap_true.
|
||||
|
||||
ls_status-lstate = zif_abapgit_definitions=>c_state-deleted.
|
||||
mo_stage->rm(
|
||||
iv_path = <ls_diff_file>-path
|
||||
is_status = ls_status
|
||||
iv_filename = <ls_diff_file>-filename ).
|
||||
|
||||
ELSE.
|
||||
|
||||
IF <ls_diff_file>-lstate = 'A' AND are_all_lines_patched( lt_diff ) = abap_true.
|
||||
ls_status-lstate = zif_abapgit_definitions=>c_state-added.
|
||||
ELSE.
|
||||
ls_status-lstate = zif_abapgit_definitions=>c_state-modified.
|
||||
ENDIF.
|
||||
|
||||
mo_stage->add(
|
||||
iv_path = <ls_diff_file>-path
|
||||
iv_filename = <ls_diff_file>-filename
|
||||
is_status = ls_status
|
||||
iv_data = lv_patch ).
|
||||
|
||||
ENDIF.
|
||||
|
||||
ENDLOOP.
|
||||
|
||||
IF lv_something_patched = abap_false.
|
||||
zcx_abapgit_exception=>raise( |Nothing added| ).
|
||||
ENDIF.
|
||||
|
||||
ENDMETHOD.
|
||||
|
||||
|
||||
METHOD refresh.
|
||||
|
||||
DATA:
|
||||
lt_diff_files_old TYPE tt_file_diff.
|
||||
|
||||
lt_diff_files_old = mt_diff_files.
|
||||
|
||||
CASE iv_action.
|
||||
WHEN c_actions-refresh.
|
||||
refresh_full( ).
|
||||
WHEN c_actions-refresh_local.
|
||||
refresh_local( ).
|
||||
WHEN OTHERS.
|
||||
refresh_local_object( iv_action ).
|
||||
ENDCASE.
|
||||
|
||||
calculate_diff( ).
|
||||
restore_patch_flags( lt_diff_files_old ).
|
||||
|
||||
ENDMETHOD.
|
||||
|
||||
|
||||
METHOD refresh_full.
|
||||
mo_repo->refresh( abap_true ).
|
||||
ENDMETHOD.
|
||||
|
||||
|
||||
METHOD refresh_local.
|
||||
mo_repo->refresh_local_objects( ).
|
||||
ENDMETHOD.
|
||||
|
||||
|
||||
METHOD refresh_local_object.
|
||||
|
||||
DATA:
|
||||
lv_regex TYPE string,
|
||||
lv_obj_type TYPE tadir-object,
|
||||
lv_obj_name TYPE tadir-obj_name.
|
||||
|
||||
lv_regex = c_actions-refresh_local_object && `_(\w{4})_(.*)`.
|
||||
|
||||
FIND FIRST OCCURRENCE OF REGEX lv_regex
|
||||
IN iv_action
|
||||
SUBMATCHES lv_obj_type lv_obj_name.
|
||||
|
||||
IF sy-subrc = 0.
|
||||
mo_repo->refresh_local_object(
|
||||
iv_obj_type = lv_obj_type
|
||||
iv_obj_name = lv_obj_name ).
|
||||
ELSE.
|
||||
zcx_abapgit_exception=>raise( |Invalid refresh action { iv_action }| ).
|
||||
ENDIF.
|
||||
|
||||
ENDMETHOD.
|
||||
|
||||
|
||||
METHOD apply_patch_all.
|
||||
|
||||
DATA: lv_filename TYPE string,
|
||||
lt_patch TYPE string_table,
|
||||
lv_line_index TYPE string.
|
||||
|
||||
FIELD-SYMBOLS: <lv_patch> TYPE LINE OF string_table.
|
||||
|
||||
SPLIT iv_patch AT ',' INTO TABLE lt_patch.
|
||||
|
||||
LOOP AT lt_patch ASSIGNING <lv_patch>.
|
||||
|
||||
get_patch_data(
|
||||
EXPORTING
|
||||
iv_patch = <lv_patch>
|
||||
IMPORTING
|
||||
ev_filename = lv_filename
|
||||
ev_line_index = lv_line_index ).
|
||||
|
||||
apply_patch_for( iv_filename = lv_filename
|
||||
iv_line_index = lv_line_index
|
||||
iv_patch_flag = iv_patch_flag ).
|
||||
|
||||
ENDLOOP.
|
||||
|
||||
ENDMETHOD.
|
||||
|
||||
|
||||
METHOD are_all_lines_patched.
|
||||
|
||||
DATA: lv_patch_count TYPE i.
|
||||
|
||||
FIELD-SYMBOLS: <ls_diff> TYPE zif_abapgit_definitions=>ty_diff.
|
||||
|
||||
LOOP AT it_diff ASSIGNING <ls_diff>
|
||||
WHERE patch_flag = abap_true.
|
||||
lv_patch_count = lv_patch_count + 1.
|
||||
ENDLOOP.
|
||||
|
||||
rv_are_all_lines_patched = boolc( lv_patch_count = lines( it_diff ) ).
|
||||
|
||||
ENDMETHOD.
|
||||
|
||||
|
||||
METHOD get_patch_data.
|
||||
|
||||
DATA: lv_section TYPE string.
|
||||
|
||||
CLEAR: ev_filename, ev_line_index.
|
||||
|
||||
FIND FIRST OCCURRENCE OF REGEX `patch_line` && `_(.*)_(\d)+_(\d+)`
|
||||
IN iv_patch
|
||||
SUBMATCHES ev_filename lv_section ev_line_index.
|
||||
IF sy-subrc <> 0.
|
||||
zcx_abapgit_exception=>raise( |Invalid patch| ).
|
||||
ENDIF.
|
||||
|
||||
ENDMETHOD.
|
||||
|
||||
|
||||
METHOD apply_patch_for.
|
||||
|
||||
DATA: lo_diff TYPE REF TO zcl_abapgit_diff,
|
||||
ls_diff_line TYPE zif_abapgit_definitions=>ty_diff,
|
||||
lv_line TYPE i.
|
||||
|
||||
lo_diff = get_diff_object( iv_filename ).
|
||||
|
||||
ls_diff_line = get_diff_line( io_diff = lo_diff
|
||||
iv_line_index = iv_line_index ).
|
||||
|
||||
CASE ls_diff_line-result.
|
||||
WHEN zif_abapgit_definitions=>c_diff-update
|
||||
OR zif_abapgit_definitions=>c_diff-insert.
|
||||
|
||||
lv_line = ls_diff_line-new_num.
|
||||
|
||||
lo_diff->set_patch_new( iv_line_new = lv_line
|
||||
iv_patch_flag = iv_patch_flag ).
|
||||
|
||||
WHEN zif_abapgit_definitions=>c_diff-delete.
|
||||
|
||||
lv_line = ls_diff_line-old_num.
|
||||
|
||||
lo_diff->set_patch_old( iv_line_old = lv_line
|
||||
iv_patch_flag = iv_patch_flag ).
|
||||
|
||||
ENDCASE.
|
||||
|
||||
ENDMETHOD.
|
||||
|
||||
|
||||
METHOD get_diff_object.
|
||||
|
||||
FIELD-SYMBOLS: <ls_diff_file> LIKE LINE OF mt_diff_files.
|
||||
|
||||
LOOP AT mt_diff_files ASSIGNING <ls_diff_file>.
|
||||
IF get_normalized_fname_with_path( <ls_diff_file> ) = iv_filename.
|
||||
ro_diff = <ls_diff_file>-o_diff.
|
||||
EXIT.
|
||||
ENDIF.
|
||||
ENDLOOP.
|
||||
|
||||
IF ro_diff IS NOT BOUND.
|
||||
zcx_abapgit_exception=>raise( |Invalid filename { iv_filename }| ).
|
||||
ENDIF.
|
||||
|
||||
ENDMETHOD.
|
||||
|
||||
|
||||
METHOD get_diff_line.
|
||||
|
||||
DATA: lt_diff TYPE zif_abapgit_definitions=>ty_diffs_tt,
|
||||
lv_line_index TYPE sy-tabix.
|
||||
|
||||
|
||||
lv_line_index = iv_line_index.
|
||||
lt_diff = io_diff->get( ).
|
||||
|
||||
READ TABLE lt_diff INTO rs_diff
|
||||
INDEX lv_line_index.
|
||||
IF sy-subrc <> 0.
|
||||
zcx_abapgit_exception=>raise( |Invalid line index { lv_line_index }| ).
|
||||
ENDIF.
|
||||
|
||||
ENDMETHOD.
|
||||
|
||||
|
||||
METHOD add_menu_begin.
|
||||
|
||||
io_menu->add(
|
||||
iv_txt = |Refresh local|
|
||||
iv_typ = zif_abapgit_html=>c_action_type-dummy
|
||||
iv_act = c_actions-refresh_local
|
||||
iv_id = c_actions-refresh_local
|
||||
iv_title = |Refresh all local objects, without refreshing the remote| ).
|
||||
|
||||
io_menu->add(
|
||||
iv_txt = |Refresh|
|
||||
iv_typ = zif_abapgit_html=>c_action_type-dummy
|
||||
iv_act = c_actions-refresh
|
||||
iv_id = c_actions-refresh
|
||||
iv_title = |Complete refresh of all objects, local and remote| ).
|
||||
|
||||
ENDMETHOD.
|
||||
|
||||
|
||||
METHOD scripts.
|
||||
|
||||
ro_html = super->scripts( ).
|
||||
|
||||
ro_html->add( 'preparePatch();' ).
|
||||
ro_html->add( 'registerStagePatch();' ).
|
||||
|
||||
ENDMETHOD.
|
||||
|
||||
|
||||
METHOD render_table_head_non_unified.
|
||||
|
||||
render_patch_head( io_html = io_html
|
||||
is_diff = is_diff ).
|
||||
|
||||
super->render_table_head_non_unified(
|
||||
io_html = io_html
|
||||
is_diff = is_diff ).
|
||||
|
||||
ENDMETHOD.
|
||||
|
||||
|
||||
METHOD render_patch.
|
||||
|
||||
CONSTANTS:
|
||||
BEGIN OF lc_css_class,
|
||||
patch TYPE string VALUE `patch` ##NO_TEXT,
|
||||
END OF lc_css_class.
|
||||
|
||||
DATA:
|
||||
lv_id TYPE string,
|
||||
lv_patched TYPE abap_bool,
|
||||
lv_is_patch_possible TYPE abap_bool.
|
||||
|
||||
lv_patched = get_diff_object( iv_filename )->is_line_patched( iv_index ).
|
||||
|
||||
lv_is_patch_possible = is_patch_line_possible(
|
||||
is_diff_line = is_diff_line
|
||||
iv_fstate = iv_fstate ).
|
||||
|
||||
IF lv_is_patch_possible = abap_true.
|
||||
|
||||
lv_id = |{ iv_filename }_{ mv_section_count }_{ iv_index }|.
|
||||
|
||||
io_html->add( |<td class="{ lc_css_class-patch }">| ).
|
||||
io_html->add_checkbox(
|
||||
iv_id = |patch_line_{ lv_id }|
|
||||
iv_checked = lv_patched ).
|
||||
io_html->add( |</td>| ).
|
||||
|
||||
ELSE.
|
||||
|
||||
io_html->add( |<td class="{ lc_css_class-patch }">| ).
|
||||
io_html->add( |</td>| ).
|
||||
|
||||
ENDIF.
|
||||
|
||||
ENDMETHOD.
|
||||
|
||||
|
||||
METHOD render_patch_head.
|
||||
|
||||
io_html->add( |<th class="patch">| ).
|
||||
io_html->add_checkbox( iv_id = |patch_file_{ get_normalized_fname_with_path( is_diff ) }| ).
|
||||
io_html->add( '</th>' ).
|
||||
|
||||
ENDMETHOD.
|
||||
|
||||
|
||||
METHOD render_beacon_begin_of_row.
|
||||
|
||||
mv_section_count = mv_section_count + 1.
|
||||
|
||||
io_html->add( |<th class="patch">| ).
|
||||
io_html->add_checkbox( iv_id = |patch_section_{ get_normalized_fname_with_path( is_diff ) }_{ mv_section_count }| ).
|
||||
io_html->add( '</th>' ).
|
||||
|
||||
ENDMETHOD.
|
||||
|
||||
|
||||
METHOD render_content.
|
||||
|
||||
CLEAR: mv_section_count.
|
||||
|
||||
IF mv_pushed = abap_true.
|
||||
refresh_full( ).
|
||||
calculate_diff( ).
|
||||
CLEAR: mv_pushed.
|
||||
ENDIF.
|
||||
|
||||
ro_html = super->render_content( ).
|
||||
|
||||
ENDMETHOD.
|
||||
|
||||
|
||||
METHOD render_diff_head_after_state.
|
||||
|
||||
DATA: lv_act_id TYPE string.
|
||||
|
||||
IF is_diff-obj_type IS NOT INITIAL AND is_diff-obj_name IS NOT INITIAL.
|
||||
|
||||
lv_act_id = |{ c_actions-refresh_local_object }_{ is_diff-obj_type }_{ is_diff-obj_name }|.
|
||||
|
||||
io_html->add_a(
|
||||
iv_txt = |Refresh|
|
||||
iv_typ = zif_abapgit_html=>c_action_type-dummy
|
||||
iv_act = lv_act_id
|
||||
iv_id = lv_act_id
|
||||
iv_title = |Local refresh of this object| ).
|
||||
|
||||
ENDIF.
|
||||
|
||||
super->render_diff_head_after_state(
|
||||
io_html = io_html
|
||||
is_diff = is_diff ).
|
||||
|
||||
ENDMETHOD.
|
||||
|
||||
|
||||
METHOD insert_nav.
|
||||
|
||||
" add beacon at beginning of file
|
||||
rv_insert_nav = abap_true.
|
||||
|
||||
ENDMETHOD.
|
||||
|
||||
|
||||
METHOD render_line_split_row.
|
||||
|
||||
render_patch( io_html = io_html
|
||||
iv_filename = iv_filename
|
||||
is_diff_line = is_diff_line
|
||||
iv_fstate = iv_fstate
|
||||
iv_index = iv_index ).
|
||||
|
||||
super->render_line_split_row(
|
||||
io_html = io_html
|
||||
iv_filename = iv_filename
|
||||
is_diff_line = is_diff_line
|
||||
iv_index = iv_index
|
||||
iv_fstate = iv_fstate
|
||||
iv_new = iv_new
|
||||
iv_old = iv_old ).
|
||||
|
||||
ENDMETHOD.
|
||||
|
||||
|
||||
METHOD is_every_changed_line_patched.
|
||||
|
||||
DATA: lt_diff TYPE zif_abapgit_definitions=>ty_diffs_tt.
|
||||
|
||||
FIELD-SYMBOLS:
|
||||
<ls_diff_file> TYPE zcl_abapgit_gui_page_diff=>ty_file_diff,
|
||||
<ls_diff> TYPE zif_abapgit_definitions=>ty_diff.
|
||||
|
||||
rv_everything_patched = abap_true.
|
||||
|
||||
LOOP AT mt_diff_files ASSIGNING <ls_diff_file>.
|
||||
|
||||
lt_diff = <ls_diff_file>-o_diff->get( ).
|
||||
|
||||
LOOP AT lt_diff ASSIGNING <ls_diff>
|
||||
WHERE result IS NOT INITIAL
|
||||
AND patch_flag = abap_false.
|
||||
rv_everything_patched = abap_false.
|
||||
EXIT.
|
||||
ENDLOOP.
|
||||
IF sy-subrc = 0.
|
||||
EXIT.
|
||||
ENDIF.
|
||||
|
||||
ENDLOOP.
|
||||
|
||||
ENDMETHOD.
|
||||
|
||||
|
||||
METHOD is_patch_line_possible.
|
||||
|
||||
IF is_diff_line-result = zif_abapgit_definitions=>c_diff-update
|
||||
OR is_diff_line-result = zif_abapgit_definitions=>c_diff-insert
|
||||
OR is_diff_line-result = zif_abapgit_definitions=>c_diff-delete.
|
||||
rv_is_patch_line_possible = abap_true.
|
||||
ENDIF.
|
||||
|
||||
ENDMETHOD.
|
||||
|
||||
|
||||
METHOD zif_abapgit_gui_page_hotkey~get_hotkey_actions.
|
||||
|
||||
DATA: ls_hotkey_action LIKE LINE OF rt_hotkey_actions.
|
||||
|
||||
ls_hotkey_action-name = |Stage changes|.
|
||||
ls_hotkey_action-action = |stagePatch|.
|
||||
ls_hotkey_action-hotkey = |s|.
|
||||
INSERT ls_hotkey_action INTO TABLE rt_hotkey_actions.
|
||||
|
||||
ls_hotkey_action-name = |Refresh local|.
|
||||
ls_hotkey_action-action = |refreshLocal|.
|
||||
ls_hotkey_action-hotkey = |r|.
|
||||
INSERT ls_hotkey_action INTO TABLE rt_hotkey_actions.
|
||||
|
||||
ENDMETHOD.
|
||||
|
||||
ENDCLASS.
|
253
src/ui/zcl_abapgit_gui_page_patch.clas.testclasses.abap
Normal file
253
src/ui/zcl_abapgit_gui_page_patch.clas.testclasses.abap
Normal file
|
@ -0,0 +1,253 @@
|
|||
*"* use this source file for your ABAP unit test classes
|
||||
|
||||
CLASS ltcl_get_patch_data DEFINITION FINAL FOR TESTING
|
||||
DURATION SHORT
|
||||
RISK LEVEL HARMLESS.
|
||||
|
||||
PRIVATE SECTION.
|
||||
METHODS:
|
||||
get_patch_data_add FOR TESTING RAISING cx_static_check,
|
||||
get_patch_data_remove FOR TESTING RAISING cx_static_check,
|
||||
invalid_patch_missing_file FOR TESTING RAISING cx_static_check,
|
||||
invalid_patch_missing_index FOR TESTING RAISING cx_static_check.
|
||||
|
||||
ENDCLASS.
|
||||
|
||||
|
||||
CLASS ltcl_is_patch_line_possible DEFINITION FINAL FOR TESTING
|
||||
DURATION SHORT
|
||||
RISK LEVEL HARMLESS.
|
||||
|
||||
PRIVATE SECTION.
|
||||
DATA:
|
||||
mo_cut TYPE REF TO zcl_abapgit_gui_page_patch,
|
||||
mv_is_patch_line_possible TYPE abap_bool,
|
||||
ms_diff_line TYPE zif_abapgit_definitions=>ty_diff,
|
||||
mv_fstate TYPE char1.
|
||||
|
||||
METHODS:
|
||||
setup RAISING zcx_abapgit_exception,
|
||||
initial_diff_line FOR TESTING RAISING cx_static_check,
|
||||
for_update_patch_shd_be_possbl FOR TESTING RAISING cx_static_check,
|
||||
for_insert_patch_shd_be_possbl FOR TESTING RAISING cx_static_check,
|
||||
for_delete_patch_shd_be_possbl FOR TESTING RAISING cx_static_check,
|
||||
|
||||
given_diff_line
|
||||
IMPORTING
|
||||
is_diff_line TYPE zif_abapgit_definitions=>ty_diff OPTIONAL,
|
||||
|
||||
given_fstate
|
||||
IMPORTING
|
||||
iv_fstate TYPE char1,
|
||||
|
||||
when_is_patch_line_possible,
|
||||
|
||||
then_patch_shd_be_possible,
|
||||
then_patch_shd_not_be_possible.
|
||||
|
||||
ENDCLASS.
|
||||
|
||||
CLASS zcl_abapgit_gui_page_patch DEFINITION LOCAL FRIENDS ltcl_is_patch_line_possible.
|
||||
|
||||
CLASS ltcl_get_patch_data IMPLEMENTATION.
|
||||
|
||||
METHOD get_patch_data_add.
|
||||
|
||||
DATA: lv_file_name TYPE string,
|
||||
lv_line_index TYPE string.
|
||||
|
||||
zcl_abapgit_gui_page_patch=>get_patch_data(
|
||||
EXPORTING
|
||||
iv_patch = |patch_line_zcl_test_git_add_p.clas.abap_0_19|
|
||||
IMPORTING
|
||||
ev_filename = lv_file_name
|
||||
ev_line_index = lv_line_index ).
|
||||
|
||||
cl_abap_unit_assert=>assert_equals(
|
||||
exp = |zcl_test_git_add_p.clas.abap|
|
||||
act = lv_file_name ).
|
||||
|
||||
cl_abap_unit_assert=>assert_equals(
|
||||
exp = |19|
|
||||
act = lv_line_index ).
|
||||
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD get_patch_data_remove.
|
||||
|
||||
DATA: lv_file_name TYPE string,
|
||||
lv_line_index TYPE string.
|
||||
|
||||
zcl_abapgit_gui_page_patch=>get_patch_data(
|
||||
EXPORTING
|
||||
iv_patch = |patch_line_ztest_patch.prog.abap_0_39|
|
||||
IMPORTING
|
||||
ev_filename = lv_file_name
|
||||
ev_line_index = lv_line_index ).
|
||||
|
||||
cl_abap_unit_assert=>assert_equals(
|
||||
exp = |ztest_patch.prog.abap|
|
||||
act = lv_file_name ).
|
||||
|
||||
cl_abap_unit_assert=>assert_equals(
|
||||
exp = |39|
|
||||
act = lv_line_index ).
|
||||
|
||||
ENDMETHOD.
|
||||
|
||||
|
||||
METHOD invalid_patch_missing_file.
|
||||
|
||||
DATA: lv_file_name TYPE string,
|
||||
lv_line_index TYPE string,
|
||||
lx_error TYPE REF TO zcx_abapgit_exception.
|
||||
|
||||
TRY.
|
||||
zcl_abapgit_gui_page_patch=>get_patch_data(
|
||||
EXPORTING
|
||||
iv_patch = |patch_39|
|
||||
IMPORTING
|
||||
ev_filename = lv_file_name
|
||||
ev_line_index = lv_line_index ).
|
||||
|
||||
cl_abap_unit_assert=>fail( ).
|
||||
|
||||
CATCH zcx_abapgit_exception INTO lx_error.
|
||||
cl_abap_unit_assert=>assert_equals(
|
||||
exp = |Invalid patch|
|
||||
act = lx_error->get_text( ) ).
|
||||
ENDTRY.
|
||||
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD invalid_patch_missing_index.
|
||||
|
||||
DATA: lv_file_name TYPE string,
|
||||
lv_line_index TYPE string,
|
||||
lx_error TYPE REF TO zcx_abapgit_exception.
|
||||
|
||||
TRY.
|
||||
zcl_abapgit_gui_page_patch=>get_patch_data(
|
||||
EXPORTING
|
||||
iv_patch = |patch_ztest_patch.prog.abap|
|
||||
IMPORTING
|
||||
ev_filename = lv_file_name
|
||||
ev_line_index = lv_line_index ).
|
||||
|
||||
cl_abap_unit_assert=>fail( ).
|
||||
|
||||
CATCH zcx_abapgit_exception INTO lx_error.
|
||||
cl_abap_unit_assert=>assert_equals(
|
||||
exp = |Invalid patch|
|
||||
act = lx_error->get_text( ) ).
|
||||
ENDTRY.
|
||||
|
||||
ENDMETHOD.
|
||||
|
||||
ENDCLASS.
|
||||
|
||||
|
||||
|
||||
CLASS ltcl_is_patch_line_possible IMPLEMENTATION.
|
||||
|
||||
METHOD setup.
|
||||
|
||||
CONSTANTS:
|
||||
lc_dummy_key TYPE zif_abapgit_persistence=>ty_value VALUE '000000000001'.
|
||||
|
||||
CREATE OBJECT mo_cut
|
||||
EXPORTING
|
||||
iv_key = lc_dummy_key.
|
||||
|
||||
ENDMETHOD.
|
||||
|
||||
|
||||
METHOD initial_diff_line.
|
||||
|
||||
given_diff_line( ).
|
||||
when_is_patch_line_possible( ).
|
||||
then_patch_shd_not_be_possible( ).
|
||||
|
||||
ENDMETHOD.
|
||||
|
||||
|
||||
METHOD for_update_patch_shd_be_possbl.
|
||||
|
||||
DATA: ls_diff_line TYPE zif_abapgit_definitions=>ty_diff.
|
||||
|
||||
ls_diff_line-result = zif_abapgit_definitions=>c_diff-update.
|
||||
|
||||
given_diff_line( ls_diff_line ).
|
||||
when_is_patch_line_possible( ).
|
||||
then_patch_shd_be_possible( ).
|
||||
|
||||
ENDMETHOD.
|
||||
|
||||
|
||||
METHOD for_insert_patch_shd_be_possbl.
|
||||
|
||||
DATA: ls_diff_line TYPE zif_abapgit_definitions=>ty_diff.
|
||||
|
||||
ls_diff_line-result = zif_abapgit_definitions=>c_diff-insert.
|
||||
|
||||
given_diff_line( ls_diff_line ).
|
||||
when_is_patch_line_possible( ).
|
||||
then_patch_shd_be_possible( ).
|
||||
|
||||
ENDMETHOD.
|
||||
|
||||
|
||||
METHOD for_delete_patch_shd_be_possbl.
|
||||
|
||||
DATA: ls_diff_line TYPE zif_abapgit_definitions=>ty_diff.
|
||||
|
||||
ls_diff_line-result = zif_abapgit_definitions=>c_diff-delete.
|
||||
|
||||
given_diff_line( ls_diff_line ).
|
||||
when_is_patch_line_possible( ).
|
||||
then_patch_shd_be_possible( ).
|
||||
|
||||
ENDMETHOD.
|
||||
|
||||
|
||||
METHOD when_is_patch_line_possible.
|
||||
|
||||
mv_is_patch_line_possible = mo_cut->is_patch_line_possible(
|
||||
is_diff_line = ms_diff_line
|
||||
iv_fstate = mv_fstate ).
|
||||
|
||||
ENDMETHOD.
|
||||
|
||||
|
||||
METHOD then_patch_shd_be_possible.
|
||||
|
||||
cl_abap_unit_assert=>assert_not_initial(
|
||||
act = mv_is_patch_line_possible
|
||||
msg = |Patch should be possible| ).
|
||||
|
||||
ENDMETHOD.
|
||||
|
||||
|
||||
METHOD then_patch_shd_not_be_possible.
|
||||
|
||||
cl_abap_unit_assert=>assert_initial(
|
||||
act = mv_is_patch_line_possible
|
||||
msg = |Patch should not be possible| ).
|
||||
|
||||
ENDMETHOD.
|
||||
|
||||
|
||||
METHOD given_diff_line.
|
||||
|
||||
ms_diff_line = is_diff_line.
|
||||
|
||||
ENDMETHOD.
|
||||
|
||||
|
||||
METHOD given_fstate.
|
||||
|
||||
mv_fstate = iv_fstate.
|
||||
|
||||
ENDMETHOD.
|
||||
|
||||
ENDCLASS.
|
17
src/ui/zcl_abapgit_gui_page_patch.clas.xml
Normal file
17
src/ui/zcl_abapgit_gui_page_patch.clas.xml
Normal file
|
@ -0,0 +1,17 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<abapGit version="v1.0.0" serializer="LCL_OBJECT_CLAS" serializer_version="v1.0.0">
|
||||
<asx:abap xmlns:asx="http://www.sap.com/abapxml" version="1.0">
|
||||
<asx:values>
|
||||
<VSEOCLASS>
|
||||
<CLSNAME>ZCL_ABAPGIT_GUI_PAGE_PATCH</CLSNAME>
|
||||
<LANGU>E</LANGU>
|
||||
<DESCRIPT>GUI - Patch page</DESCRIPT>
|
||||
<STATE>1</STATE>
|
||||
<CLSCCINCL>X</CLSCCINCL>
|
||||
<FIXPT>X</FIXPT>
|
||||
<UNICODE>X</UNICODE>
|
||||
<WITH_UNIT_TESTS>X</WITH_UNIT_TESTS>
|
||||
</VSEOCLASS>
|
||||
</asx:values>
|
||||
</asx:abap>
|
||||
</abapGit>
|
|
@ -103,7 +103,7 @@ ENDCLASS.
|
|||
|
||||
|
||||
|
||||
CLASS ZCL_ABAPGIT_GUI_PAGE_STAGE IMPLEMENTATION.
|
||||
CLASS zcl_abapgit_gui_page_stage IMPLEMENTATION.
|
||||
|
||||
|
||||
METHOD build_menu.
|
||||
|
@ -240,7 +240,7 @@ CLASS ZCL_ABAPGIT_GUI_PAGE_STAGE IMPLEMENTATION.
|
|||
|
||||
METHOD get_page_patch.
|
||||
|
||||
DATA: lo_page TYPE REF TO zcl_abapgit_gui_page_diff,
|
||||
DATA: lo_page TYPE REF TO zcl_abapgit_gui_page_patch,
|
||||
lv_key TYPE zif_abapgit_persistence=>ty_repo-key.
|
||||
|
||||
zcl_abapgit_html_action_utils=>file_obj_decode(
|
||||
|
@ -251,8 +251,7 @@ CLASS ZCL_ABAPGIT_GUI_PAGE_STAGE IMPLEMENTATION.
|
|||
|
||||
CREATE OBJECT lo_page
|
||||
EXPORTING
|
||||
iv_key = lv_key
|
||||
iv_patch_mode = abap_true.
|
||||
iv_key = lv_key.
|
||||
|
||||
ri_page = lo_page.
|
||||
|
||||
|
|
Loading…
Reference in New Issue
Block a user