@@ -44,12 +44,6 @@ | |||
-webkit-line-clamp: 2; | |||
-webkit-box-orient: vertical; | |||
} | |||
.ui.label{ | |||
font-weight: normal; | |||
} | |||
.active { | |||
color: #0366D6 !important; | |||
} | |||
.opacity5{ opacity:0.5;} | |||
.radius15{ border-radius:1.5rem !important; } | |||
@@ -287,70 +281,6 @@ | |||
position: relative; | |||
} | |||
/**seach**/ | |||
/**搜索导航条适配窄屏**/ | |||
.seachnav{ | |||
overflow-x: auto; | |||
overflow-y: hidden; | |||
scrollbar-width: none; /* firefox */ | |||
-ms-overflow-style: none; /* IE 10+ */ | |||
} | |||
.seachnav::-webkit-scrollbar { | |||
display: none; /* Chrome Safari */ | |||
} | |||
.ui.green.button, .ui.green.buttons .button{ | |||
background-color: #5BB973; | |||
} | |||
.seach .repos--seach{ | |||
padding-bottom: 0; | |||
border-bottom: none; | |||
} | |||
.seach .ui.secondary.pointing.menu{ | |||
border-bottom: none; | |||
} | |||
.seach .ui.secondary.pointing.menu .item > i{ | |||
margin-right: 5px; | |||
} | |||
.seach .ui.secondary.pointing.menu .active.item{ | |||
border-bottom-width: 2px; | |||
margin: 0 0 -1px; | |||
} | |||
.seach .ui.menu .active.item>.label { | |||
background: #1684FC; | |||
color: #FFF; | |||
} | |||
.seach .ui.menu .item>.label:not(.active.item>.label) { | |||
background: #e8e8e8; | |||
color: rgba(0,0,0,.6); | |||
} | |||
.highlight{ | |||
color: red; | |||
} | |||
.ui.list .list>.item>img.image+.content, .ui.list>.item>img.image+.content { | |||
width: calc(100% - 3.0em); | |||
margin-left: 0; | |||
} | |||
.seach .ui.list .list>.item .header, .seach .ui.list>.item .header{ | |||
margin-bottom: 0.5em; | |||
font-size: 1.4rem !important; | |||
font-weight: normal; | |||
} | |||
.seach .time, .seach .time a{ | |||
font-size: 12px; | |||
color: grey; | |||
} | |||
.seach .list .item.members .ui.avatar.image { | |||
width: 3.2em; | |||
height: 3.2em; | |||
} | |||
.ui.list .list>.item.members>img.image+.content, .ui.list>.item.members>img.image+.content { | |||
width: calc(100% - 4.0em); | |||
margin-left: 0; | |||
} | |||
@media only screen and (max-width: 767px) { | |||
.am-mt-30{ margin-top: 1.5rem !important;} | |||
.ui.secondary.hometop.segment{ | |||
@@ -0,0 +1,186 @@ | |||
DROP FOREIGN TABLE public.dataset_es; | |||
CREATE FOREIGN TABLE public.dataset_es | |||
( | |||
id bigint NOT NULL, | |||
title character varying(255), | |||
status integer, | |||
category character varying(255), | |||
description text, | |||
download_times bigint, | |||
license character varying(255), | |||
task character varying(255), | |||
release_id bigint, | |||
user_id bigint, | |||
repo_id bigint, | |||
created_unix bigint, | |||
updated_unix bigint, | |||
file_name text, | |||
file_desc text | |||
)SERVER multicorn_es | |||
OPTIONS | |||
( | |||
host '192.168.207.94', | |||
port '9200', | |||
index 'dataset-es-index', | |||
rowid_column 'id', | |||
default_sort '_id' | |||
) | |||
; | |||
DELETE FROM public.dataset_es; | |||
INSERT INTO public.dataset_es( | |||
id, | |||
title, | |||
status, | |||
category, | |||
description, | |||
download_times, | |||
license, task, | |||
release_id, | |||
user_id, | |||
repo_id, | |||
created_unix, | |||
updated_unix, | |||
file_name, | |||
file_desc | |||
) | |||
SELECT | |||
b.id, | |||
b.title, | |||
b.status, | |||
b.category, | |||
b.description, | |||
b.download_times, | |||
b.license, | |||
b.task, | |||
b.release_id, | |||
b.user_id, | |||
b.repo_id, | |||
b.created_unix, | |||
b.updated_unix, | |||
(select array_to_string(array_agg(name order by created_unix desc),'-#,#-') from public.attachment a where a.dataset_id=b.id and a.is_private=false), | |||
(select array_to_string(array_agg(description order by created_unix desc),'-#,#-') from public.attachment a where a.dataset_id=b.id and a.is_private=false) | |||
FROM public.dataset b,public.repository c where b.repo_id=c.id and c.is_private=false; | |||
DROP TRIGGER IF EXISTS es_insert_dataset on public.dataset; | |||
CREATE OR REPLACE FUNCTION public.insert_dataset_data() RETURNS trigger AS | |||
$def$ | |||
DECLARE | |||
privateValue boolean=false; | |||
BEGIN | |||
select into privateValue is_private from public.repository where id=NEW.repo_id; | |||
if not privateValue then | |||
INSERT INTO public.dataset_es( | |||
id, | |||
title, | |||
status, | |||
category, | |||
description, | |||
download_times, | |||
license, | |||
task, | |||
release_id, | |||
user_id, | |||
repo_id, | |||
created_unix, | |||
updated_unix) | |||
VALUES ( | |||
NEW.id, | |||
NEW.title, | |||
NEW.status, | |||
NEW.category, | |||
NEW.description, | |||
NEW.download_times, | |||
NEW.license, | |||
NEW.task, | |||
NEW.release_id, | |||
NEW.user_id, | |||
NEW.repo_id, | |||
NEW.created_unix, | |||
NEW.updated_unix | |||
); | |||
end if; | |||
RETURN NEW; | |||
END; | |||
$def$ | |||
LANGUAGE plpgsql; | |||
CREATE TRIGGER es_insert_dataset | |||
AFTER INSERT ON public.dataset | |||
FOR EACH ROW EXECUTE PROCEDURE insert_dataset_data(); | |||
ALTER TABLE public.dataset ENABLE ALWAYS TRIGGER es_insert_dataset; | |||
DROP TRIGGER IF EXISTS es_udpate_dataset_file_name on public.attachment; | |||
CREATE OR REPLACE FUNCTION public.udpate_dataset_file_name() RETURNS trigger AS | |||
$def$ | |||
BEGIN | |||
if (TG_OP = 'UPDATE') then | |||
update public.dataset_es SET file_desc=(select array_to_string(array_agg(description order by created_unix desc),'-#,#-') from public.attachment where dataset_id=NEW.dataset_id and is_private=false) where id=NEW.dataset_id; | |||
elsif (TG_OP = 'INSERT') then | |||
update public.dataset_es SET file_name=(select array_to_string(array_agg(name order by created_unix desc),'-#,#-') from public.attachment where dataset_id=NEW.dataset_id and is_private=false) where id=NEW.dataset_id; | |||
elsif (TG_OP = 'DELETE') then | |||
update public.dataset_es SET file_name=(select array_to_string(array_agg(name order by created_unix desc),'-#,#-') from public.attachment where dataset_id=OLD.dataset_id and is_private=false) where id=OLD.dataset_id; | |||
update public.dataset_es SET file_desc=(select array_to_string(array_agg(description order by created_unix desc),'-#,#-') from public.attachment where dataset_id=OLD.dataset_id and is_private=false) where id=OLD.dataset_id; | |||
end if; | |||
return NEW; | |||
END; | |||
$def$ | |||
LANGUAGE plpgsql; | |||
CREATE TRIGGER es_udpate_dataset_file_name | |||
AFTER INSERT OR UPDATE OR DELETE ON public.attachment | |||
FOR EACH ROW EXECUTE PROCEDURE udpate_dataset_file_name(); | |||
ALTER TABLE public.attachment ENABLE ALWAYS TRIGGER es_udpate_dataset_file_name; | |||
DROP TRIGGER IF EXISTS es_update_dataset on public.dataset; | |||
CREATE OR REPLACE FUNCTION public.update_dataset() RETURNS trigger AS | |||
$def$ | |||
BEGIN | |||
UPDATE public.dataset_es | |||
SET description=NEW.description, | |||
title=NEW.title, | |||
category=NEW.category, | |||
task=NEW.task, | |||
download_times=NEW.download_times, | |||
updated_unix=NEW.updated_unix, | |||
file_name=(select array_to_string(array_agg(name order by created_unix desc),'-#,#-') from public.attachment where dataset_id=NEW.id and is_private=false), | |||
file_desc=(select array_to_string(array_agg(description order by created_unix desc),'-#,#-') from public.attachment where dataset_id=NEW.id and is_private=false) | |||
where id=NEW.id; | |||
return new; | |||
END | |||
$def$ | |||
LANGUAGE plpgsql; | |||
CREATE TRIGGER es_update_dataset | |||
AFTER UPDATE ON public.dataset | |||
FOR EACH ROW EXECUTE PROCEDURE update_dataset(); | |||
ALTER TABLE public.dataset ENABLE ALWAYS TRIGGER es_update_dataset; | |||
DROP TRIGGER IF EXISTS es_delete_dataset on public.dataset; | |||
CREATE OR REPLACE FUNCTION public.delete_dataset() RETURNS trigger AS | |||
$def$ | |||
declare | |||
BEGIN | |||
DELETE FROM public.dataset_es where id=OLD.id; | |||
return new; | |||
END | |||
$def$ | |||
LANGUAGE plpgsql; | |||
CREATE TRIGGER es_delete_dataset | |||
AFTER DELETE ON public.dataset | |||
FOR EACH ROW EXECUTE PROCEDURE delete_dataset(); | |||
ALTER TABLE public.dataset ENABLE ALWAYS TRIGGER es_delete_dataset; |
@@ -0,0 +1,215 @@ | |||
DROP FOREIGN TABLE public.issue_es; | |||
CREATE FOREIGN TABLE public.issue_es | |||
( | |||
id bigint NOT NULL, | |||
repo_id bigint, | |||
index bigint, | |||
poster_id bigint, | |||
original_author character varying(255), | |||
original_author_id bigint, | |||
name character varying(255) , | |||
content text, | |||
comment text, | |||
milestone_id bigint, | |||
priority integer, | |||
is_closed boolean, | |||
is_pull boolean, | |||
pr_id bigint, | |||
num_comments integer, | |||
ref character varying(255), | |||
deadline_unix bigint, | |||
created_unix bigint, | |||
updated_unix bigint, | |||
closed_unix bigint, | |||
is_locked boolean NOT NULL, | |||
amount bigint, | |||
is_transformed boolean NOT NULL | |||
)SERVER multicorn_es | |||
OPTIONS | |||
( | |||
host '192.168.207.94', | |||
port '9200', | |||
index 'issue-es-index', | |||
rowid_column 'id', | |||
default_sort '_id' | |||
) | |||
; | |||
delete from public.issue_es; | |||
INSERT INTO public.issue_es( | |||
id, | |||
repo_id, | |||
index, | |||
poster_id, | |||
original_author, | |||
original_author_id, | |||
name, | |||
content, | |||
milestone_id, | |||
priority, | |||
is_closed, | |||
is_pull, | |||
num_comments, | |||
ref, | |||
deadline_unix, | |||
created_unix, | |||
updated_unix, | |||
closed_unix, | |||
is_locked, | |||
amount, | |||
is_transformed,comment,pr_id) | |||
SELECT | |||
b.id, | |||
b.repo_id, | |||
b.index, | |||
b.poster_id, | |||
b.original_author, | |||
b.original_author_id, | |||
b.name, | |||
b.content, | |||
b.milestone_id, | |||
b.priority, | |||
b.is_closed, | |||
b.is_pull, | |||
b.num_comments, | |||
b.ref, | |||
b.deadline_unix, | |||
b.created_unix, | |||
b.updated_unix, | |||
b.closed_unix, | |||
b.is_locked, | |||
b.amount, | |||
b.is_transformed, | |||
(select array_to_string(array_agg(content order by created_unix desc),',') from public.comment a where a.issue_id=b.id), | |||
(select id from public.pull_request d where b.id=d.issue_id and b.is_pull=true) | |||
FROM public.issue b,public.repository c where b.repo_id=c.id and c.is_private=false; | |||
CREATE OR REPLACE FUNCTION public.insert_issue_data() RETURNS trigger AS | |||
$def$ | |||
DECLARE | |||
privateValue boolean=false; | |||
BEGIN | |||
select into privateValue is_private from public.repository where id=NEW.repo_id; | |||
if not privateValue then | |||
INSERT INTO public.issue_es( | |||
id, | |||
repo_id, | |||
index, | |||
poster_id, | |||
original_author, | |||
original_author_id, | |||
name, | |||
content, | |||
milestone_id, | |||
priority, | |||
is_closed, | |||
is_pull, | |||
num_comments, | |||
ref, | |||
deadline_unix, | |||
created_unix, | |||
updated_unix, | |||
closed_unix, | |||
is_locked, | |||
amount, | |||
is_transformed) | |||
VALUES ( | |||
NEW.id, | |||
NEW.repo_id, | |||
NEW.index, | |||
NEW.poster_id, | |||
NEW.original_author, | |||
NEW.original_author_id, | |||
NEW.name, | |||
NEW.content, | |||
NEW.milestone_id, | |||
NEW.priority, | |||
NEW.is_closed, | |||
NEW.is_pull, | |||
NEW.num_comments, | |||
NEW.ref, | |||
NEW.deadline_unix, | |||
NEW.created_unix, | |||
NEW.updated_unix, | |||
NEW.closed_unix, | |||
NEW.is_locked, | |||
NEW.amount, | |||
NEW.is_transformed | |||
); | |||
end if; | |||
RETURN NEW; | |||
END; | |||
$def$ | |||
LANGUAGE plpgsql; | |||
DROP TRIGGER IF EXISTS es_insert_issue on public.issue; | |||
CREATE TRIGGER es_insert_issue | |||
AFTER INSERT ON public.issue | |||
FOR EACH ROW EXECUTE PROCEDURE insert_issue_data(); | |||
ALTER TABLE public.issue ENABLE ALWAYS TRIGGER es_insert_issue; | |||
CREATE OR REPLACE FUNCTION public.udpate_issue_comment() RETURNS trigger AS | |||
$def$ | |||
BEGIN | |||
if (TG_OP = 'DELETE') then | |||
update public.issue_es SET comment=(select array_to_string(array_agg(content order by created_unix desc),',') from public.comment where issue_id=OLD.issue_id) where id=OLD.issue_id; | |||
elsif (TG_OP = 'UPDATE') then | |||
update public.issue_es SET comment=(select array_to_string(array_agg(content order by created_unix desc),',') from public.comment where issue_id=NEW.issue_id) where id=NEW.issue_id; | |||
end if; | |||
return null; | |||
END; | |||
$def$ | |||
LANGUAGE plpgsql; | |||
DROP TRIGGER IF EXISTS es_udpate_issue_comment on public.comment; | |||
CREATE TRIGGER es_udpate_issue_comment | |||
AFTER DELETE OR UPDATE ON public.comment | |||
FOR EACH ROW EXECUTE PROCEDURE udpate_issue_comment(); | |||
ALTER TABLE public.comment ENABLE ALWAYS TRIGGER es_udpate_issue_comment; | |||
CREATE OR REPLACE FUNCTION public.update_issue() RETURNS trigger AS | |||
$def$ | |||
declare | |||
BEGIN | |||
UPDATE public.issue_es | |||
SET content=NEW.content, | |||
name=NEW.name, | |||
is_closed=NEW.is_closed, | |||
num_comments=NEW.num_comments, | |||
comment=(select array_to_string(array_agg(content order by created_unix desc),',') from public.comment where issue_id=NEW.id) | |||
where id=NEW.id; | |||
return new; | |||
END | |||
$def$ | |||
LANGUAGE plpgsql; | |||
DROP TRIGGER IF EXISTS es_update_issue on public.issue; | |||
CREATE TRIGGER es_update_issue | |||
AFTER UPDATE ON public.issue | |||
FOR EACH ROW EXECUTE PROCEDURE update_issue(); | |||
ALTER TABLE public.issue ENABLE ALWAYS TRIGGER es_update_issue; | |||
CREATE OR REPLACE FUNCTION public.delete_issue() RETURNS trigger AS | |||
$def$ | |||
declare | |||
BEGIN | |||
DELETE FROM public.issue_es where id=OLD.id; | |||
return new; | |||
END | |||
$def$ | |||
LANGUAGE plpgsql; | |||
DROP TRIGGER IF EXISTS es_delete_issue on public.issue; | |||
CREATE TRIGGER es_delete_issue | |||
AFTER DELETE ON public.issue | |||
FOR EACH ROW EXECUTE PROCEDURE delete_issue(); | |||
ALTER TABLE public.issue ENABLE ALWAYS TRIGGER es_delete_issue; |
@@ -0,0 +1,532 @@ | |||
-- 要处理项目从私有变为公有,并且从公有变成私有的情况 | |||
DROP FOREIGN table if exists public.repository_es; | |||
CREATE FOREIGN TABLE public.repository_es ( | |||
id bigint NOT NULL, | |||
owner_id bigint, | |||
owner_name character varying(255), | |||
lower_name character varying(255) NOT NULL, | |||
name character varying(255) NOT NULL, | |||
description text, | |||
website character varying(2048), | |||
original_service_type integer, | |||
original_url character varying(2048), | |||
default_branch character varying(255), | |||
num_watches integer, | |||
num_stars integer, | |||
num_forks integer, | |||
num_issues integer, | |||
num_closed_issues integer, | |||
num_pulls integer, | |||
num_closed_pulls integer, | |||
num_milestones integer DEFAULT 0 NOT NULL, | |||
num_closed_milestones integer DEFAULT 0 NOT NULL, | |||
is_private boolean, | |||
is_empty boolean, | |||
is_archived boolean, | |||
is_mirror boolean, | |||
status integer DEFAULT 0 NOT NULL, | |||
is_fork boolean DEFAULT false NOT NULL, | |||
fork_id bigint, | |||
is_template boolean DEFAULT false NOT NULL, | |||
template_id bigint, | |||
size bigint DEFAULT 0 NOT NULL, | |||
is_fsck_enabled boolean DEFAULT true NOT NULL, | |||
close_issues_via_commit_in_any_branch boolean DEFAULT false NOT NULL, | |||
topics text, | |||
avatar character varying(64), | |||
created_unix bigint, | |||
updated_unix bigint, | |||
contract_address character varying(255), | |||
block_chain_status integer DEFAULT 0 NOT NULL, | |||
balance character varying(255) DEFAULT '0'::character varying NOT NULL, | |||
clone_cnt bigint DEFAULT 0 NOT NULL, | |||
license character varying(100), | |||
download_cnt bigint DEFAULT 0 NOT NULL, | |||
num_commit bigint DEFAULT 0 NOT NULL, | |||
git_clone_cnt bigint DEFAULT 0 NOT NULL, | |||
creator_id bigint NOT NULL DEFAULT 0, | |||
repo_type integer NOT NULL DEFAULT 0, | |||
lang character varying(2048), | |||
alias character varying(255), | |||
lower_alias character varying(255) | |||
) SERVER multicorn_es | |||
OPTIONS | |||
( | |||
host '192.168.207.94', | |||
port '9200', | |||
index 'repository-es-index', | |||
rowid_column 'id', | |||
default_sort '_id' | |||
) | |||
; | |||
delete from public.repository_es; | |||
INSERT INTO public.repository_es (id, | |||
owner_id, | |||
owner_name, | |||
lower_name, | |||
name, | |||
description, | |||
website, | |||
original_service_type, | |||
original_url, | |||
default_branch, | |||
num_watches, | |||
num_stars, | |||
num_forks, | |||
num_issues, | |||
num_closed_issues, | |||
num_pulls, | |||
num_closed_pulls, | |||
num_milestones, | |||
num_closed_milestones, | |||
is_private, | |||
is_empty, | |||
is_archived, | |||
is_mirror, | |||
status, | |||
is_fork, | |||
fork_id, | |||
is_template, | |||
template_id, | |||
size, | |||
is_fsck_enabled, | |||
close_issues_via_commit_in_any_branch, | |||
topics, | |||
avatar, | |||
created_unix, | |||
updated_unix, | |||
contract_address, | |||
block_chain_status, | |||
balance, | |||
clone_cnt, | |||
num_commit, | |||
git_clone_cnt, | |||
creator_id, | |||
repo_type, | |||
lang, | |||
alias, | |||
lower_alias | |||
) | |||
SELECT | |||
id, | |||
owner_id, | |||
owner_name, | |||
lower_name, | |||
name, | |||
description, | |||
website, | |||
original_service_type, | |||
original_url, | |||
default_branch, | |||
num_watches, | |||
num_stars, | |||
num_forks, | |||
num_issues, | |||
num_closed_issues, | |||
num_pulls, | |||
num_closed_pulls, | |||
num_milestones, | |||
num_closed_milestones, | |||
is_private, | |||
is_empty, | |||
is_archived, | |||
is_mirror, | |||
status, | |||
is_fork, | |||
fork_id, | |||
is_template, | |||
template_id, | |||
size, | |||
is_fsck_enabled, | |||
close_issues_via_commit_in_any_branch, | |||
topics, | |||
avatar, | |||
created_unix, | |||
updated_unix, | |||
contract_address, | |||
block_chain_status, | |||
balance, | |||
clone_cnt, | |||
num_commit, | |||
git_clone_cnt, | |||
creator_id, | |||
repo_type, | |||
(select array_to_string(array_agg(language order by percentage desc),',') from public.language_stat a where a.repo_id=b.id), | |||
alias, | |||
lower_alias | |||
FROM public.repository b where b.is_private=false; | |||
DROP TRIGGER IF EXISTS es_insert_repository on public.repository; | |||
CREATE OR REPLACE FUNCTION public.insert_repository_data() RETURNS trigger AS | |||
$def$ | |||
BEGIN | |||
if not NEW.is_private then | |||
INSERT INTO public.repository_es (id, | |||
owner_id, | |||
owner_name, | |||
lower_name, | |||
name, | |||
description, | |||
website, | |||
original_service_type, | |||
original_url, | |||
default_branch, | |||
num_watches, | |||
num_stars, | |||
num_forks, | |||
num_issues, | |||
num_closed_issues, | |||
num_pulls, | |||
num_closed_pulls, | |||
num_milestones, | |||
num_closed_milestones, | |||
is_private, | |||
is_empty, | |||
is_archived, | |||
is_mirror, | |||
status, | |||
is_fork, | |||
fork_id, | |||
is_template, | |||
template_id, | |||
size, | |||
is_fsck_enabled, | |||
close_issues_via_commit_in_any_branch, | |||
topics, | |||
avatar, | |||
created_unix, | |||
updated_unix, | |||
contract_address, | |||
block_chain_status, | |||
balance, | |||
clone_cnt, | |||
num_commit, | |||
git_clone_cnt, | |||
creator_id, | |||
repo_type, | |||
alias, | |||
lower_alias) VALUES | |||
(NEW.id, | |||
NEW.owner_id, | |||
NEW.owner_name, | |||
NEW.lower_name, | |||
NEW.name, | |||
NEW.description, | |||
NEW.website, | |||
NEW.original_service_type, | |||
NEW.original_url, | |||
NEW.default_branch, | |||
NEW.num_watches, | |||
NEW.num_stars, | |||
NEW.num_forks, | |||
NEW.num_issues, | |||
NEW.num_closed_issues, | |||
NEW.num_pulls, | |||
NEW.num_closed_pulls, | |||
NEW.num_milestones, | |||
NEW.num_closed_milestones, | |||
NEW.is_private, | |||
NEW.is_empty, | |||
NEW.is_archived, | |||
NEW.is_mirror, | |||
NEW.status, | |||
NEW.is_fork, | |||
NEW.fork_id, | |||
NEW.is_template, | |||
NEW.template_id, | |||
NEW.size, | |||
NEW.is_fsck_enabled, | |||
NEW.close_issues_via_commit_in_any_branch, | |||
NEW.topics, | |||
NEW.avatar, | |||
NEW.created_unix, | |||
NEW.updated_unix, | |||
NEW.contract_address, | |||
NEW.block_chain_status, | |||
NEW.balance, | |||
NEW.clone_cnt, | |||
NEW.num_commit, | |||
NEW.git_clone_cnt, | |||
NEW.creator_id, | |||
NEW.repo_type, | |||
NEW.alias, | |||
NEW.lower_alias); | |||
end if; | |||
RETURN NEW; | |||
END; | |||
$def$ | |||
LANGUAGE plpgsql; | |||
CREATE TRIGGER es_insert_repository | |||
AFTER INSERT ON public.repository | |||
FOR EACH ROW EXECUTE PROCEDURE insert_repository_data(); | |||
ALTER TABLE public.repository ENABLE ALWAYS TRIGGER es_insert_repository; | |||
DROP TRIGGER IF EXISTS es_update_repository on public.repository; | |||
CREATE OR REPLACE FUNCTION public.update_repository() RETURNS trigger AS | |||
$def$ | |||
BEGIN | |||
if OLD.is_private != NEW.is_private then | |||
if OLD.is_private and not NEW.is_private then | |||
--insert | |||
INSERT INTO public.repository_es (id, | |||
owner_id, | |||
owner_name, | |||
lower_name, | |||
name, | |||
description, | |||
website, | |||
original_service_type, | |||
original_url, | |||
default_branch, | |||
num_watches, | |||
num_stars, | |||
num_forks, | |||
num_issues, | |||
num_closed_issues, | |||
num_pulls, | |||
num_closed_pulls, | |||
num_milestones, | |||
num_closed_milestones, | |||
is_private, | |||
is_empty, | |||
is_archived, | |||
is_mirror, | |||
status, | |||
is_fork, | |||
fork_id, | |||
is_template, | |||
template_id, | |||
size, | |||
is_fsck_enabled, | |||
close_issues_via_commit_in_any_branch, | |||
topics, | |||
avatar, | |||
created_unix, | |||
updated_unix, | |||
contract_address, | |||
block_chain_status, | |||
balance, | |||
clone_cnt, | |||
num_commit, | |||
git_clone_cnt, | |||
creator_id, | |||
repo_type, | |||
lang, | |||
alias, | |||
lower_alias) | |||
SELECT | |||
id, | |||
owner_id, | |||
owner_name, | |||
lower_name, | |||
name, | |||
description, | |||
website, | |||
original_service_type, | |||
original_url, | |||
default_branch, | |||
num_watches, | |||
num_stars, | |||
num_forks, | |||
num_issues, | |||
num_closed_issues, | |||
num_pulls, | |||
num_closed_pulls, | |||
num_milestones, | |||
num_closed_milestones, | |||
is_private, | |||
is_empty, | |||
is_archived, | |||
is_mirror, | |||
status, | |||
is_fork, | |||
fork_id, | |||
is_template, | |||
template_id, | |||
size, | |||
is_fsck_enabled, | |||
close_issues_via_commit_in_any_branch, | |||
topics, | |||
avatar, | |||
created_unix, | |||
updated_unix, | |||
contract_address, | |||
block_chain_status, | |||
balance, | |||
clone_cnt, | |||
num_commit, | |||
git_clone_cnt, | |||
creator_id, | |||
repo_type, | |||
(select array_to_string(array_agg(language order by percentage desc),',') from public.language_stat a where a.repo_id=b.id), | |||
alias, | |||
lower_alias | |||
FROM public.repository b where b.id=NEW.id; | |||
INSERT INTO public.dataset_es( | |||
id, | |||
title, | |||
status, | |||
category, | |||
description, | |||
download_times, | |||
license, task, | |||
release_id, | |||
user_id, | |||
repo_id, | |||
created_unix, | |||
updated_unix,file_name) | |||
SELECT | |||
b.id, | |||
b.title, | |||
b.status, | |||
b.category, | |||
b.description, | |||
b.download_times, | |||
b.license, | |||
b.task, | |||
b.release_id, | |||
b.user_id, | |||
b.repo_id, | |||
b.created_unix, | |||
b.updated_unix,(select array_to_string(array_agg(name order by created_unix desc),',') from public.attachment a where a.dataset_id=b.id and a.is_private=false) | |||
FROM public.dataset b where b.repo_id=NEW.id; | |||
INSERT INTO public.issue_es( | |||
id, | |||
repo_id, | |||
index, | |||
poster_id, | |||
original_author, | |||
original_author_id, | |||
name, | |||
content, | |||
milestone_id, | |||
priority, | |||
is_closed, | |||
is_pull, | |||
num_comments, | |||
ref, | |||
deadline_unix, | |||
created_unix, | |||
updated_unix, | |||
closed_unix, | |||
is_locked, | |||
amount, | |||
is_transformed,comment,pr_id) | |||
SELECT | |||
b.id, | |||
b.repo_id, | |||
b.index, | |||
b.poster_id, | |||
b.original_author, | |||
b.original_author_id, | |||
b.name, | |||
b.content, | |||
b.milestone_id, | |||
b.priority, | |||
b.is_closed, | |||
b.is_pull, | |||
b.num_comments, | |||
b.ref, | |||
b.deadline_unix, | |||
b.created_unix, | |||
b.updated_unix, | |||
b.closed_unix, | |||
b.is_locked, | |||
b.amount, | |||
b.is_transformed, | |||
(select array_to_string(array_agg(content order by created_unix desc),',') from public.comment a where a.issue_id=b.id), | |||
(select id from public.pull_request d where d.issue_id=b.id) | |||
FROM public.issue b where b.repo_id=NEW.id; | |||
end if; | |||
if not OLD.is_private and NEW.is_private then | |||
delete from public.issue_es where repo_id=NEW.id; | |||
delete from public.dataset_es where repo_id=NEW.id; | |||
delete from public.repository_es where id=NEW.id; | |||
end if; | |||
end if; | |||
if not NEW.is_private then | |||
raise notice 'update repo,the updated_unix is %',NEW.updated_unix; | |||
update public.repository_es SET description=NEW.description, | |||
name=NEW.name, | |||
lower_name=NEW.lower_name, | |||
owner_name=NEW.owner_name, | |||
website=NEW.website, | |||
updated_unix=NEW.updated_unix, | |||
num_watches=NEW.num_watches, | |||
num_stars=NEW.num_stars, | |||
num_forks=NEW.num_forks, | |||
topics=NEW.topics, | |||
alias = NEW.alias, | |||
lower_alias = NEW.lower_alias, | |||
avatar=NEW.avatar | |||
where id=NEW.id; | |||
end if; | |||
return new; | |||
END | |||
$def$ | |||
LANGUAGE plpgsql; | |||
CREATE TRIGGER es_update_repository | |||
AFTER UPDATE ON public.repository | |||
FOR EACH ROW EXECUTE PROCEDURE update_repository(); | |||
ALTER TABLE public.repository ENABLE ALWAYS TRIGGER es_update_repository; | |||
DROP TRIGGER IF EXISTS es_delete_repository on public.repository; | |||
CREATE OR REPLACE FUNCTION public.delete_repository() RETURNS trigger AS | |||
$def$ | |||
declare | |||
BEGIN | |||
delete from public.issue_es where repo_id=OLD.id; | |||
delete from public.dataset_es where repo_id=OLD.id; | |||
DELETE FROM public.repository_es where id=OLD.id; | |||
return new; | |||
END | |||
$def$ | |||
LANGUAGE plpgsql; | |||
CREATE TRIGGER es_delete_repository | |||
AFTER DELETE ON public.repository | |||
FOR EACH ROW EXECUTE PROCEDURE delete_repository(); | |||
ALTER TABLE public.repository ENABLE ALWAYS TRIGGER es_delete_repository; | |||
DROP TRIGGER IF EXISTS es_udpate_repository_lang on public.language_stat; | |||
CREATE OR REPLACE FUNCTION public.udpate_repository_lang() RETURNS trigger AS | |||
$def$ | |||
BEGIN | |||
if (TG_OP = 'UPDATE') then | |||
update public.repository_es SET lang=(select array_to_string(array_agg(language order by percentage desc),',') from public.language_stat where repo_id=NEW.repo_id) where id=NEW.repo_id; | |||
elsif (TG_OP = 'INSERT') then | |||
update public.repository_es SET lang=(select array_to_string(array_agg(language order by percentage desc),',') from public.language_stat where repo_id=NEW.repo_id) where id=NEW.repo_id; | |||
elsif (TG_OP = 'DELETE') then | |||
if exists(select 1 from public.repository where id=OLD.repo_id) then | |||
update public.repository_es SET lang=(select array_to_string(array_agg(language order by percentage desc),',') from public.language_stat where repo_id=OLD.repo_id) where id=OLD.repo_id; | |||
end if; | |||
end if; | |||
return null; | |||
END; | |||
$def$ | |||
LANGUAGE plpgsql; | |||
CREATE TRIGGER es_udpate_repository_lang | |||
AFTER INSERT OR UPDATE OR DELETE ON public.language_stat | |||
FOR EACH ROW EXECUTE PROCEDURE udpate_repository_lang(); | |||
ALTER TABLE public.language_stat ENABLE ALWAYS TRIGGER es_udpate_repository_lang; |
@@ -0,0 +1,308 @@ | |||
DROP FOREIGN table if exists public.user_es; | |||
CREATE FOREIGN TABLE public.user_es | |||
( | |||
id bigint NOT NULL , | |||
lower_name character varying(255) NULL, | |||
name character varying(255) NULL, | |||
full_name character varying(255), | |||
email character varying(255), | |||
keep_email_private boolean, | |||
email_notifications_preference character varying(20) , | |||
passwd character varying(255) , | |||
passwd_hash_algo character varying(255) , | |||
must_change_password boolean NOT NULL DEFAULT false, | |||
login_type integer, | |||
login_source bigint NOT NULL DEFAULT 0, | |||
login_name character varying(255) , | |||
type integer, | |||
location character varying(255), | |||
website character varying(255), | |||
rands character varying(10), | |||
salt character varying(10), | |||
language character varying(5), | |||
description character varying(255), | |||
created_unix bigint, | |||
updated_unix bigint, | |||
last_login_unix bigint, | |||
last_repo_visibility boolean, | |||
max_repo_creation integer, | |||
is_active boolean, | |||
is_admin boolean, | |||
is_restricted boolean NOT NULL DEFAULT false, | |||
allow_git_hook boolean, | |||
allow_import_local boolean, | |||
allow_create_organization boolean DEFAULT true, | |||
prohibit_login boolean NOT NULL DEFAULT false, | |||
avatar character varying(2048) , | |||
avatar_email character varying(255), | |||
use_custom_avatar boolean, | |||
num_followers integer, | |||
num_following integer NOT NULL DEFAULT 0, | |||
num_stars integer, | |||
num_repos integer, | |||
num_teams integer, | |||
num_members integer, | |||
visibility integer NOT NULL DEFAULT 0, | |||
repo_admin_change_team_access boolean NOT NULL DEFAULT false, | |||
diff_view_style character varying(255), | |||
theme character varying(255), | |||
token character varying(1024) , | |||
public_key character varying(255), | |||
private_key character varying(255), | |||
is_operator boolean NOT NULL DEFAULT false, | |||
num_dataset_stars integer NOT NULL DEFAULT 0 | |||
) SERVER multicorn_es | |||
OPTIONS | |||
( | |||
host '192.168.207.94', | |||
port '9200', | |||
index 'user-es-index', | |||
rowid_column 'id', | |||
default_sort '_id' | |||
) | |||
; | |||
delete from public.user_es; | |||
INSERT INTO public.user_es( | |||
id, | |||
lower_name, | |||
name, | |||
full_name, | |||
email, | |||
keep_email_private, | |||
email_notifications_preference, | |||
must_change_password, | |||
login_type, | |||
login_source, | |||
login_name, | |||
type, | |||
location, | |||
website, | |||
rands, | |||
language, | |||
description, | |||
created_unix, | |||
updated_unix, | |||
last_login_unix, | |||
last_repo_visibility, | |||
max_repo_creation, | |||
is_active, | |||
is_restricted, | |||
allow_git_hook, | |||
allow_import_local, | |||
allow_create_organization, | |||
prohibit_login, | |||
avatar, | |||
avatar_email, | |||
use_custom_avatar, | |||
num_followers, | |||
num_following, | |||
num_stars, | |||
num_repos, | |||
num_teams, | |||
num_members, | |||
visibility, | |||
repo_admin_change_team_access, | |||
diff_view_style, | |||
theme, | |||
is_operator, | |||
num_dataset_stars) | |||
SELECT | |||
id, | |||
lower_name, | |||
name, | |||
full_name, | |||
email, | |||
keep_email_private, | |||
email_notifications_preference, | |||
must_change_password, | |||
login_type, | |||
login_source, | |||
login_name, | |||
type, | |||
location, | |||
website, | |||
rands, | |||
language, | |||
description, | |||
created_unix, | |||
updated_unix, | |||
last_login_unix, | |||
last_repo_visibility, | |||
max_repo_creation, | |||
is_active, | |||
is_restricted, | |||
allow_git_hook, | |||
allow_import_local, | |||
allow_create_organization, | |||
prohibit_login, | |||
avatar, | |||
avatar_email, | |||
use_custom_avatar, | |||
num_followers, | |||
num_following, | |||
num_stars, | |||
num_repos, | |||
num_teams, | |||
num_members, | |||
visibility, | |||
repo_admin_change_team_access, | |||
diff_view_style, | |||
theme, | |||
is_operator, | |||
num_dataset_stars | |||
FROM public.user; | |||
DROP TRIGGER IF EXISTS es_insert_user on public.user; | |||
CREATE OR REPLACE FUNCTION public.insert_user_data() RETURNS trigger AS | |||
$def$ | |||
BEGIN | |||
INSERT INTO public."user_es"( | |||
id, | |||
lower_name, | |||
name, | |||
full_name, | |||
email, | |||
keep_email_private, | |||
email_notifications_preference, | |||
must_change_password, | |||
login_type, | |||
login_source, | |||
login_name, | |||
type, | |||
location, | |||
website, | |||
rands, | |||
language, | |||
description, | |||
created_unix, | |||
updated_unix, | |||
last_login_unix, | |||
last_repo_visibility, | |||
max_repo_creation, | |||
is_active, | |||
is_restricted, | |||
allow_git_hook, | |||
allow_import_local, | |||
allow_create_organization, | |||
prohibit_login, | |||
avatar, | |||
avatar_email, | |||
use_custom_avatar, | |||
num_followers, | |||
num_following, | |||
num_stars, | |||
num_repos, | |||
num_teams, | |||
num_members, | |||
visibility, | |||
repo_admin_change_team_access, | |||
diff_view_style, | |||
theme, | |||
is_operator, | |||
num_dataset_stars) | |||
VALUES ( | |||
NEW.id, | |||
NEW.lower_name, | |||
NEW.name, | |||
NEW.full_name, | |||
NEW.email, | |||
NEW.keep_email_private, | |||
NEW.email_notifications_preference, | |||
NEW.must_change_password, | |||
NEW.login_type, | |||
NEW.login_source, | |||
NEW.login_name, | |||
NEW.type, | |||
NEW.location, | |||
NEW.website, | |||
NEW.rands, | |||
NEW.language, | |||
NEW.description, | |||
NEW.created_unix, | |||
NEW.updated_unix, | |||
NEW.last_login_unix, | |||
NEW.last_repo_visibility, | |||
NEW.max_repo_creation, | |||
NEW.is_active, | |||
NEW.is_restricted, | |||
NEW.allow_git_hook, | |||
NEW.allow_import_local, | |||
NEW.allow_create_organization, | |||
NEW.prohibit_login, | |||
NEW.avatar, | |||
NEW.avatar_email, | |||
NEW.use_custom_avatar, | |||
NEW.num_followers, | |||
NEW.num_following, | |||
NEW.num_stars, | |||
NEW.num_repos, | |||
NEW.num_teams, | |||
NEW.num_members, | |||
NEW.visibility, | |||
NEW.repo_admin_change_team_access, | |||
NEW.diff_view_style, | |||
NEW.theme, | |||
NEW.is_operator, | |||
NEW.num_dataset_stars | |||
); | |||
RETURN NEW; | |||
END; | |||
$def$ | |||
LANGUAGE plpgsql; | |||
CREATE TRIGGER es_insert_user | |||
AFTER INSERT ON public.user | |||
FOR EACH ROW EXECUTE PROCEDURE insert_user_data(); | |||
ALTER TABLE public.user ENABLE ALWAYS TRIGGER es_insert_user; | |||
DROP TRIGGER IF EXISTS es_update_user on public.user; | |||
CREATE OR REPLACE FUNCTION public.update_user() RETURNS trigger AS | |||
$def$ | |||
BEGIN | |||
UPDATE public.user_es | |||
SET description=NEW.description, | |||
name=NEW.name, | |||
full_name=NEW.full_name, | |||
location=NEW.location, | |||
website=NEW.website, | |||
email=NEW.email, | |||
num_dataset_stars=NEW.num_dataset_stars, | |||
updated_unix=NEW.updated_unix | |||
where id=NEW.id; | |||
return new; | |||
END | |||
$def$ | |||
LANGUAGE plpgsql; | |||
CREATE TRIGGER es_update_user | |||
AFTER UPDATE ON public.user | |||
FOR EACH ROW EXECUTE PROCEDURE update_user(); | |||
ALTER TABLE public.user ENABLE ALWAYS TRIGGER es_update_user; | |||
DROP TRIGGER IF EXISTS es_delete_user on public.user; | |||
CREATE OR REPLACE FUNCTION public.delete_user() RETURNS trigger AS | |||
$def$ | |||
declare | |||
BEGIN | |||
DELETE FROM public.user_es where id=OLD.id; | |||
return new; | |||
END | |||
$def$ | |||
LANGUAGE plpgsql; | |||
CREATE TRIGGER es_delete_user | |||
AFTER DELETE ON public.user | |||
FOR EACH ROW EXECUTE PROCEDURE delete_user(); | |||
ALTER TABLE public.user ENABLE ALWAYS TRIGGER es_delete_user; |
@@ -138,6 +138,7 @@ func init() { | |||
new(OfficialTag), | |||
new(OfficialTagRepos), | |||
new(WechatBindLog), | |||
new(SearchRecord), | |||
) | |||
tablesStatistic = append(tablesStatistic, | |||
@@ -6,13 +6,14 @@ | |||
package models | |||
import ( | |||
"code.gitea.io/gitea/modules/git" | |||
"context" | |||
"crypto/md5" | |||
"errors" | |||
"fmt" | |||
"html/template" | |||
"math/rand" | |||
"code.gitea.io/gitea/modules/git" | |||
"xorm.io/xorm" | |||
"code.gitea.io/gitea/modules/blockchain" | |||
@@ -191,6 +191,7 @@ type SearchRepoOptions struct { | |||
// True -> include just courses | |||
// False -> include just no courses | |||
Course util.OptionalBool | |||
OnlySearchPrivate bool | |||
} | |||
//SearchOrderBy is used to sort the result | |||
@@ -219,12 +220,15 @@ const ( | |||
SearchOrderByDownloadTimes SearchOrderBy = "download_times DESC" | |||
SearchOrderByHot SearchOrderBy = "(num_watches + num_stars + num_forks + clone_cnt) DESC" | |||
SearchOrderByActive SearchOrderBy = "(num_issues + num_pulls + num_commit) DESC" | |||
SearchOrderByWatches SearchOrderBy = "num_watches DESC" | |||
) | |||
// SearchRepositoryCondition creates a query condition according search repository options | |||
func SearchRepositoryCondition(opts *SearchRepoOptions) builder.Cond { | |||
var cond = builder.NewCond() | |||
if opts.OnlySearchPrivate { | |||
cond = cond.And(builder.Eq{"is_private": true}) | |||
} | |||
if opts.Private { | |||
if opts.Actor != nil && !opts.Actor.IsAdmin && opts.Actor.ID != opts.OwnerID { | |||
// OK we're in the context of a User | |||
@@ -337,7 +341,7 @@ func SearchRepositoryCondition(opts *SearchRepoOptions) builder.Cond { | |||
if !opts.TopicOnly { | |||
var likes = builder.NewCond() | |||
for _, v := range strings.Split(opts.Keyword, ",") { | |||
likes = likes.Or(builder.Like{"lower_name", strings.ToLower(v)}) | |||
likes = likes.Or(builder.Like{"lower_alias", strings.ToLower(v)}) | |||
likes = likes.Or(builder.Like{"alias", v}) | |||
if opts.IncludeDescription { | |||
likes = likes.Or(builder.Like{"LOWER(description)", strings.ToLower(v)}) | |||
@@ -0,0 +1,83 @@ | |||
package models | |||
import ( | |||
"code.gitea.io/gitea/modules/log" | |||
"code.gitea.io/gitea/modules/timeutil" | |||
"xorm.io/xorm" | |||
) | |||
type SearchRecord struct { | |||
ID int64 `xorm:"pk autoincr"` | |||
//user | |||
Keyword string `xorm:"NOT NULL"` | |||
// | |||
CreatedUnix timeutil.TimeStamp `xorm:"INDEX created"` | |||
} | |||
func SaveSearchKeywordToDb(keyword string) error { | |||
record := &SearchRecord{ | |||
Keyword: keyword, | |||
} | |||
sess := x.NewSession() | |||
defer sess.Close() | |||
_, err := sess.Insert(record) | |||
if err != nil { | |||
log.Info("insert error." + err.Error()) | |||
return err | |||
} | |||
return nil | |||
} | |||
func setIssueQueryCondition(sess *xorm.Session, Keyword string, isPull bool, userId int64) { | |||
sess.And("issue.poster_id=?", userId) | |||
sess.And("issue.is_pull=?", isPull) | |||
sess.And("(issue.name like '%" + Keyword + "%' or issue.content like '%" + Keyword + "%')") | |||
sess.Join("INNER", "repository", "issue.repo_id = repository.id").And("repository.is_private = ?", true) | |||
} | |||
func SearchPrivateIssueOrPr(Page int, PageSize int, Keyword string, isPull bool, userId int64) ([]*Issue, int64, error) { | |||
sess := x.NewSession() | |||
defer sess.Close() | |||
setIssueQueryCondition(sess, Keyword, isPull, userId) | |||
count, err := sess.Count(new(Issue)) | |||
if err != nil { | |||
return nil, 0, err | |||
} | |||
setIssueQueryCondition(sess, Keyword, isPull, userId) | |||
sess.Desc("issue.created_unix") | |||
sess.Limit(PageSize, (Page-1)*PageSize) | |||
issues := make([]*Issue, 0) | |||
if err := sess.Find(&issues); err != nil { | |||
return nil, 0, err | |||
} else { | |||
return issues, count, nil | |||
} | |||
} | |||
func setDataSetQueryCondition(sess *xorm.Session, Keyword string, userId int64) { | |||
sess.And("dataset.user_id=?", userId) | |||
sess.And("(dataset.title like '%" + Keyword + "%' or dataset.description like '%" + Keyword + "%')") | |||
sess.Join("INNER", "repository", "dataset.repo_id = repository.id").And("repository.is_private = ?", true) | |||
} | |||
func SearchDatasetBySQL(Page int, PageSize int, Keyword string, userId int64) ([]*Dataset, int64, error) { | |||
sess := x.NewSession() | |||
defer sess.Close() | |||
setDataSetQueryCondition(sess, Keyword, userId) | |||
count, err := sess.Count(new(Dataset)) | |||
if err != nil { | |||
return nil, 0, err | |||
} | |||
setDataSetQueryCondition(sess, Keyword, userId) | |||
sess.Desc("dataset.created_unix") | |||
sess.Limit(PageSize, (Page-1)*PageSize) | |||
datasets := make([]*Dataset, 0) | |||
if err := sess.Find(&datasets); err != nil { | |||
return nil, 0, err | |||
} else { | |||
return datasets, count, nil | |||
} | |||
} |
@@ -437,7 +437,7 @@ var ( | |||
//home page | |||
RecommentRepoAddr string | |||
ESSearchURL string | |||
//notice config | |||
UserNameOfNoticeRepo string | |||
RepoNameOfNoticeRepo string | |||
@@ -1267,6 +1267,7 @@ func NewContext() { | |||
sec = Cfg.Section("homepage") | |||
RecommentRepoAddr = sec.Key("Address").MustString("https://git.openi.org.cn/OpenIOSSG/promote/raw/branch/master/") | |||
ESSearchURL = sec.Key("ESSearchURL").MustString("http://192.168.207.94:9200") | |||
sec = Cfg.Section("notice") | |||
UserNameOfNoticeRepo = sec.Key("USER_NAME").MustString("OpenIOSSG") | |||
@@ -254,6 +254,18 @@ page_dev_yunlao_desc3=Developers can freely choose the corresponding computing r | |||
page_dev_yunlao_desc4=If your model requires more computing resources, you can also apply for it separately. | |||
page_dev_yunlao_apply=Apply Separately | |||
search=Search | |||
search_repo=Repository | |||
search_dataset=DataSet | |||
search_issue=Issue | |||
search_pr=Pull Request | |||
search_user=User | |||
search_org=Organization | |||
search_finded=Find | |||
search_related=related | |||
search_maybe=maybe | |||
search_ge= | |||
[explore] | |||
repos = Repositories | |||
select_repos = Select the project | |||
@@ -256,6 +256,18 @@ page_dev_yunlao_desc3=开发者可以根据使用需求,自由选择相应计 | |||
page_dev_yunlao_desc4=如果您的模型需要更多的计算资源,也可以单独申请 | |||
page_dev_yunlao_apply=单独申请 | |||
search=搜索 | |||
search_repo=项目 | |||
search_dataset=数据集 | |||
search_issue=任务 | |||
search_pr=合并请求 | |||
search_user=用户 | |||
search_org=组织 | |||
search_finded=找到 | |||
search_related=相关 | |||
search_maybe=约为 | |||
search_ge=个 | |||
[explore] | |||
repos=项目 | |||
select_repos=精选项目 | |||
@@ -0,0 +1,1281 @@ | |||
var token; | |||
if(isEmpty(token)){ | |||
var meta = $("meta[name=_uid]"); | |||
if(!isEmpty(meta)){ | |||
token = meta.attr("content"); | |||
console.log("token is uid:" + token); | |||
} | |||
} | |||
var html =document.documentElement; | |||
var lang = html.attributes["lang"] | |||
var isZh = true; | |||
if(lang != null && lang.nodeValue =="en-US" ){ | |||
console.log("the language is " + lang.nodeValue); | |||
isZh=false; | |||
}else{ | |||
console.log("default lang=zh"); | |||
} | |||
function isEmpty(str){ | |||
if(typeof str == "undefined" || str == null || str == ""){ | |||
return true; | |||
} | |||
return false; | |||
} | |||
var itemType={ | |||
"1":"repository", | |||
"2":"issue", | |||
"3":"user", | |||
"4":"org", | |||
"5":"dataset", | |||
"6":"pr" | |||
}; | |||
var sortBy={ | |||
"10":"default", | |||
"11":"updated_unix.keyword", | |||
"12":"num_watches", | |||
"13":"num_stars", | |||
"14":"num_forks", | |||
"20":"default", | |||
"21":"updated_unix.keyword", | |||
"30":"default", | |||
"31":"name.keyword", | |||
"32":"name.keyword", | |||
"33":"created_unix.keyword", | |||
"34":"created_unix.keyword", | |||
"40":"default", | |||
"41":"name.keyword", | |||
"42":"name.keyword", | |||
"43":"created_unix.keyword", | |||
"44":"created_unix.keyword", | |||
"50":"default", | |||
"51":"download_times", | |||
"60":"default", | |||
"61":"updated_unix.keyword" | |||
}; | |||
var sortAscending={ | |||
"10":"false", | |||
"11":"false", | |||
"12":"false", | |||
"13":"false", | |||
"14":"false", | |||
"20":"false", | |||
"21":"false", | |||
"30":"false", | |||
"31":"true", | |||
"32":"false", | |||
"33":"false", | |||
"34":"true", | |||
"40":"false", | |||
"41":"true", | |||
"42":"false", | |||
"43":"false", | |||
"44":"true", | |||
"50":"false", | |||
"51":"false", | |||
"60":"false", | |||
"61":"false" | |||
}; | |||
var currentPage = 1; | |||
var pageSize = 15; | |||
var currentSearchTableName ="repository"; | |||
var currentSearchKeyword=""; | |||
var currentSearchSortBy=""; | |||
var currentSearchAscending="false"; | |||
var OnlySearchLabel=false; | |||
var startIndex =1; | |||
var endIndex = 5; | |||
var totalPage = 1; | |||
var totalNum = 0; | |||
var privateTotal = 0; | |||
function initPageInfo(){ | |||
currentPage = 1; | |||
startIndex =1; | |||
endIndex = 5; | |||
} | |||
function searchItem(type,sortType){ | |||
console.log("enter item 2."); | |||
currentSearchKeyword = document.getElementById("keyword_input").value; | |||
if(!isEmpty(currentSearchKeyword)){ | |||
initPageInfo(); | |||
currentSearchTableName = itemType[type]; | |||
currentSearchSortBy = sortBy[sortType]; | |||
currentSearchAscending = sortAscending[sortType]; | |||
OnlySearchLabel =false; | |||
page(currentPage); | |||
} | |||
} | |||
function search(){ | |||
console.log("enter here 1."); | |||
currentSearchKeyword = document.getElementById("keyword_input").value; | |||
if(!isEmpty(currentSearchKeyword)){ | |||
currentSearchKeyword = currentSearchKeyword.trim(); | |||
} | |||
$('#searchForm').addClass("hiddenSearch"); | |||
initPageInfo(); | |||
if(!isEmpty(currentSearchKeyword)){ | |||
document.getElementById("find_id").innerHTML=getLabel(isZh,"search_finded"); | |||
currentSearchSortBy = sortBy[10]; | |||
currentSearchAscending = "false"; | |||
OnlySearchLabel =false; | |||
page(currentPage); | |||
if(currentSearchTableName != "repository"){ | |||
doSearch("repository",currentSearchKeyword,1,pageSize,true,"",false); | |||
} | |||
if(currentSearchTableName != "issue"){ | |||
doSearch("issue",currentSearchKeyword,1,pageSize,true,"",false); | |||
} | |||
if(currentSearchTableName != "user"){ | |||
doSearch("user",currentSearchKeyword,1,pageSize,true,"",false); | |||
} | |||
if(currentSearchTableName != "org"){ | |||
doSearch("org",currentSearchKeyword,1,pageSize,true,"",false); | |||
} | |||
if(currentSearchTableName != "dataset"){ | |||
doSearch("dataset",currentSearchKeyword,1,pageSize,true,"",false); | |||
} | |||
if(currentSearchTableName != "pr"){ | |||
doSearch("pr",currentSearchKeyword,1,pageSize,true,"",false); | |||
} | |||
}else{ | |||
initDiv(false); | |||
document.getElementById("find_id").innerHTML=getLabel(isZh,"search_empty"); | |||
$('#find_title').html(""); | |||
document.getElementById("sort_type").innerHTML=""; | |||
document.getElementById("child_search_item").innerHTML=""; | |||
document.getElementById("page_menu").innerHTML=""; | |||
$('#repo_total').text(""); | |||
$('#pr_total').text(""); | |||
$('#issue_total').text(""); | |||
$('#dataset_total').text(""); | |||
$('#user_total').text(""); | |||
$('#org_total').text(""); | |||
setActivate(null); | |||
} | |||
} | |||
function initDiv(isSearchLabel=false){ | |||
if(isSearchLabel){ | |||
document.getElementById("search_div").style.display="none"; | |||
document.getElementById("search_label_div").style.display="block"; | |||
document.getElementById("dataset_item").style.display="none"; | |||
document.getElementById("issue_item").style.display="none"; | |||
document.getElementById("pr_item").style.display="none"; | |||
document.getElementById("user_item").style.display="none"; | |||
document.getElementById("org_item").style.display="none"; | |||
document.getElementById("find_id").innerHTML=""; | |||
}else{ | |||
document.getElementById("search_div").style.display="block"; | |||
document.getElementById("search_label_div").style.display="none"; | |||
document.getElementById("dataset_item").style.display="block"; | |||
document.getElementById("issue_item").style.display="block"; | |||
document.getElementById("pr_item").style.display="block"; | |||
document.getElementById("user_item").style.display="block"; | |||
document.getElementById("org_item").style.display="block"; | |||
document.getElementById("find_id").innerHTML=getLabel(isZh,"search_finded"); | |||
} | |||
} | |||
function doSearchLabel(tableName,keyword,sortBy="",ascending="false"){ | |||
initDiv(true); | |||
//document.getElementById("search_div").style.display="none"; | |||
//document.getElementById("search_label_div").style.display="block"; | |||
document.getElementById("search_label_div").innerHTML="<p class=\"searchlabel\">#" + keyword + "</p>"; | |||
currentSearchKeyword = keyword; | |||
initPageInfo(); | |||
currentSearchTableName = tableName; | |||
currentSearchSortBy = sortBy; | |||
currentSearchAscending = ascending; | |||
OnlySearchLabel =true; | |||
page(currentPage); | |||
} | |||
function searchLabel(tableName,keyword,sortBy="",ascending="false"){ | |||
sessionStorage.setItem("keyword",keyword); | |||
sessionStorage.setItem("tableName",tableName); | |||
sessionStorage.setItem("searchLabel",true); | |||
sessionStorage.setItem("sortBy",sortBy); | |||
sessionStorage.setItem("ascending",ascending); | |||
console.log("enter label search."); | |||
window.open("/all/search/"); | |||
} | |||
function doSearch(tableName,keyword,page,pageSize=15,onlyReturnNum=true,sortBy="",OnlySearchLabel=false){ | |||
var language = "zh-CN"; | |||
if(!isZh){ | |||
language="en-US"; | |||
} | |||
$.ajax({ | |||
type:"GET", | |||
url:"/all/dosearch/", | |||
headers: { | |||
authorization:token, | |||
}, | |||
dataType:"json", | |||
data:{ | |||
'TableName': tableName, | |||
'Key': keyword, | |||
'Page': page, | |||
'PageSize': pageSize, | |||
'OnlyReturnNum':onlyReturnNum, | |||
'SortBy':sortBy, | |||
'OnlySearchLabel':OnlySearchLabel, | |||
'Ascending':currentSearchAscending, | |||
'WebTotal':totalNum, | |||
'PrivateTotal':privateTotal, | |||
'language':language | |||
}, | |||
async:true, | |||
success:function(json){ | |||
console.log("tableName=" + tableName); | |||
console.log(json); | |||
displayResult(tableName,page,json,onlyReturnNum,keyword); | |||
}, | |||
error:function(response) { | |||
console.log(response); | |||
} | |||
}); | |||
} | |||
function displayResult(tableName,page,jsonResult,onlyReturnNum,keyword){ | |||
if(tableName == "repository") { | |||
displayRepoResult(page,jsonResult,onlyReturnNum,keyword); | |||
} else if (tableName == "issue") { | |||
displayIssueResult(page,jsonResult,onlyReturnNum,keyword); | |||
} else if (tableName == "user") { | |||
displayUserResult(page,jsonResult,onlyReturnNum,keyword); | |||
} else if (tableName == "org") { | |||
displayOrgResult(page,jsonResult,onlyReturnNum,keyword); | |||
} else if (tableName == "dataset") { | |||
displayDataSetResult(page,jsonResult,onlyReturnNum,keyword); | |||
} else if (tableName == "pr") { | |||
displayPrResult(page,jsonResult,onlyReturnNum,keyword); | |||
} | |||
if(!onlyReturnNum){ | |||
console.log("set total num." + tableName); | |||
totalPage =Math.ceil(jsonResult.Total/pageSize); | |||
totalNum = jsonResult.Total; | |||
privateTotal = jsonResult.PrivateTotal; | |||
setPage(page); | |||
} | |||
} | |||
function displayPrResult(page,jsonResult,onlyReturnNum,keyword){ | |||
var data = jsonResult.Result; | |||
var total = jsonResult.Total; | |||
$('#pr_total').text(total); | |||
if(!onlyReturnNum){ | |||
setActivate("pr_item"); | |||
//$('#keyword_desc').text(keyword); | |||
//$('#obj_desc').text(getLabel(isZh,"search_pr")); | |||
//$('#child_total').text(total); | |||
$('#find_title').html(getLabel(isZh,"find_title").replace('{keyword}',keyword).replace('{tablename}',getLabel(isZh,"search_pr")).replace('{total}',total)); | |||
setIssueOrPrInnerHtml(data,"pulls"); | |||
} | |||
} | |||
var categoryDesc={ | |||
"computer_vision":"计算机视觉", | |||
"natural_language_processing":"自然语言处理", | |||
"speech_processing":"语音处理", | |||
"computer_vision_natural_language_processing":"计算机视觉、自然语言处理" | |||
}; | |||
var categoryENDesc={ | |||
"computer_vision":"computer vision", | |||
"natural_language_processing":"natural language processing", | |||
"speech_processing":"speech processing", | |||
"computer_vision_natural_language_processing":"computer vision and natural language processing" | |||
}; | |||
var taskDesc={ | |||
"machine_translation":"机器翻译", | |||
"question_answering_system":"问答系统", | |||
"information_retrieval":"信息检索", | |||
"knowledge_graph":"知识图谱", | |||
"text_annotation":"文本标注", | |||
"text_categorization":"文本分类", | |||
"emotion_analysis":"情感分析", | |||
"language_modeling":"语言建模", | |||
"speech_recognition":"语音识别", | |||
"automatic_digest":"自动文摘", | |||
"information_extraction":"信息抽取", | |||
"description_generation":"说明生成", | |||
"image_classification":"图像分类", | |||
"face_recognition":"人脸识别", | |||
"image_search":"图像搜索", | |||
"target_detection":"目标检测", | |||
"image_description_generation":"图像描述生成", | |||
"vehicle_license_plate_recognition":"车辆车牌识别", | |||
"medical_image_analysis":"医学图像分析", | |||
"unmanned":"无人驾驶", | |||
"unmanned_security":"无人安防", | |||
"drone":"无人机", | |||
"vr_ar":"VR/AR", | |||
"2_d_vision":"2-D视觉", | |||
"2_5_d_vision":"2.5-D视觉", | |||
"3_d_reconstruction":"3D重构", | |||
"image_processing":"图像处理", | |||
"video_processing":"视频处理", | |||
"visual_input_system":"视觉输入系统", | |||
"speech_coding":"语音编码", | |||
"speech_enhancement":"语音增强", | |||
"speech_recognition":"语音识别", | |||
"speech_synthesis":"语音合成" | |||
}; | |||
var taskENDesc={ | |||
"machine_translation":"machine translation", | |||
"question_answering_system":"question answering system", | |||
"information_retrieval":"information retrieval", | |||
"knowledge_graph":"knowledge graph", | |||
"text_annotation":"text annotation", | |||
"text_categorization":"text categorization", | |||
"emotion_analysis":"emotion analysis", | |||
"language_modeling":"language modeling", | |||
"speech_recognition":"speech recognition", | |||
"automatic_digest":"automatic digest", | |||
"information_extraction":"information extraction", | |||
"description_generation":"description generation", | |||
"image_classification":"image classification", | |||
"face_recognition":"face recognition", | |||
"image_search":"image search", | |||
"target_detection":"target detection", | |||
"image_description_generation":"image description generation", | |||
"vehicle_license_plate_recognition":"vehicle license plate recognition", | |||
"medical_image_analysis":"medical image analysis", | |||
"unmanned":"unmanned", | |||
"unmanned_security":"unmanned security", | |||
"drone":"drone", | |||
"vr_ar":"VR/AR", | |||
"2_d_vision":"2.D vision", | |||
"2.5_d_vision":"2.5D vision", | |||
"3_d_reconstruction":"3Dreconstruction", | |||
"image_processing":"image processing", | |||
"video_processing":"video processing", | |||
"visual_input_system":"visual input system", | |||
"speech_coding":"speech coding", | |||
"speech_enhancement":"speech enhancement", | |||
"speech_recognition":"speech recognition", | |||
"speech_synthesis":"speech synthesis" | |||
}; | |||
function getCategoryDesc(isZh,key){ | |||
var re = key; | |||
if(isZh){ | |||
re = categoryDesc[key]; | |||
}else{ | |||
re = categoryENDesc[key]; | |||
} | |||
if(isEmpty(re)){ | |||
return key; | |||
} | |||
return re; | |||
} | |||
function getTaskDesc(isZh,key){ | |||
var re = key; | |||
if(isZh){ | |||
re = taskDesc[key]; | |||
}else{ | |||
re = taskENDesc[key]; | |||
} | |||
if(isEmpty(re)){ | |||
return key; | |||
} | |||
return re; | |||
} | |||
function getActiveItem(sort_type){ | |||
console.log("currentSearchSortBy=" + currentSearchSortBy + " sort_type=" + sortBy[sort_type]); | |||
if(currentSearchSortBy == sortBy[sort_type] && currentSearchAscending == sortAscending[sort_type]){ | |||
return "active "; | |||
}else{ | |||
return ""; | |||
} | |||
} | |||
function displayDataSetResult(page,jsonResult,onlyReturnNum,keyword){ | |||
var data = jsonResult.Result; | |||
var total = jsonResult.Total; | |||
$('#dataset_total').text(total); | |||
if(!onlyReturnNum){ | |||
setActivate("dataset_item"); | |||
//$('#keyword_desc').text(keyword); | |||
//$('#obj_desc').text(getLabel(isZh,"search_dataset")); | |||
//$('#child_total').text(total); | |||
$('#find_title').html(getLabel(isZh,"find_title").replace('{keyword}',keyword).replace('{tablename}',getLabel(isZh,"search_dataset")).replace('{total}',total)); | |||
var sortHtml = ""; | |||
sortHtml +="<a class=\"" + getActiveItem(50) + "item\" href=\"javascript:searchItem(5,50);\" tabindex=\"-1\" role=\"menuitem\" id=\"menuitem_1\">"+ getLabel(isZh,"search_matched") + "</a>"; | |||
sortHtml +="<a class=\"" + getActiveItem(51) + "item\" href=\"javascript:searchItem(5,51);\" tabindex=\"-1\" role=\"menuitem\" id=\"menuitem_1\">"+ getLabel(isZh,"search_matched_download") + "</a>"; | |||
document.getElementById("sort_type").innerHTML=sortHtml; | |||
var html = ""; | |||
var currentTime = new Date().getTime(); | |||
for(var i = 0; i < data.length;i++){ | |||
var recordMap = data[i]; | |||
html += "<div class=\"item\">"; | |||
html += " <div class=\"content\">"; | |||
html += " <div class=\"ui right metas\">" ; | |||
if(!isEmpty(recordMap["category"])){ | |||
html += " <span class=\"text grey\"><svg class=\"svg octicon-tasklist\" width=\"16\" height=\"16\" aria-hidden=\"true\"><use xlink:href=\"#octicon-tasklist\" /></svg> " + getCategoryDesc(isZh,recordMap["category"]) + "</span>"; | |||
} | |||
if(!isEmpty(recordMap["task"])){ | |||
html += " <span class=\"text grey\"><svg class=\"svg octicon-tag\" width=\"16\" height=\"16\" aria-hidden=\"true\"><use xlink:href=\"#octicon-tag\" /></svg>" + getTaskDesc(isZh,recordMap["task"]) + "</span>"; | |||
} | |||
html += " <span class=\"text grey\"><i class=\"ri-fire-line\"></i> " +recordMap["download_times"] + "</span> "; | |||
html +=" </div>"; | |||
html += " <div class=\"ui header\">"; | |||
html += " <a class=\"name\" href=\"/" +recordMap["repoUrl"] +"/datasets\" target=\"_blank\">" + recordMap["title"] + "</a>"; | |||
html +=" <span class=\"middle\"><svg class=\"svg octicon-repo-clone\" width=\"16\" height=\"16\" aria-hidden=\"true\"><use xlink:href=\"#octicon-repo-clone\"></use></svg></span>"; | |||
html +=" </div>"; | |||
html += " <div class=\"description\">"; | |||
html += " <p class=\"has-emoji\"> " + recordMap["description"] + "</p>"; | |||
if(!isEmpty(recordMap["file_name"])){ | |||
html += " <p class=\"has-emoji\"> " + recordMap["file_name"] + "</p>"; | |||
} | |||
html +=" <p class=\"time\">"; | |||
html +=" <span class=\"am-ml-10\"></span> "+ getLabel(isZh,"search_lasted_update") + " " + recordMap["updated_html"]; | |||
html +=" </p>"; | |||
html +=" </div>"; | |||
html +=" </div>"; | |||
html +="</div>"; | |||
} | |||
document.getElementById("child_search_item").innerHTML=html; | |||
} | |||
} | |||
function displayOrgResult(page,jsonResult,onlyReturnNum,keyword){ | |||
var data = jsonResult.Result; | |||
var total = jsonResult.Total; | |||
$('#org_total').text(total); | |||
if(!onlyReturnNum){ | |||
setActivate("org_item"); | |||
//$('#keyword_desc').text(keyword); | |||
//$('#obj_desc').text(getLabel(isZh,"search_org")); | |||
//$('#child_total').text(total); | |||
$('#find_title').html(getLabel(isZh,"find_title").replace('{keyword}',keyword).replace('{tablename}',getLabel(isZh,"search_org")).replace('{total}',total)); | |||
var sortHtml = ""; | |||
sortHtml +="<a class=\"" + getActiveItem(40) + "item\" href=\"javascript:searchItem(4,40);\" tabindex=\"-1\" role=\"menuitem\" id=\"menuitem_1\">"+ getLabel(isZh,"search_matched") + "</a>"; | |||
sortHtml +="<a class=\"" + getActiveItem(41) + "item\" href=\"javascript:searchItem(4,41);\" tabindex=\"-1\" role=\"menuitem\" id=\"menuitem_1\">"+ getLabel(isZh,"search_letter_asc") + "</a>"; | |||
sortHtml +="<a class=\"" + getActiveItem(42) + "item\" href=\"javascript:searchItem(4,42);\" tabindex=\"-1\" role=\"menuitem\" id=\"menuitem_2\">"+ getLabel(isZh,"search_letter_desc") + "</a>"; | |||
sortHtml +="<a class=\"" + getActiveItem(43) + "item\" href=\"javascript:searchItem(4,43);\" tabindex=\"-1\" role=\"menuitem\" id=\"menuitem_2\">"+ getLabel(isZh,"search_lasted_create") + "</a>"; | |||
sortHtml +="<a class=\"" + getActiveItem(44) + "item\" href=\"javascript:searchItem(4,44);\" tabindex=\"-1\" role=\"menuitem\" id=\"menuitem_2\">"+ getLabel(isZh,"search_early_create") + "</a>"; | |||
document.getElementById("sort_type").innerHTML=sortHtml; | |||
var html = ""; | |||
var currentTime = new Date().getTime(); | |||
for(var i = 0; i < data.length;i++){ | |||
var recordMap = data[i]; | |||
html += "<div class=\"item members\">"; | |||
html += "<img class=\"ui avatar image\" src=\"" + recordMap["avatar"] + "\"></img>"; | |||
html += " <div class=\"content\">"; | |||
html += " <div class=\"ui header\">"; | |||
html += " <a class=\"name\" href=\"/" + recordMap["real_name"] +"\" target=\"_blank\">" + recordMap["name"] + " " + recordMap["full_name"] + "</a>"; | |||
html +=" </div>"; | |||
html += " <div class=\"description\">"; | |||
html += " <p class=\"has-emoji\"> " + recordMap["description"] + "</p>"; | |||
html +=" <p class=\"has-emoji\">"; | |||
if(!isEmpty(recordMap["location"]) && recordMap["location"] != "null"){ | |||
html +=" <i class=\"ri-map-pin-2-line\"></i> " + recordMap["location"]; | |||
} | |||
html +=" <span class=\"am-ml-10\"></span>"; | |||
if(!isEmpty(recordMap["website"]) && recordMap["website"] != "null"){ | |||
html +=" <i class=\"ri-links-line\"></i>" + "<a href=\""+ recordMap["website"] + "\" target=\"_blank\">" + recordMap["website"] + "</a>"; | |||
} | |||
html +=" <i class=\"ri-time-line am-ml-10\"></i> "+ getLabel(isZh,"search_add_by") + " "; | |||
html += recordMap["add_time"] | |||
html +=" </p>"; | |||
html +=" </div>"; | |||
html +=" </div>"; | |||
html +="</div>"; | |||
} | |||
document.getElementById("child_search_item").innerHTML=html; | |||
} | |||
} | |||
var monthDisplay=new Array("Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Spt","Oct","Nov","Dec"); | |||
function displayUserResult(page,jsonResult,onlyReturnNum,keyword){ | |||
var data = jsonResult.Result; | |||
var total = jsonResult.Total; | |||
$('#user_total').text(total); | |||
if(!onlyReturnNum){ | |||
setActivate("user_item"); | |||
//$('#keyword_desc').text(keyword); | |||
//$('#obj_desc').text(getLabel(isZh,"search_user")); | |||
//$('#child_total').text(total); | |||
$('#find_title').html(getLabel(isZh,"find_title").replace('{keyword}',keyword).replace('{tablename}',getLabel(isZh,"search_user")).replace('{total}',total)); | |||
var sortHtml = "";//equal user sort by | |||
sortHtml +="<a class=\"" + getActiveItem(30) + "item\" href=\"javascript:searchItem(3,30);\" tabindex=\"-1\" role=\"menuitem\" id=\"menuitem_1\">"+ getLabel(isZh,"search_matched") + "</a>"; | |||
sortHtml +="<a class=\"" + getActiveItem(31) + "item\" href=\"javascript:searchItem(3,31);\" tabindex=\"-1\" role=\"menuitem\" id=\"menuitem_1\">"+ getLabel(isZh,"search_letter_asc") + "</a>"; | |||
sortHtml +="<a class=\"" + getActiveItem(32) + "item\" href=\"javascript:searchItem(3,32);\" tabindex=\"-1\" role=\"menuitem\" id=\"menuitem_2\">"+ getLabel(isZh,"search_letter_desc") + "</a>"; | |||
sortHtml +="<a class=\"" + getActiveItem(33) + "item\" href=\"javascript:searchItem(3,33);\" tabindex=\"-1\" role=\"menuitem\" id=\"menuitem_2\">"+ getLabel(isZh,"search_lasted_create") + "</a>"; | |||
sortHtml +="<a class=\"" + getActiveItem(34) + "item\" href=\"javascript:searchItem(3,34);\" tabindex=\"-1\" role=\"menuitem\" id=\"menuitem_2\">"+ getLabel(isZh,"search_early_create") + "</a>"; | |||
document.getElementById("sort_type").innerHTML=sortHtml; | |||
var html = ""; | |||
var currentTime = new Date().getTime(); | |||
for(var i = 0; i < data.length;i++){ | |||
var recordMap = data[i]; | |||
html += "<div class=\"item members\">"; | |||
html += "<img class=\"ui avatar image\" src=\"" + recordMap["avatar"] + "\"></img>"; | |||
html += " <div class=\"content\">"; | |||
html += " <div class=\"ui header\">"; | |||
html += " <a class=\"name\" href=\"/" + recordMap["real_name"] +"\" target=\"_blank\">" + recordMap["name"] + " " + recordMap["full_name"] + "</a>"; | |||
html +=" </div>"; | |||
html += " <div class=\"description\">"; | |||
html += " <p class=\"has-emoji\"> " + recordMap["description"] + "</p>"; | |||
html +=" <p class=\"has-emoji\">"; | |||
if(!isEmpty(recordMap["email"]) && recordMap["email"] != "null"){ | |||
html +=" <i class=\"ri-mail-line\"></i> <a href=\"mailto:" + recordMap["email"] + "\" rel=\"nofollow\">" + recordMap["email"] + "</a>"; | |||
} | |||
html +=" <i class=\"ri-time-line am-ml-10\"></i> "+ getLabel(isZh,"search_add_by") + " "; | |||
html += recordMap["add_time"] | |||
html +=" </p>"; | |||
html +=" </div>"; | |||
html +=" </div>"; | |||
html +="</div>"; | |||
} | |||
document.getElementById("child_search_item").innerHTML=html; | |||
} | |||
} | |||
function setIssueOrPrInnerHtml(data,path){ | |||
var sortHtml = ""; | |||
if(path =="issues"){ | |||
sortHtml +="<a class=\"" + getActiveItem(20) + "item\" href=\"javascript:searchItem(2,20);\" tabindex=\"-1\" role=\"menuitem\" id=\"menuitem_1\">"+ getLabel(isZh,"search_matched") + "</a>"; | |||
sortHtml +="<a class=\"" + getActiveItem(21) + "item\" href=\"javascript:searchItem(2,21);\" tabindex=\"-1\" role=\"menuitem\" id=\"menuitem_1\">"+ getLabel(isZh,"search_lasted") + "</a>"; | |||
}else{ | |||
sortHtml +="<a class=\"" + getActiveItem(60) + "item\" href=\"javascript:searchItem(6,60);\" tabindex=\"-1\" role=\"menuitem\" id=\"menuitem_1\">"+ getLabel(isZh,"search_matched") + "</a>"; | |||
sortHtml +="<a class=\"" + getActiveItem(61) + "item\" href=\"javascript:searchItem(6,61);\" tabindex=\"-1\" role=\"menuitem\" id=\"menuitem_1\">"+ getLabel(isZh,"search_lasted") + "</a>"; | |||
} | |||
document.getElementById("sort_type").innerHTML=sortHtml; | |||
var html = ""; | |||
var currentTime = new Date().getTime(); | |||
for(var i = 0; i < data.length;i++){ | |||
var recordMap = data[i]; | |||
html += "<div class=\"item\">"; | |||
html += " <div class=\"content\">"; | |||
html += " <div class=\"ui header\">"; | |||
html += " <a class=\"name\" href=\"/" + recordMap["repoUrl"] +"/" + path + "/" + recordMap["index"] + "\" target=\"_blank\">" + recordMap["name"] + "</a>"; | |||
html +=" </div>"; | |||
html += " <div class=\"description\">"; | |||
html += " <p class=\"has-emoji\"> " + recordMap["content"] + "</p>"; | |||
html +=" <p class=\"time\">"; | |||
html +=" <i class=\"ri-code-box-line\"></i>"; | |||
html +=" <a class=\"am-text grey\" href=\"/" + recordMap["repoUrl"] +"/" + path + "/" + recordMap["index"] + "\" target=\"_blank\"> " + addBlank(recordMap["repoUrl"]) +" #" + recordMap["index"] + "</a> "; | |||
html +=" <i class=\"ri-information-line am-ml-10\"></i> "; | |||
if(recordMap["is_closed"] != null && (!(recordMap["is_closed"]) || recordMap["is_closed"]=="f")){ | |||
html += getLabel(isZh,"search_open"); | |||
}else{ | |||
html += getLabel(isZh,"search_closed"); | |||
} | |||
html +=" <i class=\"ri-message-2-line am-ml-10\"></i> " + recordMap["num_comments"]; | |||
html +=" <span class=\"am-ml-10\"> </span> "+ getLabel(isZh,"search_lasted_update") + " "+ recordMap["updated_html"]; | |||
html +=" </p>"; | |||
html +=" </div>"; | |||
html +=" </div>"; | |||
html +="</div>"; | |||
} | |||
document.getElementById("child_search_item").innerHTML=html; | |||
} | |||
function addBlank(url){ | |||
if(url == null){ | |||
return url; | |||
} | |||
var tmps = url.split("/"); | |||
if(tmps.length == 2){ | |||
return tmps[0] + " / " + tmps[1]; | |||
} | |||
return url; | |||
} | |||
function displayIssueResult(page,jsonResult,onlyReturnNum,keyword){ | |||
var data = jsonResult.Result; | |||
var total = jsonResult.Total; | |||
$('#issue_total').text(total); | |||
if(!onlyReturnNum){ | |||
setActivate("issue_item"); | |||
//$('#keyword_desc').text(keyword); | |||
//$('#obj_desc').text(getLabel(isZh,"search_issue")); | |||
//$('#child_total').text(total); | |||
$('#find_title').html(getLabel(isZh,"find_title").replace('{keyword}',keyword).replace('{tablename}',getLabel(isZh,"search_issue")).replace('{total}',total)); | |||
setIssueOrPrInnerHtml(data,"issues"); | |||
} | |||
} | |||
function setActivate(name){ | |||
$('#repo_item').removeClass("active"); | |||
$('#user_item').removeClass("active"); | |||
$('#issue_item').removeClass("active"); | |||
$('#dataset_item').removeClass("active"); | |||
$('#org_item').removeClass("active"); | |||
$('#pr_item').removeClass("active"); | |||
if(name==null){ | |||
return; | |||
} | |||
var tmp = "#" + name; | |||
$(tmp).addClass("active"); | |||
} | |||
function displayRepoResult(page,jsonResult,onlyReturnNum,keyword){ | |||
var data = jsonResult.Result; | |||
var total = jsonResult.Total; | |||
$('#repo_total').text(total); | |||
if(!onlyReturnNum){ | |||
setActivate("repo_item"); | |||
// $('#keyword_desc').text(keyword); | |||
//$('#obj_desc').text(getLabel(isZh,"search_repo")); | |||
//$('#child_total').text(total); | |||
$('#find_title').html(getLabel(isZh,"find_title").replace('{keyword}',keyword).replace('{tablename}',getLabel(isZh,"search_repo")).replace('{total}',total)); | |||
var sortHtml = ""; | |||
sortHtml +="<a class=\"" + getActiveItem(10) + "item\" href=\"javascript:searchItem(1,10);\" tabindex=\"-1\" role=\"menuitem\" id=\"menuitem_1\">"+ getLabel(isZh,"search_matched") + "</a>"; | |||
sortHtml +="<a class=\"" + getActiveItem(11) + "item\" href=\"javascript:searchItem(1,11);\" tabindex=\"-1\" role=\"menuitem\" id=\"menuitem_1\">"+ getLabel(isZh,"search_lasted") + "</a>"; | |||
sortHtml +="<a class=\"" + getActiveItem(12) + "item\" href=\"javascript:searchItem(1,12);\" tabindex=\"-1\" role=\"menuitem\" id=\"menuitem_1\">"+ getLabel(isZh,"search_watched") + "</a>"; | |||
sortHtml +="<a class=\"" + getActiveItem(13) + "item\" href=\"javascript:searchItem(1,13);\" tabindex=\"-1\" role=\"menuitem\" id=\"menuitem_1\">"+ getLabel(isZh,"search_star") + "</a>"; | |||
sortHtml +="<a class=\"" + getActiveItem(14) + "item\" href=\"javascript:searchItem(1,14);\" tabindex=\"-1\" role=\"menuitem\" id=\"menuitem_1\">"+ getLabel(isZh,"search_fork") + "</a>"; | |||
document.getElementById("sort_type").innerHTML=sortHtml; | |||
var html = ""; | |||
var currentTime = new Date().getTime(); | |||
for(var i = 0; i < data.length;i++){ | |||
var recordMap = data[i]; | |||
html += "<div class=\"item\">"; | |||
if(!isEmpty(recordMap['avatar'])){ | |||
html += "<img class=\"ui avatar image\" src=\"" + recordMap['avatar'] + "\">"; | |||
} | |||
html += " <div class=\"content\">"; | |||
html += " <div class=\"ui header\">"; | |||
html += " <a class=\"name\" href=\"/" + recordMap["owner_name"] + "/" + recordMap["real_name"] +"\" target=\"_blank\"> <span>" + recordMap["owner_name"] +"</span> <span>/</span> <strong>" + recordMap["alias"] + "</strong></a>"; | |||
if(recordMap["is_private"]){ | |||
html +=" <span class=\"middle text gold\"><svg class=\"svg octicon-lock\" width=\"16\" height=\"16\" aria-hidden=\"true\"><use xlink:href=\"#octicon-lock\" /></svg></span>"; | |||
} | |||
html +=" </div>"; | |||
html += " <div class=\"description\">"; | |||
html += " <p class=\"has-emoji\"> " + recordMap["description"] + "</p>"; | |||
html += " <div class=\"ui tags\">"; | |||
if(!isEmpty(recordMap["topics"]) && recordMap["topics"] !="null"){ | |||
for(var j = 0; j < recordMap["topics"].length;j++){ | |||
//function searchLabel(tableName,keyword,sortBy="",ascending=false) | |||
html +=" <a href=\"javascript:searchLabel('repository','" + recordMap["topics"][j] + "','updated_unix.keyword',false);\" ><div class=\"ui small label topic\">"+ recordMap["hightTopics"][j] + "</div></a>"; | |||
} | |||
} | |||
html +=" </div>"; | |||
html +=" <p class=\"time\">"; | |||
html +=" <i class=\"icon fa-eye outline\"></i> " + recordMap["num_watches"] + " <i class=\"icon star outline\"></i> " + recordMap["num_stars"] + " <i class=\"icon code branch\"></i> " + recordMap["num_forks"] +" "; | |||
html +=" "+ getLabel(isZh,"search_lasted_update") + " " + recordMap["updated_html"]; | |||
if(!isEmpty(recordMap["lang"])){ | |||
var lang = recordMap["lang"] | |||
var tmpLang = recordMap["lang"].split(","); | |||
if(tmpLang.length>0){ | |||
lang = tmpLang[0] | |||
} | |||
var backColor = "#3572A5"; | |||
if(LanguagesColor[lang] != null){ | |||
backColor = LanguagesColor[lang]; | |||
} | |||
html +=" <span class=\"text grey am-ml-10\"><i class=\"color-icon\" style=\"background-color: "+ backColor + "\"></i> " + lang + "</span>"; | |||
} | |||
html +=" </p>"; | |||
html +=" </div>"; | |||
html +=" </div>"; | |||
html +="</div>"; | |||
} | |||
document.getElementById("child_search_item").innerHTML=html; | |||
} | |||
} | |||
function getTime(UpdatedUnix,currentTime){ | |||
UpdatedUnix = UpdatedUnix; | |||
currentTime = currentTime / 1000; | |||
var timeEscSecond = currentTime - UpdatedUnix; | |||
if( timeEscSecond < 0){ | |||
timeEscSecond = 1; | |||
} | |||
console.log("currentTime=" + currentTime + " updateUnix=" + UpdatedUnix); | |||
var hours= Math.floor(timeEscSecond / 3600); | |||
//计算相差分钟数 | |||
var leave2 = Math.floor(timeEscSecond % (3600)); //计算小时数后剩余的秒数 | |||
var minutes= Math.floor(leave2 / 60);//计算相差分钟数 | |||
var leave3=Math.floor(leave2 % 60); //计算分钟数后剩余的秒数 | |||
var seconds= leave3; | |||
if(hours == 0 && minutes == 0){ | |||
return seconds + getRepoOrOrg(6,isZh); | |||
}else{ | |||
if(hours > 0){ | |||
if(hours >= 24){ | |||
var days = Math.ceil(hours/24) | |||
if (days >= 30 && days <365){ | |||
return Math.ceil(days/30) + getRepoOrOrg(8,isZh); | |||
}else if(days >= 365){ | |||
return Math.ceil(days/365) + getRepoOrOrg(9,isZh); | |||
} | |||
return Math.ceil(hours/24) + getRepoOrOrg(7,isZh); | |||
}else{ | |||
return hours + getRepoOrOrg(4,isZh); | |||
} | |||
}else{ | |||
return minutes + getRepoOrOrg(5,isZh); | |||
} | |||
} | |||
} | |||
function getRepoOrOrg(key,isZhLang){ | |||
if(isZhLang){ | |||
return repoAndOrgZH[key]; | |||
}else{ | |||
return repoAndOrgEN[key]; | |||
} | |||
} | |||
var repoAndOrgZH={ | |||
"1":"项目", | |||
"2":"成员", | |||
"3":"团队", | |||
"4":"小时前", | |||
"5":"分钟前", | |||
"6":"秒前", | |||
"7":"天前", | |||
"8":"个月前", | |||
"9":"年前" | |||
}; | |||
var repoAndOrgEN={ | |||
"1":"repository", | |||
"2":"Members ", | |||
"3":"Teams", | |||
"4":" hours ago", | |||
"5":" minutes ago", | |||
"6":" seconds ago", | |||
"7":" day ago", | |||
"8":" month ago", | |||
"9":" year ago" | |||
}; | |||
function page(current){ | |||
currentPage=current; | |||
doSearch(currentSearchTableName,currentSearchKeyword,current,pageSize,false,currentSearchSortBy,OnlySearchLabel); | |||
} | |||
function nextPage(){ | |||
currentPage = currentPage+1; | |||
console.log("currentPage=" + currentPage); | |||
if(currentPage >= endIndex){ | |||
startIndex=startIndex+1; | |||
endIndex = endIndex +1; | |||
} | |||
page(currentPage); | |||
} | |||
function prePage(){ | |||
console.log("currentPage=" + currentPage); | |||
if(currentPage > 1){ | |||
currentPage = currentPage-1; | |||
if(currentPage <= startIndex && startIndex > 1){ | |||
startIndex = startIndex -1; | |||
endIndex = endIndex - 1; | |||
} | |||
console.log("currentPage=" + (currentPage)); | |||
page(currentPage); | |||
} | |||
} | |||
function getXPosition(e){ | |||
var x=e.offsetLeft; | |||
while(e=e.offsetParent) | |||
{ | |||
x+=e.offsetLeft; | |||
} | |||
return x+20;//-260防止屏幕超出 | |||
} | |||
//获取y坐标 | |||
function getYPosition(e){ | |||
var y=e.offsetTop; | |||
while(e=e.offsetParent) | |||
{ | |||
y+=e.offsetTop; | |||
} | |||
return y+20;//80为input高度 | |||
} | |||
function goPage(event){ | |||
var inputpage = document.getElementById("inputpage_div") | |||
var left = getXPosition(event.target); | |||
var top = getYPosition(event.target); | |||
var goNum = $('#inputpage').val(); | |||
if (goNum<=0){ | |||
showTip(getLabel(isZh,"search_input_large_0"),"warning",left+5,top); | |||
} | |||
else if(goNum<=totalPage){ | |||
page(goNum); | |||
} | |||
else{ | |||
showTip(getLabel(isZh,"search_input_maxed"),"warning",left+5,top); | |||
} | |||
} | |||
function showTip(tip, type,left,top) { | |||
var $tip = $('#tipmsg'); | |||
var tipmsg = document.getElementById("tipmsg") | |||
var style="z-index:10024;top:" + top + "px;left:" + left + "px;position:absolute;width:200px;height:60px;vertical-align:middle;"; | |||
console.log(style); | |||
tipmsg.style = style; | |||
var html ="<p>" + tip + "</p>" | |||
$tip.stop(true).prop('class', 'alert alert-' + type).html(html).fadeIn(500).delay(2000).fadeOut(500); | |||
} | |||
function setPage(currentPage){ | |||
console.log("totalPage=" + totalPage); | |||
var html =""; | |||
console.log("currentPage=" + currentPage); | |||
console.log("privateTotal=" + privateTotal); | |||
// if(totalPage==0){ | |||
// return; | |||
// } | |||
html += "<span class=\"item\">" + getLabel(isZh,"search_input_total") + " " + totalNum + " " + getLabel(isZh,"search_srtip") + "</span>" | |||
if(currentPage > 1){ | |||
html += "<a class=\"item navigation\" href=\"javascript:page(1)\"><span class=\"navigation_label\">" + getLabel(isZh,"search_home_page") + "</span></a>"; | |||
html += "<a class=\"item navigation\" href=\"javascript:prePage()\"><i class=\"left arrow icon\"></i></a>"; | |||
}else{ | |||
html += "<a class=\"disabled item navigation\" href=\"javascript:page(1)\"><span class=\"navigation_label\">" + getLabel(isZh,"search_home_page") + "</span></a>"; | |||
html += "<a class=\"disabled item navigation\" href=\"javascript:prePage()\"><i class=\"left arrow icon\"></i></a>"; | |||
} | |||
for(var i=startIndex; i <= endIndex; i++){ | |||
var page_i = i; | |||
if(page_i > totalPage){ | |||
break; | |||
} | |||
if( page_i == currentPage){ | |||
html += "<a id=\"page_" + page_i+ "\" class=\"active item\" href=\"javascript:page(" + page_i +")\">" + page_i + "</a>"; | |||
}else{ | |||
html += "<a id=\"page_" + page_i+ "\" class=\"item\" href=\"javascript:page(" + page_i +")\">" + page_i + "</a>"; | |||
} | |||
} | |||
if(currentPage >=totalPage){ | |||
html += "<a class=\"disabled item navigation\" href=\"javascript:nextPage()\"><i class=\"icon right arrow\"></i></a>"; | |||
html += "<a class=\"disabled item navigation\" href=\"javascript:page(" + totalPage + ")\"><span class=\"navigation_label\">" + getLabel(isZh,"search_last_page") + "</span></a>"; | |||
}else{ | |||
html += "<a class=\"item navigation\" href=\"javascript:nextPage()\"><i class=\"icon right arrow\"></i></a>"; | |||
html += "<a class=\"item navigation\" href=\"javascript:page(" + totalPage + ")\"><span class=\"navigation_label\">" + getLabel(isZh,"search_last_page") + "</span></a>"; | |||
} | |||
html +="<div class=\"item\"> " + getLabel(isZh,"search_go_to") + "<div id=\"inputpage_div\" class=\"ui input\"><input id=\"inputpage\" type=\"text\"></div>" + getLabel(isZh,"search_go_page") + "</div>"; | |||
console.log("html=" + html) | |||
document.getElementById("page_menu").innerHTML=html; | |||
$('#inputpage').on('keypress',function(event){ | |||
if(event.keyCode == 13){ | |||
goPage(event); | |||
} | |||
}); | |||
} | |||
$('#keyword_input').on('keypress',function(event){ | |||
if(event.keyCode == 13){ | |||
search(); | |||
} | |||
}); | |||
var LanguagesColor = { | |||
"1C Enterprise": "#814CCC", | |||
"ABAP": "#E8274B", | |||
"AGS Script": "#B9D9FF", | |||
"AMPL": "#E6EFBB", | |||
"ANTLR": "#9DC3FF", | |||
"API Blueprint": "#2ACCA8", | |||
"APL": "#5A8164", | |||
"ASP": "#6a40fd", | |||
"ATS": "#1ac620", | |||
"ActionScript": "#882B0F", | |||
"Ada": "#02f88c", | |||
"Agda": "#315665", | |||
"Alloy": "#64C800", | |||
"AngelScript": "#C7D7DC", | |||
"AppleScript": "#101F1F", | |||
"Arc": "#aa2afe", | |||
"AspectJ": "#a957b0", | |||
"Assembly": "#6E4C13", | |||
"Asymptote": "#4a0c0c", | |||
"AutoHotkey": "#6594b9", | |||
"AutoIt": "#1C3552", | |||
"Ballerina": "#FF5000", | |||
"Batchfile": "#C1F12E", | |||
"BlitzMax": "#cd6400", | |||
"Boo": "#d4bec1", | |||
"Brainfuck": "#2F2530", | |||
"C": "#555555", | |||
"C#": "#178600", | |||
"C++": "#f34b7d", | |||
"CSS": "#563d7c", | |||
"Ceylon": "#dfa535", | |||
"Chapel": "#8dc63f", | |||
"Cirru": "#ccccff", | |||
"Clarion": "#db901e", | |||
"Clean": "#3F85AF", | |||
"Click": "#E4E6F3", | |||
"Clojure": "#db5855", | |||
"CoffeeScript": "#244776", | |||
"ColdFusion": "#ed2cd6", | |||
"Common Lisp": "#3fb68b", | |||
"Common Workflow Language": "#B5314C", | |||
"Component Pascal": "#B0CE4E", | |||
"Crystal": "#000100", | |||
"Cuda": "#3A4E3A", | |||
"D": "#ba595e", | |||
"DM": "#447265", | |||
"Dart": "#00B4AB", | |||
"DataWeave": "#003a52", | |||
"Dhall": "#dfafff", | |||
"Dockerfile": "#384d54", | |||
"Dogescript": "#cca760", | |||
"Dylan": "#6c616e", | |||
"E": "#ccce35", | |||
"ECL": "#8a1267", | |||
"EQ": "#a78649", | |||
"Eiffel": "#946d57", | |||
"Elixir": "#6e4a7e", | |||
"Elm": "#60B5CC", | |||
"Emacs Lisp": "#c065db", | |||
"EmberScript": "#FFF4F3", | |||
"Erlang": "#B83998", | |||
"F#": "#b845fc", | |||
"F*": "#572e30", | |||
"FLUX": "#88ccff", | |||
"Factor": "#636746", | |||
"Fancy": "#7b9db4", | |||
"Fantom": "#14253c", | |||
"Faust": "#c37240", | |||
"Forth": "#341708", | |||
"Fortran": "#4d41b1", | |||
"FreeMarker": "#0050b2", | |||
"Frege": "#00cafe", | |||
"G-code": "#D08CF2", | |||
"GAML": "#FFC766", | |||
"GDScript": "#355570", | |||
"Game Maker Language": "#71b417", | |||
"Genie": "#fb855d", | |||
"Gherkin": "#5B2063", | |||
"Glyph": "#c1ac7f", | |||
"Gnuplot": "#f0a9f0", | |||
"Go": "#00ADD8", | |||
"Golo": "#88562A", | |||
"Gosu": "#82937f", | |||
"Grammatical Framework": "#79aa7a", | |||
"Groovy": "#e69f56", | |||
"HTML": "#e34c26", | |||
"Hack": "#878787", | |||
"Harbour": "#0e60e3", | |||
"Haskell": "#5e5086", | |||
"Haxe": "#df7900", | |||
"HiveQL": "#dce200", | |||
"HolyC": "#ffefaf", | |||
"Hy": "#7790B2", | |||
"IDL": "#a3522f", | |||
"IGOR Pro": "#0000cc", | |||
"Idris": "#b30000", | |||
"Io": "#a9188d", | |||
"Ioke": "#078193", | |||
"Isabelle": "#FEFE00", | |||
"J": "#9EEDFF", | |||
"JSONiq": "#40d47e", | |||
"Java": "#b07219", | |||
"JavaScript": "#f1e05a", | |||
"Jolie": "#843179", | |||
"Jsonnet": "#0064bd", | |||
"Julia": "#a270ba", | |||
"Jupyter Notebook": "#DA5B0B", | |||
"KRL": "#28430A", | |||
"Kotlin": "#F18E33", | |||
"LFE": "#4C3023", | |||
"LLVM": "#185619", | |||
"LOLCODE": "#cc9900", | |||
"LSL": "#3d9970", | |||
"Lasso": "#999999", | |||
"Lex": "#DBCA00", | |||
"LiveScript": "#499886", | |||
"LookML": "#652B81", | |||
"Lua": "#000080", | |||
"MATLAB": "#e16737", | |||
"MAXScript": "#00a6a6", | |||
"MLIR": "#5EC8DB", | |||
"MQL4": "#62A8D6", | |||
"MQL5": "#4A76B8", | |||
"MTML": "#b7e1f4", | |||
"Makefile": "#427819", | |||
"Mask": "#f97732", | |||
"Max": "#c4a79c", | |||
"Mercury": "#ff2b2b", | |||
"Meson": "#007800", | |||
"Metal": "#8f14e9", | |||
"Mirah": "#c7a938", | |||
"Modula-3": "#223388", | |||
"NCL": "#28431f", | |||
"Nearley": "#990000", | |||
"Nemerle": "#3d3c6e", | |||
"NetLinx": "#0aa0ff", | |||
"NetLinx+ERB": "#747faa", | |||
"NetLogo": "#ff6375", | |||
"NewLisp": "#87AED7", | |||
"Nextflow": "#3ac486", | |||
"Nim": "#37775b", | |||
"Nit": "#009917", | |||
"Nix": "#7e7eff", | |||
"Nu": "#c9df40", | |||
"OCaml": "#3be133", | |||
"ObjectScript": "#424893", | |||
"Objective-C": "#438eff", | |||
"Objective-C++": "#6866fb", | |||
"Objective-J": "#ff0c5a", | |||
"Odin": "#60AFFE", | |||
"Omgrofl": "#cabbff", | |||
"Opal": "#f7ede0", | |||
"OpenQASM": "#AA70FF", | |||
"Oxygene": "#cdd0e3", | |||
"Oz": "#fab738", | |||
"P4": "#7055b5", | |||
"PHP": "#4F5D95", | |||
"PLSQL": "#dad8d8", | |||
"Pan": "#cc0000", | |||
"Papyrus": "#6600cc", | |||
"Parrot": "#f3ca0a", | |||
"Pascal": "#E3F171", | |||
"Pawn": "#dbb284", | |||
"Pep8": "#C76F5B", | |||
"Perl": "#0298c3", | |||
"PigLatin": "#fcd7de", | |||
"Pike": "#005390", | |||
"PogoScript": "#d80074", | |||
"PostScript": "#da291c", | |||
"PowerBuilder": "#8f0f8d", | |||
"PowerShell": "#012456", | |||
"Processing": "#0096D8", | |||
"Prolog": "#74283c", | |||
"Propeller Spin": "#7fa2a7", | |||
"Puppet": "#302B6D", | |||
"PureBasic": "#5a6986", | |||
"PureScript": "#1D222D", | |||
"Python": "#3572A5", | |||
"QML": "#44a51c", | |||
"Quake": "#882233", | |||
"R": "#198CE7", | |||
"RAML": "#77d9fb", | |||
"RUNOFF": "#665a4e", | |||
"Racket": "#3c5caa", | |||
"Ragel": "#9d5200", | |||
"Raku": "#0000fb", | |||
"Rascal": "#fffaa0", | |||
"Reason": "#ff5847", | |||
"Rebol": "#358a5b", | |||
"Red": "#f50000", | |||
"Ren'Py": "#ff7f7f", | |||
"Ring": "#2D54CB", | |||
"Riot": "#A71E49", | |||
"Roff": "#ecdebe", | |||
"Rouge": "#cc0088", | |||
"Ruby": "#701516", | |||
"Rust": "#dea584", | |||
"SAS": "#B34936", | |||
"SQF": "#3F3F3F", | |||
"SRecode Template": "#348a34", | |||
"SaltStack": "#646464", | |||
"Scala": "#c22d40", | |||
"Scheme": "#1e4aec", | |||
"Self": "#0579aa", | |||
"Shell": "#89e051", | |||
"Shen": "#120F14", | |||
"Slash": "#007eff", | |||
"Slice": "#003fa2", | |||
"SmPL": "#c94949", | |||
"Smalltalk": "#596706", | |||
"Solidity": "#AA6746", | |||
"SourcePawn": "#5c7611", | |||
"Squirrel": "#800000", | |||
"Stan": "#b2011d", | |||
"Standard ML": "#dc566d", | |||
"Starlark": "#76d275", | |||
"SuperCollider": "#46390b", | |||
"Swift": "#ffac45", | |||
"SystemVerilog": "#DAE1C2", | |||
"TI Program": "#A0AA87", | |||
"Tcl": "#e4cc98", | |||
"TeX": "#3D6117", | |||
"Terra": "#00004c", | |||
"Turing": "#cf142b", | |||
"TypeScript": "#2b7489", | |||
"UnrealScript": "#a54c4d", | |||
"V": "#5d87bd", | |||
"VBA": "#867db1", | |||
"VBScript": "#15dcdc", | |||
"VCL": "#148AA8", | |||
"VHDL": "#adb2cb", | |||
"Vala": "#fbe5cd", | |||
"Verilog": "#b2b7f8", | |||
"Vim script": "#199f4b", | |||
"Visual Basic .NET": "#945db7", | |||
"Volt": "#1F1F1F", | |||
"Vue": "#2c3e50", | |||
"WebAssembly": "#04133b", | |||
"Wollok": "#a23738", | |||
"X10": "#4B6BEF", | |||
"XC": "#99DA07", | |||
"XQuery": "#5232e7", | |||
"XSLT": "#EB8CEB", | |||
"YARA": "#220000", | |||
"YASnippet": "#32AB90", | |||
"Yacc": "#4B6C4B", | |||
"ZAP": "#0d665e", | |||
"ZIL": "#dc75e5", | |||
"ZenScript": "#00BCD1", | |||
"Zephir": "#118f9e", | |||
"Zig": "#ec915c", | |||
"eC": "#913960", | |||
"mIRC Script": "#926059", | |||
"mcfunction": "#E22837", | |||
"nesC": "#94B0C7", | |||
"ooc": "#b0b77e", | |||
"q": "#0040cd", | |||
"sed": "#64b970", | |||
"wdl": "#42f1f4", | |||
"wisp": "#7582D1", | |||
"xBase": "#403a40", | |||
} | |||
function getLabel(isZh,key){ | |||
if(isZh){ | |||
return zhCN[key] | |||
}else{ | |||
return esUN[key] | |||
} | |||
} | |||
var zhCN={ | |||
"search":"搜索", | |||
"search_repo":"项目", | |||
"search_dataset":"数据集", | |||
"search_issue":"任务", | |||
"search_pr":"合并请求", | |||
"search_user":"用户", | |||
"search_org":"组织", | |||
"search_finded":"找到", | |||
"search_matched":"最佳匹配", | |||
"search_matched_download":"下载次数", | |||
"search_lasted_update":"最后更新于", | |||
"search_letter_asc":"字母顺序排序", | |||
"search_letter_desc":"字母逆序排序", | |||
"search_lasted_create":"最近创建", | |||
"search_early_create":"最早创建", | |||
"search_add_by":"加入于", | |||
"search_lasted":"最近更新", | |||
"search_open":"开启中", | |||
"search_closed":"已关闭", | |||
"search_watched":"关注数", | |||
"search_star":"点赞数", | |||
"search_fork":"Fork数", | |||
"search_input_large_0":"请输入大于0的数值。", | |||
"search_input_maxed":"不能超出总页数。", | |||
"search_input_total":"共", | |||
"search_srtip":"条", | |||
"search_home_page":"首页", | |||
"search_last_page":"末页", | |||
"search_go_to":"前往", | |||
"search_go_page":"页", | |||
"find_title":"“<strong class=\"highlight\" id=\"keyword_desc\">{keyword}</strong>”相关{tablename}约为{total}个", | |||
"search_empty":"<strong>请输入任意关键字开始搜索。</strong>" | |||
} | |||
var esUN={ | |||
"search":"Search", | |||
"search_repo":"Repository", | |||
"search_dataset":"DataSet", | |||
"search_issue":"Issue", | |||
"search_pr":"Pull Request", | |||
"search_user":"User", | |||
"search_org":"Organization", | |||
"search_finded":"Find", | |||
"search_matched":"Best Match", | |||
"search_matched_download":"Most downloads", | |||
"search_lasted_update":"Updated ", | |||
"search_letter_asc":"Alphabetically", | |||
"search_letter_desc":"Reverse alphabetically", | |||
"search_lasted_create":"Recently created", | |||
"search_early_create":"First created", | |||
"search_add_by":"Joined on", | |||
"search_lasted":"Recently updated", | |||
"search_open":"Open", | |||
"search_closed":"Closed", | |||
"search_watched":"Watches", | |||
"search_star":"Stars", | |||
"search_fork":"Forks", | |||
"search_input_large_0":"Please enter a value greater than 0.", | |||
"search_input_maxed":"Cannot exceed total pages.", | |||
"search_input_total":"Total", | |||
"search_srtip":"", | |||
"search_home_page":"First", | |||
"search_last_page":"Last", | |||
"search_go_to":"Go", | |||
"search_go_page":"Page", | |||
"find_title":" {total} \"<strong class=\"highlight\" id=\"keyword_desc\">{keyword}</strong>\" related {tablename}", | |||
"search_empty":"<strong>Please enter any keyword to start the search.</strong>" | |||
} | |||
initDiv(false); | |||
document.onreadystatechange = function() { | |||
if (document.readyState === "complete") { | |||
var tmpSearchLabel = sessionStorage.getItem("searchLabel"); | |||
console.log("tmpSearchLabel=" + tmpSearchLabel); | |||
if(tmpSearchLabel){ | |||
console.log("search label...."); | |||
sessionStorage.removeItem("searchLabel"); | |||
doSearchLabel(sessionStorage.getItem("tableName"),sessionStorage.getItem("keyword"),sessionStorage.getItem("sortBy"),sessionStorage.getItem("ascending")); | |||
}else{ | |||
console.log("normal search...."); | |||
search(); | |||
} | |||
} | |||
} | |||
@@ -620,10 +620,10 @@ function showfilelist(){ | |||
for (var i=0;i<labeltastresult.length;i++){ | |||
var fname = labeltastresult[i].pic_image_field.substring(labeltastresult[i].pic_image_field.lastIndexOf('/') + 1); | |||
console.log(labeltastresult[i]) | |||
//console.log(labeltastresult[i]) | |||
if(labeltastresult[i].pic_image_field.length > 70){ | |||
var tmpIndex = labeltastresult[i].pic_image_field.indexOf("/",70); | |||
console.log(tmpIndex) | |||
//console.log(tmpIndex) | |||
if(tmpIndex != -1){ | |||
fname = labeltastresult[i].pic_image_field.substring(tmpIndex + 1); | |||
fname = fname.substring(fname.indexOf('/')+1); | |||
@@ -679,7 +679,7 @@ function breadFiles(){ | |||
fname_full_path = tableData[fileindex].pic_image_field.substring(tmp_index + 1); | |||
} | |||
var fname_path = fname_full_path.split('/') | |||
console.log(fname_path) | |||
//console.log(fname_path) | |||
// var filename_text = tableData[fileindex].pic_image_field.substring(tableData[fileindex].pic_image_field.lastIndexOf('/')+1) | |||
var html_breadFile = '' | |||
// var source_name = filename_title+'.zip' | |||
@@ -71,6 +71,8 @@ func NewServices() { | |||
log.Info("decompression.NewContext() succeed.") | |||
labelmsg.Init() | |||
log.Info("labelmsg.Init() succeed.") | |||
InitESClient() | |||
log.Info("ES Client succeed.") | |||
} | |||
// In case of problems connecting to DB, retry connection. Eg, PGSQL in Docker Container on Synology | |||
@@ -323,6 +323,9 @@ func RegisterRoutes(m *macaron.Macaron) { | |||
m.Get("/action/notification", routers.ActionNotification) | |||
m.Get("/recommend/org", routers.RecommendOrgFromPromote) | |||
m.Get("/recommend/repo", routers.RecommendRepoFromPromote) | |||
m.Post("/all/search/", routers.Search) | |||
m.Get("/all/search/", routers.EmptySearch) | |||
m.Get("/all/dosearch/", routers.SearchApi) | |||
m.Get("/home/term", routers.HomeTerm) | |||
m.Group("/explore", func() { | |||
m.Get("", func(ctx *context.Context) { | |||
@@ -0,0 +1,1190 @@ | |||
package routers | |||
import ( | |||
"encoding/json" | |||
"fmt" | |||
"sort" | |||
"strconv" | |||
"strings" | |||
"code.gitea.io/gitea/models" | |||
"code.gitea.io/gitea/modules/context" | |||
"code.gitea.io/gitea/modules/log" | |||
"code.gitea.io/gitea/modules/setting" | |||
"code.gitea.io/gitea/modules/timeutil" | |||
"github.com/olivere/elastic/v7" | |||
) | |||
type SearchRes struct { | |||
Total int64 | |||
Result []map[string]interface{} | |||
PrivateTotal int64 | |||
} | |||
var client *elastic.Client | |||
func InitESClient() { | |||
ESSearchUrl := setting.ESSearchURL | |||
var err error | |||
client, err = elastic.NewClient(elastic.SetSniff(false), elastic.SetURL(ESSearchUrl)) | |||
if err != nil { | |||
log.Info("es init error.") | |||
//panic(err) | |||
} | |||
} | |||
func EmptySearch(ctx *context.Context) { | |||
log.Info("search template.") | |||
ctx.Data["Keyword"] = "" | |||
ctx.HTML(200, "explore/search_new") | |||
} | |||
func Search(ctx *context.Context) { | |||
log.Info("search template.") | |||
keyword := strings.Trim(ctx.Query("q"), " ") | |||
ctx.Data["Keyword"] = keyword | |||
ctx.Data["SortType"] = "newest" | |||
ctx.HTML(200, "explore/search_new") | |||
} | |||
func SearchApi(ctx *context.Context) { | |||
TableName := ctx.Query("TableName") | |||
Key := ctx.Query("Key") | |||
Page := ctx.QueryInt("Page") | |||
PageSize := ctx.QueryInt("PageSize") | |||
OnlyReturnNum := ctx.QueryBool("OnlyReturnNum") | |||
OnlySearchLabel := ctx.QueryBool("OnlySearchLabel") | |||
if Page <= 0 { | |||
Page = 1 | |||
} | |||
if PageSize <= 0 || PageSize > 200 { | |||
PageSize = setting.UI.IssuePagingNum | |||
} | |||
if Key != "" && !OnlyReturnNum { | |||
go models.SaveSearchKeywordToDb(Key) | |||
} | |||
if TableName == "repository" { | |||
if OnlySearchLabel { | |||
searchRepoByLabel(ctx, Key, Page, PageSize) | |||
} else { | |||
searchRepo(ctx, "repository-es-index", Key, Page, PageSize, OnlyReturnNum) | |||
} | |||
return | |||
} else if TableName == "issue" { | |||
searchIssueOrPr(ctx, "issue-es-index", Key, Page, PageSize, OnlyReturnNum, "f") | |||
return | |||
} else if TableName == "user" { | |||
searchUserOrOrg(ctx, "user-es-index", Key, Page, PageSize, true, OnlyReturnNum) | |||
return | |||
} else if TableName == "org" { | |||
searchUserOrOrg(ctx, "user-es-index", Key, Page, PageSize, false, OnlyReturnNum) | |||
return | |||
} else if TableName == "dataset" { | |||
searchDataSet(ctx, "dataset-es-index", Key, Page, PageSize, OnlyReturnNum) | |||
return | |||
} else if TableName == "pr" { | |||
searchIssueOrPr(ctx, "issue-es-index", Key, Page, PageSize, OnlyReturnNum, "t") | |||
//searchPR(ctx, "issue-es-index", Key, Page, PageSize, OnlyReturnNum) | |||
return | |||
} | |||
} | |||
func searchRepoByLabel(ctx *context.Context, Key string, Page int, PageSize int) { | |||
/* | |||
项目, ES名称: repository-es-index | |||
搜索: | |||
name character varying(255) , 项目名称 | |||
description text, 项目描述 | |||
topics json, 标签 | |||
排序: | |||
updated_unix | |||
num_watches, | |||
num_stars, | |||
num_forks, | |||
*/ | |||
SortBy := ctx.Query("SortBy") | |||
PrivateTotal := ctx.QueryInt("PrivateTotal") | |||
WebTotal := ctx.QueryInt("WebTotal") | |||
ascending := ctx.QueryBool("Ascending") | |||
language := ctx.Query("language") | |||
if language == "" { | |||
language = "zh-CN" | |||
} | |||
from := (Page - 1) * PageSize | |||
resultObj := &SearchRes{} | |||
log.Info("WebTotal=" + fmt.Sprint(WebTotal)) | |||
log.Info("PrivateTotal=" + fmt.Sprint(PrivateTotal)) | |||
resultObj.Result = make([]map[string]interface{}, 0) | |||
if from == 0 { | |||
WebTotal = 0 | |||
} | |||
if ctx.User != nil && (from < PrivateTotal || from == 0) { | |||
orderBy := models.SearchOrderByRecentUpdated | |||
switch SortBy { | |||
case "updated_unix.keyword": | |||
orderBy = models.SearchOrderByRecentUpdated | |||
case "num_stars": | |||
orderBy = models.SearchOrderByStarsReverse | |||
case "num_forks": | |||
orderBy = models.SearchOrderByForksReverse | |||
case "num_watches": | |||
orderBy = models.SearchOrderByWatches | |||
} | |||
log.Info("actor is null?:" + fmt.Sprint(ctx.User == nil)) | |||
repos, count, err := models.SearchRepository(&models.SearchRepoOptions{ | |||
ListOptions: models.ListOptions{ | |||
Page: Page, | |||
PageSize: PageSize, | |||
}, | |||
Actor: ctx.User, | |||
OrderBy: orderBy, | |||
Private: true, | |||
OnlyPrivate: true, | |||
TopicOnly: true, | |||
TopicName: Key, | |||
IncludeDescription: setting.UI.SearchRepoDescription, | |||
}) | |||
if err != nil { | |||
ctx.JSON(200, "") | |||
return | |||
} | |||
resultObj.PrivateTotal = count | |||
if repos.Len() > 0 { | |||
log.Info("Query private repo number is:" + fmt.Sprint(repos.Len())) | |||
makePrivateRepo(repos, resultObj, Key, language) | |||
} else { | |||
log.Info("not found private repo,keyword=" + Key) | |||
} | |||
if repos.Len() >= PageSize { | |||
if WebTotal > 0 { | |||
resultObj.Total = int64(WebTotal) | |||
ctx.JSON(200, resultObj) | |||
return | |||
} | |||
} | |||
} else { | |||
if ctx.User == nil { | |||
resultObj.PrivateTotal = 0 | |||
} else { | |||
resultObj.PrivateTotal = int64(PrivateTotal) | |||
} | |||
} | |||
from = from - PrivateTotal | |||
if from < 0 { | |||
from = 0 | |||
} | |||
Size := PageSize - len(resultObj.Result) | |||
log.Info("query searchRepoByLabel start") | |||
if Key != "" { | |||
boolQ := elastic.NewBoolQuery() | |||
topicsQuery := elastic.NewMatchQuery("topics", Key) | |||
boolQ.Should(topicsQuery) | |||
res, err := client.Search("repository-es-index").Query(boolQ).SortBy(getSort(SortBy, ascending)).From(from).Size(Size).Highlight(queryHighlight("topics")).Do(ctx.Req.Context()) | |||
if err == nil { | |||
searchJson, _ := json.Marshal(res) | |||
log.Info("searchJson=" + string(searchJson)) | |||
esresult := makeRepoResult(res, "", false, language) | |||
resultObj.Total = resultObj.PrivateTotal + esresult.Total | |||
resultObj.Result = append(resultObj.Result, esresult.Result...) | |||
ctx.JSON(200, resultObj) | |||
} else { | |||
log.Info("query es error," + err.Error()) | |||
ctx.JSON(200, "") | |||
} | |||
} else { | |||
ctx.JSON(200, "") | |||
} | |||
} | |||
func getSort(SortBy string, ascending bool) elastic.Sorter { | |||
var sort elastic.Sorter | |||
sort = elastic.NewScoreSort() | |||
if SortBy != "" { | |||
if SortBy == "default" { | |||
return sort | |||
} | |||
return elastic.NewFieldSort(SortBy).Order(ascending) | |||
} | |||
return sort | |||
} | |||
func searchRepo(ctx *context.Context, TableName string, Key string, Page int, PageSize int, OnlyReturnNum bool) { | |||
/* | |||
项目, ES名称: repository-es-index | |||
搜索: | |||
name character varying(255) , 项目名称 | |||
description text, 项目描述 | |||
topics json, 标签 | |||
排序: | |||
updated_unix | |||
num_watches, | |||
num_stars, | |||
num_forks, | |||
*/ | |||
SortBy := ctx.Query("SortBy") | |||
PrivateTotal := ctx.QueryInt("PrivateTotal") | |||
WebTotal := ctx.QueryInt("WebTotal") | |||
ascending := ctx.QueryBool("Ascending") | |||
from := (Page - 1) * PageSize | |||
resultObj := &SearchRes{} | |||
log.Info("WebTotal=" + fmt.Sprint(WebTotal)) | |||
log.Info("PrivateTotal=" + fmt.Sprint(PrivateTotal)) | |||
resultObj.Result = make([]map[string]interface{}, 0) | |||
if from == 0 { | |||
WebTotal = 0 | |||
} | |||
language := ctx.Query("language") | |||
if language == "" { | |||
language = "zh-CN" | |||
} | |||
if ctx.User != nil && (from < PrivateTotal || from == 0) { | |||
orderBy := models.SearchOrderByRecentUpdated | |||
switch SortBy { | |||
case "updated_unix.keyword": | |||
orderBy = models.SearchOrderByRecentUpdated | |||
case "num_stars": | |||
orderBy = models.SearchOrderByStarsReverse | |||
case "num_forks": | |||
orderBy = models.SearchOrderByForksReverse | |||
case "num_watches": | |||
orderBy = models.SearchOrderByWatches | |||
} | |||
log.Info("actor is null?:" + fmt.Sprint(ctx.User == nil)) | |||
repos, count, err := models.SearchRepository(&models.SearchRepoOptions{ | |||
ListOptions: models.ListOptions{ | |||
Page: Page, | |||
PageSize: PageSize, | |||
}, | |||
Actor: ctx.User, | |||
OrderBy: orderBy, | |||
Private: true, | |||
OnlyPrivate: true, | |||
Keyword: Key, | |||
IncludeDescription: setting.UI.SearchRepoDescription, | |||
OnlySearchPrivate: true, | |||
}) | |||
if err != nil { | |||
ctx.JSON(200, "") | |||
return | |||
} | |||
resultObj.PrivateTotal = count | |||
if repos.Len() > 0 { | |||
log.Info("Query private repo number is:" + fmt.Sprint(repos.Len())) | |||
makePrivateRepo(repos, resultObj, Key, language) | |||
} else { | |||
log.Info("not found private repo,keyword=" + Key) | |||
} | |||
if repos.Len() >= PageSize { | |||
if WebTotal > 0 { | |||
resultObj.Total = int64(WebTotal) | |||
ctx.JSON(200, resultObj) | |||
return | |||
} | |||
} | |||
} else { | |||
if ctx.User == nil { | |||
resultObj.PrivateTotal = 0 | |||
} else { | |||
resultObj.PrivateTotal = int64(PrivateTotal) | |||
} | |||
} | |||
from = from - PrivateTotal | |||
if from < 0 { | |||
from = 0 | |||
} | |||
Size := PageSize - len(resultObj.Result) | |||
log.Info("query searchRepo start") | |||
if Key != "" { | |||
boolQ := elastic.NewBoolQuery() | |||
nameQuery := elastic.NewMatchQuery("alias", Key).Boost(1024).QueryName("f_first") | |||
descriptionQuery := elastic.NewMatchQuery("description", Key).Boost(1.5).QueryName("f_second") | |||
topicsQuery := elastic.NewMatchQuery("topics", Key).Boost(1).QueryName("f_third") | |||
boolQ.Should(nameQuery, descriptionQuery, topicsQuery) | |||
res, err := client.Search(TableName).Query(boolQ).SortBy(getSort(SortBy, ascending)).From(from).Size(Size).Highlight(queryHighlight("alias", "description", "topics")).Do(ctx.Req.Context()) | |||
if err == nil { | |||
searchJson, _ := json.Marshal(res) | |||
log.Info("searchJson=" + string(searchJson)) | |||
esresult := makeRepoResult(res, Key, OnlyReturnNum, language) | |||
resultObj.Total = resultObj.PrivateTotal + esresult.Total | |||
isNeedSort := false | |||
if len(resultObj.Result) > 0 { | |||
isNeedSort = true | |||
} | |||
resultObj.Result = append(resultObj.Result, esresult.Result...) | |||
if isNeedSort { | |||
sortRepo(resultObj.Result, SortBy, ascending) | |||
} | |||
ctx.JSON(200, resultObj) | |||
} else { | |||
log.Info("query es error," + err.Error()) | |||
ctx.JSON(200, "") | |||
} | |||
} else { | |||
log.Info("query all content.") | |||
//搜索的属性要指定{"timestamp":{"unmapped_type":"date"}} | |||
res, err := client.Search(TableName).SortBy(getSort(SortBy, ascending)).From(from).Size(Size).Do(ctx.Req.Context()) | |||
if err == nil { | |||
searchJson, _ := json.Marshal(res) | |||
log.Info("searchJson=" + string(searchJson)) | |||
esresult := makeRepoResult(res, "", OnlyReturnNum, language) | |||
resultObj.Total = resultObj.PrivateTotal + esresult.Total | |||
resultObj.Result = append(resultObj.Result, esresult.Result...) | |||
ctx.JSON(200, resultObj) | |||
} else { | |||
log.Info("query es error," + err.Error()) | |||
ctx.JSON(200, "") | |||
} | |||
} | |||
} | |||
func sortRepo(Result []map[string]interface{}, SortBy string, ascending bool) { | |||
orderBy := "" | |||
switch SortBy { | |||
case "updated_unix.keyword": | |||
orderBy = "updated_unix" | |||
case "num_stars": | |||
orderBy = "num_stars" | |||
case "num_forks": | |||
orderBy = "num_forks" | |||
case "num_watches": | |||
orderBy = "num_watches" | |||
} | |||
sort.Slice(Result, func(i, j int) bool { | |||
return getInt(Result[i][orderBy], orderBy) > getInt(Result[j][orderBy], orderBy) | |||
}) | |||
} | |||
func getInt(tmp interface{}, orderBy string) int64 { | |||
timeInt, err := strconv.ParseInt(fmt.Sprint(tmp), 10, 64) | |||
if err == nil { | |||
return timeInt | |||
} else { | |||
log.Info("convert " + orderBy + " error type=" + fmt.Sprint(tmp)) | |||
} | |||
return -1 | |||
} | |||
func makePrivateRepo(repos models.RepositoryList, res *SearchRes, keyword string, language string) { | |||
for _, repo := range repos { | |||
record := make(map[string]interface{}) | |||
record["id"] = repo.ID | |||
record["name"] = makeHighLight(keyword, repo.Name) | |||
record["real_name"] = repo.Name | |||
record["owner_name"] = repo.OwnerName | |||
record["description"] = truncLongText(makeHighLight(keyword, repo.Description), true) | |||
hightTopics := make([]string, 0) | |||
if len(repo.Topics) > 0 { | |||
for _, t := range repo.Topics { | |||
hightTopics = append(hightTopics, makeHighLight(keyword, t)) | |||
} | |||
} | |||
record["hightTopics"] = hightTopics | |||
record["num_watches"] = repo.NumWatches | |||
record["num_stars"] = repo.NumStars | |||
record["num_forks"] = repo.NumForks | |||
record["alias"] = truncLongText(makeHighLight(keyword, repo.Alias), true) | |||
record["lower_alias"] = repo.LowerAlias | |||
record["topics"] = repo.Topics | |||
record["avatar"] = repo.RelAvatarLink() | |||
if len(repo.RelAvatarLink()) == 0 { | |||
record["avatar"] = setting.RepositoryAvatarFallbackImage | |||
} | |||
record["updated_unix"] = repo.UpdatedUnix | |||
record["updated_html"] = timeutil.TimeSinceUnix(repo.UpdatedUnix, language) | |||
lang, err := repo.GetTopLanguageStats(1) | |||
if err == nil && len(lang) > 0 { | |||
record["lang"] = lang[0].Language | |||
} else { | |||
record["lang"] = "" | |||
} | |||
record["is_private"] = true | |||
res.Result = append(res.Result, record) | |||
} | |||
} | |||
func makeHighLight(keyword string, dest string) string { | |||
dest = replaceIngoreUpperOrLower(dest, strings.ToLower(dest), strings.ToLower(keyword)) | |||
return dest | |||
} | |||
func replaceIngoreUpperOrLower(dest string, destLower string, keywordLower string) string { | |||
re := "" | |||
last := 0 | |||
lenDestLower := len(destLower) | |||
lenkeywordLower := len(keywordLower) | |||
for i := 0; i < lenDestLower; i++ { | |||
if destLower[i] == keywordLower[0] { | |||
isFind := true | |||
for j := 1; j < lenkeywordLower; j++ { | |||
if (i+j) < lenDestLower && keywordLower[j] != destLower[i+j] { | |||
isFind = false | |||
break | |||
} | |||
} | |||
if isFind && (i+lenkeywordLower) <= lenDestLower { | |||
re += dest[last:i] + "\u003cfont color='red'\u003e" + dest[i:(i+lenkeywordLower)] + "\u003c/font\u003e" | |||
i = i + lenkeywordLower | |||
last = i | |||
} | |||
} | |||
} | |||
if last < lenDestLower { | |||
re += dest[last:lenDestLower] | |||
} | |||
return re | |||
} | |||
func makeRepoResult(sRes *elastic.SearchResult, Key string, OnlyReturnNum bool, language string) *SearchRes { | |||
total := sRes.Hits.TotalHits.Value | |||
result := make([]map[string]interface{}, 0) | |||
if !OnlyReturnNum { | |||
for i, hit := range sRes.Hits.Hits { | |||
log.Info("this is repo query " + fmt.Sprint(i) + " result.") | |||
recordSource := make(map[string]interface{}) | |||
source, err := hit.Source.MarshalJSON() | |||
if err == nil { | |||
err = json.Unmarshal(source, &recordSource) | |||
if err == nil { | |||
record := make(map[string]interface{}) | |||
record["id"] = hit.Id | |||
record["alias"] = getLabelValue("alias", recordSource, hit.Highlight) | |||
record["real_name"] = recordSource["name"] | |||
record["owner_name"] = recordSource["owner_name"] | |||
if recordSource["description"] != nil { | |||
desc := getLabelValue("description", recordSource, hit.Highlight) | |||
record["description"] = dealLongText(desc, Key, hit.MatchedQueries) | |||
} else { | |||
record["description"] = "" | |||
} | |||
record["hightTopics"] = jsonStrToArray(getLabelValue("topics", recordSource, hit.Highlight)) | |||
record["num_watches"] = recordSource["num_watches"] | |||
record["num_stars"] = recordSource["num_stars"] | |||
record["num_forks"] = recordSource["num_forks"] | |||
record["lower_alias"] = recordSource["lower_alias"] | |||
if recordSource["topics"] != nil { | |||
topicsStr := recordSource["topics"].(string) | |||
log.Info("topicsStr=" + topicsStr) | |||
if topicsStr != "null" { | |||
record["topics"] = jsonStrToArray(topicsStr) | |||
} | |||
} | |||
if recordSource["avatar"] != nil { | |||
avatarstr := recordSource["avatar"].(string) | |||
if len(avatarstr) == 0 { | |||
record["avatar"] = setting.RepositoryAvatarFallbackImage | |||
} else { | |||
record["avatar"] = setting.AppSubURL + "/repo-avatars/" + avatarstr | |||
} | |||
} | |||
record["updated_unix"] = recordSource["updated_unix"] | |||
setUpdateHtml(record, recordSource["updated_unix"].(string), language) | |||
record["lang"] = recordSource["lang"] | |||
record["is_private"] = false | |||
result = append(result, record) | |||
} else { | |||
log.Info("deal repo source error," + err.Error()) | |||
} | |||
} else { | |||
log.Info("deal repo source error," + err.Error()) | |||
} | |||
} | |||
} | |||
returnObj := &SearchRes{ | |||
Total: total, | |||
Result: result, | |||
} | |||
return returnObj | |||
} | |||
func setUpdateHtml(record map[string]interface{}, updated_unix string, language string) { | |||
timeInt, err := strconv.ParseInt(updated_unix, 10, 64) | |||
if err == nil { | |||
record["updated_html"] = timeutil.TimeSinceUnix(timeutil.TimeStamp(timeInt), language) | |||
} | |||
} | |||
func jsonStrToArray(str string) []string { | |||
b := []byte(str) | |||
strs := make([]string, 0) | |||
err := json.Unmarshal(b, &strs) | |||
if err != nil { | |||
log.Info("convert str arrar error, str=" + str) | |||
} | |||
return strs | |||
} | |||
func dealLongText(text string, Key string, MatchedQueries []string) string { | |||
var isNeedToDealText bool | |||
isNeedToDealText = false | |||
if len(MatchedQueries) > 0 && Key != "" { | |||
if MatchedQueries[0] == "f_second" || MatchedQueries[0] == "f_third" { | |||
isNeedToDealText = true | |||
} | |||
} | |||
return truncLongText(text, isNeedToDealText) | |||
} | |||
func truncLongText(text string, isNeedToDealText bool) string { | |||
startStr := "color=" | |||
textRune := []rune(text) | |||
stringlen := len(textRune) | |||
if isNeedToDealText && stringlen > 200 { | |||
index := findFont(textRune, []rune(startStr)) | |||
if index > 0 { | |||
start := index - 50 | |||
if start < 0 { | |||
start = 0 | |||
} | |||
end := index + 150 | |||
if end >= stringlen { | |||
end = stringlen | |||
} | |||
return trimFontHtml(textRune[start:end]) + "..." | |||
} else { | |||
return trimFontHtml(textRune[0:200]) + "..." | |||
} | |||
} else { | |||
if stringlen > 200 { | |||
return trimFontHtml(textRune[0:200]) + "..." | |||
} else { | |||
return text | |||
} | |||
} | |||
} | |||
func trimFontHtml(text []rune) string { | |||
startRune := rune('<') | |||
endRune := rune('>') | |||
count := 0 | |||
for i := 0; i < len(text); i++ { | |||
if text[i] == startRune { //start < | |||
re := false | |||
j := i + 1 | |||
for ; j < len(text); j++ { | |||
if text[j] == endRune { | |||
re = true | |||
break | |||
} | |||
} | |||
if re { //found > | |||
i = j | |||
count++ | |||
} else { | |||
if count%2 == 1 { | |||
return string(text[0:i]) + "</font>" | |||
} else { | |||
return string(text[0:i]) | |||
} | |||
} | |||
} | |||
} | |||
return string(text) | |||
} | |||
func trimHrefHtml(result string) string { | |||
result = strings.Replace(result, "</a>", "", -1) | |||
result = strings.Replace(result, "\n", "", -1) | |||
var index int | |||
for { | |||
index = findSubstr(result, 0, "<a") | |||
if index != -1 { | |||
sIndex := findSubstr(result, index+2, ">") | |||
if sIndex != -1 { | |||
result = result[0:index] + result[sIndex+1:] | |||
} else { | |||
result = result[0:index] + result[index+2:] | |||
} | |||
} else { | |||
break | |||
} | |||
} | |||
return result | |||
} | |||
func findFont(text []rune, childText []rune) int { | |||
for i := 0; i < len(text); i++ { | |||
if text[i] == childText[0] { | |||
re := true | |||
for j, k := range childText { | |||
if k != text[i+j] { | |||
re = false | |||
break | |||
} | |||
} | |||
if re { | |||
return i | |||
} | |||
} | |||
} | |||
return -1 | |||
} | |||
func findSubstr(text string, startindex int, childText string) int { | |||
for i := startindex; i < len(text); i++ { | |||
if text[i] == childText[0] { | |||
re := true | |||
for k := range childText { | |||
if childText[k] != text[i+k] { | |||
re = false | |||
break | |||
} | |||
} | |||
if re { | |||
return i | |||
} | |||
} | |||
} | |||
return -1 | |||
} | |||
func searchUserOrOrg(ctx *context.Context, TableName string, Key string, Page int, PageSize int, IsQueryUser bool, OnlyReturnNum bool) { | |||
/* | |||
用户或者组织 ES名称: user-es-index | |||
搜索: | |||
name , 名称 | |||
full_name 全名 | |||
description 描述或者简介 | |||
排序: | |||
created_unix | |||
名称字母序 | |||
*/ | |||
SortBy := ctx.Query("SortBy") | |||
ascending := ctx.QueryBool("Ascending") | |||
boolQ := elastic.NewBoolQuery() | |||
typeValue := 1 | |||
if IsQueryUser { | |||
typeValue = 0 | |||
} | |||
UserOrOrgQuery := elastic.NewTermQuery("type", typeValue) | |||
if Key != "" { | |||
boolKeyQ := elastic.NewBoolQuery() | |||
log.Info("user or org Key=" + Key) | |||
nameQuery := elastic.NewMatchQuery("name", Key).Boost(2).QueryName("f_first") | |||
full_nameQuery := elastic.NewMatchQuery("full_name", Key).Boost(1.5).QueryName("f_second") | |||
descriptionQuery := elastic.NewMatchQuery("description", Key).Boost(1).QueryName("f_third") | |||
boolKeyQ.Should(nameQuery, full_nameQuery, descriptionQuery) | |||
boolQ.Must(UserOrOrgQuery, boolKeyQ) | |||
} else { | |||
boolQ.Must(UserOrOrgQuery) | |||
} | |||
res, err := client.Search(TableName).Query(boolQ).SortBy(getSort(SortBy, ascending)).From((Page - 1) * PageSize).Size(PageSize).Highlight(queryHighlight("name", "full_name", "description")).Do(ctx.Req.Context()) | |||
if err == nil { | |||
searchJson, _ := json.Marshal(res) | |||
log.Info("searchJson=" + string(searchJson)) | |||
result := makeUserOrOrgResult(res, Key, ctx, OnlyReturnNum) | |||
ctx.JSON(200, result) | |||
} else { | |||
log.Info("query es error," + err.Error()) | |||
ctx.JSON(200, "") | |||
} | |||
} | |||
func getLabelValue(key string, recordSource map[string]interface{}, searchHighliht elastic.SearchHitHighlight) string { | |||
if value, ok := searchHighliht[key]; !ok { | |||
if recordSource[key] != nil { | |||
return recordSource[key].(string) | |||
} else { | |||
return "" | |||
} | |||
} else { | |||
return value[0] | |||
} | |||
} | |||
func makeUserOrOrgResult(sRes *elastic.SearchResult, Key string, ctx *context.Context, OnlyReturnNum bool) *SearchRes { | |||
total := sRes.Hits.TotalHits.Value | |||
result := make([]map[string]interface{}, 0) | |||
if !OnlyReturnNum { | |||
for i, hit := range sRes.Hits.Hits { | |||
log.Info("this is user query " + fmt.Sprint(i) + " result.") | |||
recordSource := make(map[string]interface{}) | |||
source, err := hit.Source.MarshalJSON() | |||
if err == nil { | |||
err = json.Unmarshal(source, &recordSource) | |||
if err == nil { | |||
record := make(map[string]interface{}) | |||
record["id"] = hit.Id | |||
record["name"] = getLabelValue("name", recordSource, hit.Highlight) | |||
record["real_name"] = recordSource["name"] | |||
record["full_name"] = getLabelValue("full_name", recordSource, hit.Highlight) | |||
if recordSource["description"] != nil { | |||
desc := getLabelValue("description", recordSource, hit.Highlight) | |||
record["description"] = dealLongText(desc, Key, hit.MatchedQueries) | |||
} else { | |||
record["description"] = "" | |||
} | |||
if ctx.User != nil { | |||
record["email"] = recordSource["email"] | |||
} else { | |||
record["email"] = "" | |||
} | |||
record["location"] = recordSource["location"] | |||
record["website"] = recordSource["website"] | |||
record["num_repos"] = recordSource["num_repos"] | |||
record["num_teams"] = recordSource["num_teams"] | |||
record["num_members"] = recordSource["num_members"] | |||
record["avatar"] = strings.TrimRight(setting.AppSubURL, "/") + "/user/avatar/" + recordSource["name"].(string) + "/" + strconv.Itoa(-1) | |||
record["updated_unix"] = recordSource["updated_unix"] | |||
record["created_unix"] = recordSource["created_unix"] | |||
record["add_time"] = getAddTime(recordSource["created_unix"].(string)) | |||
result = append(result, record) | |||
} else { | |||
log.Info("deal user source error," + err.Error()) | |||
} | |||
} else { | |||
log.Info("deal user source error," + err.Error()) | |||
} | |||
} | |||
} | |||
returnObj := &SearchRes{ | |||
Total: total, | |||
Result: result, | |||
} | |||
return returnObj | |||
} | |||
func getAddTime(time string) string { | |||
timeInt, err := strconv.ParseInt(time, 10, 64) | |||
if err == nil { | |||
t := timeutil.TimeStamp(timeInt) | |||
return t.FormatShort() | |||
} | |||
return "" | |||
} | |||
func searchDataSet(ctx *context.Context, TableName string, Key string, Page int, PageSize int, OnlyReturnNum bool) { | |||
/* | |||
数据集,ES名称:dataset-es-index | |||
搜索: | |||
title , 名称 | |||
description 描述 | |||
category 标签 | |||
file_name 数据集文件名称 | |||
排序: | |||
download_times | |||
*/ | |||
log.Info("query searchdataset start") | |||
SortBy := ctx.Query("SortBy") | |||
ascending := ctx.QueryBool("Ascending") | |||
PrivateTotal := ctx.QueryInt("PrivateTotal") | |||
WebTotal := ctx.QueryInt("WebTotal") | |||
language := ctx.Query("language") | |||
if language == "" { | |||
language = "zh-CN" | |||
} | |||
from := (Page - 1) * PageSize | |||
if from == 0 { | |||
WebTotal = 0 | |||
} | |||
resultObj := &SearchRes{} | |||
log.Info("WebTotal=" + fmt.Sprint(WebTotal)) | |||
log.Info("PrivateTotal=" + fmt.Sprint(PrivateTotal)) | |||
resultObj.Result = make([]map[string]interface{}, 0) | |||
if ctx.User != nil && (from < PrivateTotal || from == 0) { | |||
log.Info("actor is null?:" + fmt.Sprint(ctx.User == nil)) | |||
datasets, count, err := models.SearchDatasetBySQL(Page, PageSize, Key, ctx.User.ID) | |||
if err != nil { | |||
ctx.JSON(200, "") | |||
return | |||
} | |||
resultObj.PrivateTotal = count | |||
datasetSize := len(datasets) | |||
if datasetSize > 0 { | |||
log.Info("Query private dataset number is:" + fmt.Sprint(datasetSize) + " count=" + fmt.Sprint(count)) | |||
makePrivateDataSet(datasets, resultObj, Key, language) | |||
} else { | |||
log.Info("not found private dataset, keyword=" + Key) | |||
} | |||
if datasetSize >= PageSize { | |||
if WebTotal > 0 { //next page, not first query. | |||
resultObj.Total = int64(WebTotal) | |||
ctx.JSON(200, resultObj) | |||
return | |||
} | |||
} | |||
} else { | |||
resultObj.PrivateTotal = int64(PrivateTotal) | |||
} | |||
from = from - PrivateTotal | |||
if from < 0 { | |||
from = 0 | |||
} | |||
Size := PageSize - len(resultObj.Result) | |||
boolQ := elastic.NewBoolQuery() | |||
if Key != "" { | |||
nameQuery := elastic.NewMatchQuery("title", Key).Boost(2).QueryName("f_first") | |||
descQuery := elastic.NewMatchQuery("description", Key).Boost(1.5).QueryName("f_second") | |||
fileNameQuery := elastic.NewMatchQuery("file_name", Key).Boost(1).QueryName("f_third") | |||
categoryQuery := elastic.NewMatchQuery("category", Key).Boost(1).QueryName("f_fourth") | |||
boolQ.Should(nameQuery, descQuery, categoryQuery, fileNameQuery) | |||
res, err := client.Search(TableName).Query(boolQ).SortBy(getSort(SortBy, ascending)).From(from).Size(Size).Highlight(queryHighlight("title", "description", "file_name", "category")).Do(ctx.Req.Context()) | |||
if err == nil { | |||
searchJson, _ := json.Marshal(res) | |||
log.Info("searchJson=" + string(searchJson)) | |||
esresult := makeDatasetResult(res, Key, OnlyReturnNum, language) | |||
resultObj.Total = resultObj.PrivateTotal + esresult.Total | |||
log.Info("query dataset es count=" + fmt.Sprint(esresult.Total) + " total=" + fmt.Sprint(resultObj.Total)) | |||
resultObj.Result = append(resultObj.Result, esresult.Result...) | |||
ctx.JSON(200, resultObj) | |||
} else { | |||
log.Info("query es error," + err.Error()) | |||
} | |||
} else { | |||
log.Info("query all datasets.") | |||
//搜索的属性要指定{"timestamp":{"unmapped_type":"date"}} | |||
res, err := client.Search(TableName).SortBy(getSort(SortBy, ascending)).From(from).Size(Size).Do(ctx.Req.Context()) | |||
if err == nil { | |||
searchJson, _ := json.Marshal(res) | |||
log.Info("searchJson=" + string(searchJson)) | |||
esresult := makeDatasetResult(res, "", OnlyReturnNum, language) | |||
resultObj.Total = resultObj.PrivateTotal + esresult.Total | |||
log.Info("query dataset es count=" + fmt.Sprint(esresult.Total) + " total=" + fmt.Sprint(resultObj.Total)) | |||
resultObj.Result = append(resultObj.Result, esresult.Result...) | |||
ctx.JSON(200, resultObj) | |||
} else { | |||
log.Info("query es error," + err.Error()) | |||
ctx.JSON(200, "") | |||
} | |||
} | |||
} | |||
func makePrivateDataSet(datasets []*models.Dataset, res *SearchRes, Key string, language string) { | |||
for _, dataset := range datasets { | |||
record := make(map[string]interface{}) | |||
record["id"] = dataset.ID | |||
userId := dataset.UserID | |||
user, errUser := models.GetUserByID(userId) | |||
if errUser == nil { | |||
record["owerName"] = user.GetDisplayName() | |||
record["avatar"] = user.RelAvatarLink() | |||
} | |||
repo, errRepo := models.GetRepositoryByID(dataset.RepoID) | |||
if errRepo == nil { | |||
log.Info("repo_url=" + repo.FullName()) | |||
record["repoUrl"] = repo.FullName() | |||
record["avatar"] = repo.RelAvatarLink() | |||
} else { | |||
log.Info("repo err=" + errRepo.Error()) | |||
} | |||
record["title"] = makeHighLight(Key, dataset.Title) | |||
record["description"] = truncLongText(makeHighLight(Key, dataset.Description), true) | |||
record["category"] = dataset.Category | |||
record["task"] = dataset.Task | |||
record["download_times"] = dataset.DownloadTimes | |||
record["created_unix"] = dataset.CreatedUnix | |||
record["updated_unix"] = repo.UpdatedUnix | |||
record["updated_html"] = timeutil.TimeSinceUnix(repo.UpdatedUnix, language) | |||
res.Result = append(res.Result, record) | |||
} | |||
} | |||
func makeDatasetResult(sRes *elastic.SearchResult, Key string, OnlyReturnNum bool, language string) *SearchRes { | |||
total := sRes.Hits.TotalHits.Value | |||
result := make([]map[string]interface{}, 0) | |||
if !OnlyReturnNum { | |||
for i, hit := range sRes.Hits.Hits { | |||
log.Info("this is dataset query " + fmt.Sprint(i) + " result.") | |||
recordSource := make(map[string]interface{}) | |||
source, err := hit.Source.MarshalJSON() | |||
if err == nil { | |||
err = json.Unmarshal(source, &recordSource) | |||
if err == nil { | |||
record := make(map[string]interface{}) | |||
record["id"] = hit.Id | |||
userIdStr := recordSource["user_id"].(string) | |||
userId, cerr := strconv.ParseInt(userIdStr, 10, 64) | |||
if cerr == nil { | |||
user, errUser := models.GetUserByID(userId) | |||
if errUser == nil { | |||
record["owerName"] = user.GetDisplayName() | |||
record["avatar"] = user.RelAvatarLink() | |||
} | |||
} | |||
setRepoInfo(recordSource, record) | |||
record["title"] = getLabelValue("title", recordSource, hit.Highlight) | |||
record["category"] = getLabelValue("category", recordSource, hit.Highlight) | |||
if recordSource["description"] != nil { | |||
desc := getLabelValue("description", recordSource, hit.Highlight) | |||
record["description"] = dealLongText(desc, Key, hit.MatchedQueries) | |||
} else { | |||
record["description"] = "" | |||
} | |||
record["file_name"] = getDatasetFileName(getLabelValue("file_name", recordSource, hit.Highlight)) | |||
record["task"] = recordSource["task"] | |||
record["download_times"] = recordSource["download_times"] | |||
record["created_unix"] = recordSource["created_unix"] | |||
setUpdateHtml(record, recordSource["updated_unix"].(string), language) | |||
result = append(result, record) | |||
} else { | |||
log.Info("deal dataset source error," + err.Error()) | |||
} | |||
} else { | |||
log.Info("deal dataset source error," + err.Error()) | |||
} | |||
} | |||
} | |||
returnObj := &SearchRes{ | |||
Total: total, | |||
Result: result, | |||
} | |||
return returnObj | |||
} | |||
func getDatasetFileName(fileName string) string { | |||
slices := strings.Split(fileName, "-#,#-") | |||
fileName = strings.Join(slices, ", ") | |||
return fileName | |||
} | |||
func searchIssueOrPr(ctx *context.Context, TableName string, Key string, Page int, PageSize int, OnlyReturnNum bool, issueOrPr string) { | |||
/* | |||
任务,合并请求 ES名称:issue-es-index | |||
搜索: | |||
name character varying(255) , 标题 | |||
content text, 内容 | |||
comment text, 评论 | |||
排序: | |||
updated_unix | |||
*/ | |||
SortBy := ctx.Query("SortBy") | |||
ascending := ctx.QueryBool("Ascending") | |||
PrivateTotal := ctx.QueryInt("PrivateTotal") | |||
WebTotal := ctx.QueryInt("WebTotal") | |||
language := ctx.Query("language") | |||
if language == "" { | |||
language = "zh-CN" | |||
} | |||
from := (Page - 1) * PageSize | |||
if from == 0 { | |||
WebTotal = 0 | |||
} | |||
resultObj := &SearchRes{} | |||
log.Info("WebTotal=" + fmt.Sprint(WebTotal)) | |||
log.Info("PrivateTotal=" + fmt.Sprint(PrivateTotal)) | |||
resultObj.Result = make([]map[string]interface{}, 0) | |||
isPull := false | |||
if issueOrPr == "t" { | |||
isPull = true | |||
} | |||
if ctx.User != nil && (from < PrivateTotal || from == 0) { | |||
log.Info("actor is null?:" + fmt.Sprint(ctx.User == nil)) | |||
issues, count, err := models.SearchPrivateIssueOrPr(Page, PageSize, Key, isPull, ctx.User.ID) | |||
if err != nil { | |||
ctx.JSON(200, "") | |||
return | |||
} | |||
resultObj.PrivateTotal = count | |||
issuesSize := len(issues) | |||
if issuesSize > 0 { | |||
log.Info("Query private repo issue number is:" + fmt.Sprint(issuesSize) + " count=" + fmt.Sprint(count)) | |||
makePrivateIssueOrPr(issues, resultObj, Key, language) | |||
} else { | |||
log.Info("not found private repo issue,keyword=" + Key) | |||
} | |||
if issuesSize >= PageSize { | |||
if WebTotal > 0 { //next page, not first query. | |||
resultObj.Total = int64(WebTotal) | |||
ctx.JSON(200, resultObj) | |||
return | |||
} | |||
} | |||
} else { | |||
resultObj.PrivateTotal = int64(PrivateTotal) | |||
} | |||
from = from - PrivateTotal | |||
if from < 0 { | |||
from = 0 | |||
} | |||
Size := PageSize - len(resultObj.Result) | |||
boolQ := elastic.NewBoolQuery() | |||
isIssueQuery := elastic.NewTermQuery("is_pull", issueOrPr) | |||
if Key != "" { | |||
boolKeyQ := elastic.NewBoolQuery() | |||
log.Info("issue Key=" + Key) | |||
nameQuery := elastic.NewMatchQuery("name", Key).Boost(2).QueryName("f_first") | |||
contentQuery := elastic.NewMatchQuery("content", Key).Boost(1.5).QueryName("f_second") | |||
commentQuery := elastic.NewMatchQuery("comment", Key).Boost(1).QueryName("f_third") | |||
boolKeyQ.Should(nameQuery, contentQuery, commentQuery) | |||
boolQ.Must(isIssueQuery, boolKeyQ) | |||
} else { | |||
boolQ.Must(isIssueQuery) | |||
} | |||
res, err := client.Search(TableName).Query(boolQ).SortBy(getSort(SortBy, ascending)).From(from).Size(Size).Highlight(queryHighlight("name", "content", "comment")).Do(ctx.Req.Context()) | |||
if err == nil { | |||
searchJson, _ := json.Marshal(res) | |||
log.Info("searchJson=" + string(searchJson)) | |||
esresult := makeIssueResult(res, Key, OnlyReturnNum, language) | |||
resultObj.Total = resultObj.PrivateTotal + esresult.Total | |||
log.Info("query issue es count=" + fmt.Sprint(esresult.Total) + " total=" + fmt.Sprint(resultObj.Total)) | |||
resultObj.Result = append(resultObj.Result, esresult.Result...) | |||
ctx.JSON(200, resultObj) | |||
} else { | |||
log.Info("query es error," + err.Error()) | |||
} | |||
} | |||
func queryHighlight(names ...string) *elastic.Highlight { | |||
re := elastic.NewHighlight() | |||
for i := 0; i < len(names); i++ { | |||
field := &elastic.HighlighterField{ | |||
Name: names[i], | |||
} | |||
re.Fields(field) | |||
} | |||
re.PreTags("<font color='red'>") | |||
re.PostTags("</font>") | |||
return re | |||
} | |||
func setRepoInfo(recordSource map[string]interface{}, record map[string]interface{}) { | |||
repoIdstr := recordSource["repo_id"].(string) | |||
repoId, cerr := strconv.ParseInt(repoIdstr, 10, 64) | |||
if cerr == nil { | |||
repo, errRepo := models.GetRepositoryByID(repoId) | |||
if errRepo == nil { | |||
log.Info("repo_url=" + repo.FullName()) | |||
record["repoUrl"] = repo.FullName() | |||
record["avatar"] = repo.RelAvatarLink() | |||
} else { | |||
log.Info("repo err=" + errRepo.Error()) | |||
} | |||
} else { | |||
log.Info("parse int err=" + cerr.Error()) | |||
} | |||
} | |||
func makePrivateIssueOrPr(issues []*models.Issue, res *SearchRes, Key string, language string) { | |||
for _, issue := range issues { | |||
record := make(map[string]interface{}) | |||
record["id"] = issue.ID | |||
record["repo_id"] = issue.RepoID | |||
repo, errRepo := models.GetRepositoryByID(issue.RepoID) | |||
if errRepo == nil { | |||
log.Info("repo_url=" + repo.FullName()) | |||
record["repoUrl"] = repo.FullName() | |||
record["avatar"] = repo.RelAvatarLink() | |||
} else { | |||
log.Info("repo err=" + errRepo.Error()) | |||
} | |||
record["name"] = makeHighLight(Key, issue.Title) | |||
record["content"] = truncLongText(makeHighLight(Key, issue.Content), true) | |||
if issue.IsPull { | |||
pr, err1 := issue.GetPullRequest() | |||
if err1 == nil && pr != nil { | |||
record["pr_id"] = pr.ID | |||
} | |||
} | |||
record["index"] = issue.Index | |||
record["num_comments"] = issue.NumComments | |||
record["is_closed"] = issue.IsClosed | |||
record["updated_unix"] = issue.UpdatedUnix | |||
record["updated_html"] = timeutil.TimeSinceUnix(repo.UpdatedUnix, language) | |||
res.Result = append(res.Result, record) | |||
} | |||
} | |||
func makeIssueResult(sRes *elastic.SearchResult, Key string, OnlyReturnNum bool, language string) *SearchRes { | |||
total := sRes.Hits.TotalHits.Value | |||
result := make([]map[string]interface{}, 0) | |||
if !OnlyReturnNum { | |||
for i, hit := range sRes.Hits.Hits { | |||
log.Info("this is issue query " + fmt.Sprint(i) + " result.") | |||
recordSource := make(map[string]interface{}) | |||
source, err := hit.Source.MarshalJSON() | |||
if err == nil { | |||
err = json.Unmarshal(source, &recordSource) | |||
if err == nil { | |||
record := make(map[string]interface{}) | |||
record["id"] = hit.Id | |||
record["repo_id"] = recordSource["repo_id"] | |||
log.Info("recordSource[\"repo_id\"]=" + fmt.Sprint(recordSource["repo_id"])) | |||
setRepoInfo(recordSource, record) | |||
record["name"] = getLabelValue("name", recordSource, hit.Highlight) | |||
if recordSource["content"] != nil { | |||
desc := getLabelValue("content", recordSource, hit.Highlight) | |||
record["content"] = dealLongText(desc, Key, hit.MatchedQueries) | |||
if _, ok := hit.Highlight["content"]; !ok { | |||
if _, ok_comment := hit.Highlight["comment"]; ok_comment { | |||
desc := getLabelValue("comment", recordSource, hit.Highlight) | |||
record["content"] = trimHrefHtml(dealLongText(desc, Key, hit.MatchedQueries)) | |||
} | |||
} | |||
} else { | |||
if recordSource["comment"] != nil { | |||
desc := getLabelValue("comment", recordSource, hit.Highlight) | |||
record["content"] = dealLongText(desc, Key, hit.MatchedQueries) | |||
} | |||
} | |||
if recordSource["pr_id"] != nil { | |||
record["pr_id"] = recordSource["pr_id"] | |||
} | |||
log.Info("index=" + recordSource["index"].(string)) | |||
record["index"] = recordSource["index"] | |||
record["num_comments"] = recordSource["num_comments"] | |||
record["is_closed"] = recordSource["is_closed"] | |||
record["updated_unix"] = recordSource["updated_unix"] | |||
setUpdateHtml(record, recordSource["updated_unix"].(string), language) | |||
result = append(result, record) | |||
} else { | |||
log.Info("deal issue source error," + err.Error()) | |||
} | |||
} else { | |||
log.Info("deal issue source error," + err.Error()) | |||
} | |||
} | |||
} | |||
returnObj := &SearchRes{ | |||
Total: total, | |||
Result: result, | |||
} | |||
return returnObj | |||
} |
@@ -95,9 +95,9 @@ | |||
{{if .IsSigned}} | |||
<div class="right stackable menu"> | |||
<form class="fourteen wide mobile ten wide tablet ten wide computer column ui form ignore-dirty" style="margin:auto" action="/explore/repos"> | |||
<form id="searchForm" class="fourteen wide mobile ten wide tablet ten wide computer column ui form ignore-dirty" style="margin:auto" action="/all/search/" method="post"> | |||
<div class="ui fluid action input" style="background:#363840 ;border-radius: 5px;width: 200px;height:30px;border: #888888 solid 1px;"> | |||
<input name="q" value="{{.Keyword}}" placeholder="{{.i18n.Tr "explore.search_pro"}}..." | |||
<input name="q" value="{{.Keyword}}" placeholder="{{.i18n.Tr "explore.search"}}..." | |||
style="transition: background-color 5000s ease-in-out 0s;-webkit-text-fill-color:#888888;background:#363840 ;color:#888888;border: none;outline: none;"> | |||
<input type="hidden" name="tab" value="{{$.TabName}}"> | |||
<input type="hidden" name="sort" value="hot"> | |||
@@ -199,9 +199,9 @@ | |||
<!--a class="item" target="_blank" rel="noopener noreferrer" href="https://docs.gitea.io">{{.i18n.Tr "help"}}</a--> | |||
<div class="right stackable menu"> | |||
<form class="fourteen wide mobile ten wide tablet ten wide computer column ui form ignore-dirty" style="margin:auto" action="/explore/repos"> | |||
<form id="searchForm" class="fourteen wide mobile ten wide tablet ten wide computer column ui form ignore-dirty" style="margin:auto" action="/all/search/" method="post"> | |||
<div class="ui fluid action input" style="background:#363840 ;border-radius: 5px;width: 200px;height:30px;border: #888888 solid 1px;"> | |||
<input name="q" value="{{.Keyword}}" placeholder="{{.i18n.Tr "explore.search_pro"}}..." | |||
<input name="q" value="{{.Keyword}}" placeholder="{{.i18n.Tr "explore.search"}}..." | |||
style="transition: background-color 5000s ease-in-out 0s;-webkit-text-fill-color:#888888;background:#363840 ;color:#888888;border: none;outline: none;"> | |||
<input type="hidden" name="tab" value="{{$.TabName}}"> | |||
<input type="hidden" name="sort" value="hot"> | |||
@@ -93,9 +93,9 @@ | |||
{{if .IsSigned}} | |||
<div class="right stackable menu"> | |||
<form class="fourteen wide mobile ten wide tablet ten wide computer column ui form ignore-dirty" style="margin:auto" action="/explore/repos"> | |||
<form id="searchForm" class="fourteen wide mobile ten wide tablet ten wide computer column ui form ignore-dirty" style="margin:auto" action="/all/search/" method="post"> | |||
<div class="ui fluid action input" style="background:#363840 ;border-radius: 5px;width: 200px;height:30px;border: #888888 solid 1px;"> | |||
<input name="q" value="{{.Keyword}}" placeholder="{{.i18n.Tr "explore.search_pro"}}..." | |||
<input name="q" value="{{.Keyword}}" placeholder="{{.i18n.Tr "explore.search"}}..." | |||
style="transition: background-color 5000s ease-in-out 0s;-webkit-text-fill-color:#888888;background:#363840 ;color:#888888;border: none;outline: none;"> | |||
<input type="hidden" name="tab" value="{{$.TabName}}"> | |||
<input type="hidden" name="sort" value="{{$.SortType}}"> | |||
@@ -196,9 +196,9 @@ | |||
<!--a class="item" target="_blank" rel="noopener noreferrer" href="https://docs.gitea.io">{{.i18n.Tr "help"}}</a--> | |||
<div class="right stackable menu"> | |||
<form class="fourteen wide mobile ten wide tablet ten wide computer column ui form ignore-dirty" style="margin:auto" action="/explore/repos"> | |||
<form id="searchForm" class="fourteen wide mobile ten wide tablet ten wide computer column ui form ignore-dirty" style="margin:auto" action="/all/search/" method="post"> | |||
<div class="ui fluid action input" style="background:#363840 ;border-radius: 5px;width: 200px;height:30px;border: #888888 solid 1px;"> | |||
<input name="q" value="{{.Keyword}}" placeholder="{{.i18n.Tr "explore.search_pro"}}..." | |||
<input name="q" value="{{.Keyword}}" placeholder="{{.i18n.Tr "explore.search"}}..." | |||
style="transition: background-color 5000s ease-in-out 0s;-webkit-text-fill-color:#888888;background:#363840 ;color:#888888;border: none;outline: none;"> | |||
<input type="hidden" name="tab" value="{{$.TabName}}"> | |||
<input type="hidden" name="sort" value="{{$.SortType}}"> | |||
@@ -96,9 +96,9 @@ | |||
{{if .IsSigned}} | |||
<div class="right stackable menu"> | |||
<form class="fourteen wide mobile ten wide tablet ten wide computer column ui form ignore-dirty" style="margin:auto" action="/explore/repos"> | |||
<form id="searchForm" class="fourteen wide mobile ten wide tablet ten wide computer column ui form ignore-dirty" style="margin:auto" action="/all/search/" method="post"> | |||
<div class="ui fluid action input" style="background:#363840 ;border-radius: 5px;width: 200px;height:30px;border: #888888 solid 1px;"> | |||
<input name="q" value="{{.Keyword}}" placeholder="{{.i18n.Tr "explore.search_pro"}}..." | |||
<input name="q" value="{{.Keyword}}" placeholder="{{.i18n.Tr "explore.search"}}..." | |||
style="transition: background-color 5000s ease-in-out 0s;-webkit-text-fill-color:#888888;background:#363840 ;color:#888888;border: none;outline: none;"> | |||
<input type="hidden" name="tab" value="{{$.TabName}}"> | |||
<input type="hidden" name="sort" value="{{$.SortType}}"> | |||
@@ -199,9 +199,9 @@ | |||
<!--a class="item" target="_blank" rel="noopener noreferrer" href="https://docs.gitea.io">{{.i18n.Tr "help"}}</a--> | |||
<div class="right stackable menu"> | |||
<form class="fourteen wide mobile ten wide tablet ten wide computer column ui form ignore-dirty" style="margin:auto" action="/explore/repos"> | |||
<form id="searchForm" class="fourteen wide mobile ten wide tablet ten wide computer column ui form ignore-dirty" style="margin:auto" action="/all/search/" method="post"> | |||
<div class="ui fluid action input" style="background:#363840 ;border-radius: 5px;width: 200px;height:30px;border: #888888 solid 1px;"> | |||
<input name="q" value="{{.Keyword}}" placeholder="{{.i18n.Tr "explore.search_pro"}}..." | |||
<input name="q" value="{{.Keyword}}" placeholder="{{.i18n.Tr "explore.search"}}..." | |||
style="transition: background-color 5000s ease-in-out 0s;-webkit-text-fill-color:#888888;background:#363840 ;color:#888888;border: none;outline: none;"> | |||
<input type="hidden" name="tab" value="{{$.TabName}}"> | |||
<input type="hidden" name="sort" value="{{$.SortType}}"> | |||
@@ -0,0 +1,95 @@ | |||
{{template "base/head" .}} | |||
<div class="explore seach"> | |||
<div class="repos--seach"> | |||
<div class="ui container"> | |||
<div id="search_div" class="ui two column centered grid"> | |||
<div class="fourteen wide mobile ten wide tablet ten wide computer column ui form ignore-dirty" style="margin-top:1.2rem;margin-bottom: 1.2rem;"> | |||
<div class="ui fluid action input"> | |||
<input name="q" id="keyword_input" value="{{.Keyword}}" placeholder="{{.i18n.Tr "home.search"}}..." autofocus=""> | |||
<input type="hidden" name="topic" value=""> | |||
<input type="hidden" name="tab" value=""> | |||
<input type="hidden" name="sort" value="hot"> | |||
<button class="ui green button" onclick="search()">{{.i18n.Tr "home.search"}}</button> | |||
</div> | |||
</div> | |||
</div> | |||
<div id="search_label_div" style="display:none"> | |||
</div> | |||
</div> | |||
<div class="ui container seachnav"> | |||
<div class="ui secondary pointing menu"> | |||
<a id="repo_item" class="item" href="javascript:searchItem(1,10);"> | |||
{{.i18n.Tr "home.search_repo"}} | |||
<span class="ui circular mini label" id="repo_total"></span> | |||
</a> | |||
<a id="dataset_item" class="item" href="javascript:searchItem(5,50);"> | |||
{{.i18n.Tr "home.search_dataset"}} | |||
<span class="ui circular mini label" id="dataset_total"></span> | |||
</a> | |||
<a id="issue_item" class="item" href="javascript:searchItem(2,20);"> | |||
{{.i18n.Tr "home.search_issue"}} | |||
<span class="ui circular mini label" id="issue_total"></span> | |||
</a> | |||
<a id="pr_item" class="item" href="javascript:searchItem(6,60);"> | |||
{{.i18n.Tr "home.search_pr"}} | |||
<span class="ui circular mini label" id="pr_total"></span> | |||
</a> | |||
<a id="user_item" class="item" href="javascript:searchItem(3,30);"> | |||
{{.i18n.Tr "home.search_user"}} | |||
<span class="ui circular mini label" id="user_total"></span> | |||
</a> | |||
<a id="org_item" class="item" href="javascript:searchItem(4,40);"> | |||
{{.i18n.Tr "home.search_org"}} <span class="ui circular mini label" id="org_total"></span> | |||
</a> | |||
</div> | |||
</div> | |||
</div> | |||
<div class="ui container"> | |||
<span id="find_id">{{.i18n.Tr "home.search_finded"}}</span><span id="find_title"></span> | |||
<div class="ui right floated secondary filter menu"> | |||
<!-- Sort --> | |||
<div class="ui right dropdown type jump item"> | |||
<span class="text"> | |||
{{.i18n.Tr "repo.issues.filter_sort"}} | |||
<i class="dropdown icon"></i> | |||
</span> | |||
<div class="menu" id="sort_type"> | |||
</div> | |||
</div> | |||
</div> | |||
<div class="ui divider" style="margin-top: 1.25rem;"></div> | |||
<div class="ui very relaxed divided list" id="child_search_item"> | |||
</div><!--seach list end--> | |||
<div class="center page buttons" style="margin: 0px auto 15px"> | |||
<div class="ui borderless mini pagination menu" id="page_menu"> | |||
</div> | |||
</div> | |||
<div id="tipmsg"></div> | |||
</div> | |||
</div> | |||
<script src="/self/js/jquery.min.js" type="text/javascript"></script> | |||
<script src="/home/search.js?v={{MD5 AppVer}}" type="text/javascript"></script> | |||
<div class="am-mt-30"></div> | |||
{{template "base/footer" .}} |
@@ -628,6 +628,32 @@ display: block; | |||
.a_margin{ | |||
margin: 0px !important; | |||
} | |||
/*pages*/ | |||
.ui.borderless.pagination {border:none} | |||
.ui.pagination.menu .item { | |||
min-width: 32px; | |||
text-align: center; | |||
height: 32px; | |||
border-radius: .28571429rem; | |||
margin: 0 5px; | |||
background-color: #F2F2F2; | |||
} | |||
.ui.pagination.menu>.item:first-child, .ui.pagination.menu .item:last-child { | |||
background-color: #FFF !important; | |||
} | |||
.ui.ui.menu .item.disabled{ | |||
background-color: #F2F2F2; | |||
} | |||
.ui.pagination.menu .active.item { | |||
background-color: #3291F8; | |||
color: #FFF; | |||
} | |||
.ui.pagination.menu .item>.input { | |||
margin: 0em .5em; | |||
width: 3em; | |||
height: 32px; | |||
} | |||
@media only screen and (max-width: 767px) { | |||
.following.bar #navbar .brand{ | |||
padding-top: 6px; | |||
@@ -784,3 +810,86 @@ display: block; | |||
color: #0366d6 !important; | |||
box-shadow: -15px 0px 10px #fff; | |||
} | |||
/**seach**/ | |||
/**搜索导航条适配窄屏**/ | |||
.seachnav{ | |||
overflow-x: auto; | |||
overflow-y: hidden; | |||
scrollbar-width: none; /* firefox */ | |||
-ms-overflow-style: none; /* IE 10+ */ | |||
} | |||
.seachnav::-webkit-scrollbar { | |||
display: none; /* Chrome Safari */ | |||
} | |||
.ui.green.button, .ui.green.buttons .button{ | |||
background-color: #5BB973; | |||
} | |||
.seach .repos--seach{ | |||
padding-bottom: 0; | |||
border-bottom: none; | |||
} | |||
.seach .ui.secondary.pointing.menu{ | |||
border-bottom: none; | |||
} | |||
.seach .ui.secondary.pointing.menu .item > i{ | |||
margin-right: 5px; | |||
} | |||
.seach .ui.secondary.pointing.menu .active.item{ | |||
border-bottom-width: 2px; | |||
margin: 0 0 -1px; | |||
} | |||
.seach .ui.menu .active.item>.label { | |||
background: #1684FC; | |||
color: #FFF; | |||
} | |||
.seach .ui.menu .item>.label:not(.active.item>.label) { | |||
background: #e8e8e8; | |||
color: rgba(0,0,0,.6); | |||
} | |||
.highlight{ | |||
color: red; | |||
} | |||
.ui.list .list>.item>img.image+.content, .ui.list>.item>img.image+.content { | |||
width: calc(100% - 4.0em); | |||
margin-left: 0; | |||
} | |||
.seach .ui.list .list>.item .header, .seach .ui.list>.item .header{ | |||
margin-bottom: 0.5em; | |||
font-size: 1.4rem !important; | |||
font-weight: normal; | |||
} | |||
.seach .time, .seach .time a{ | |||
font-size: 12px; | |||
color: grey; | |||
} | |||
.seach .list .item.members .ui.avatar.image { | |||
width: 3.2em; | |||
height: 3.2em; | |||
} | |||
.ui.list .list>.item.members>img.image+.content, .ui.list>.item.members>img.image+.content { | |||
width: calc(100% - 4.0em); | |||
margin-left: 0; | |||
} | |||
.searchlabel{ | |||
color: rgba(16, 16, 16, 100); | |||
font-size: 24px; | |||
text-align: left; | |||
font-family: SourceHanSansSC-medium; | |||
} | |||
.hiddenSearch{ | |||
margin: auto; | |||
display: none; | |||
} | |||
#tipmsg { | |||
display: none; | |||
z-index: 9999; | |||
width:150; | |||
height: 80; | |||
} |
Dear OpenI User
Thank you for your continuous support to the Openl Qizhi Community AI Collaboration Platform. In order to protect your usage rights and ensure network security, we updated the Openl Qizhi Community AI Collaboration Platform Usage Agreement in January 2024. The updated agreement specifies that users are prohibited from using intranet penetration tools. After you click "Agree and continue", you can continue to use our services. Thank you for your cooperation and understanding.
For more agreement content, please refer to the《Openl Qizhi Community AI Collaboration Platform Usage Agreement》