Perfil de Administrador
-Bem-vindo ao painel do administrador.
-diff --git a/Brewfile b/Brewfile new file mode 100644 index 0000000000..7562594f48 --- /dev/null +++ b/Brewfile @@ -0,0 +1,7 @@ +tap "caskroom/cask" + +cask "google-chrome" +cask "firefox" + +brew "chromedriver" +brew "geckodriver" diff --git a/Gemfile b/Gemfile index 50771662fa..35902538e0 100644 --- a/Gemfile +++ b/Gemfile @@ -70,3 +70,6 @@ group :test do gem "capybara" gem "selenium-webdriver" end + +gem "activerecord-import" + diff --git a/Gemfile.lock b/Gemfile.lock index f229958343..7208ffc91c 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -56,6 +56,8 @@ GEM activemodel (= 8.1.3) activesupport (= 8.1.3) timeout (>= 0.4.0) + activerecord-import (2.2.0) + activerecord (>= 4.2) activestorage (8.1.3) actionpack (= 8.1.3) activejob (= 8.1.3) @@ -83,9 +85,9 @@ GEM bcrypt_pbkdf (1.1.2) bigdecimal (4.1.2) bindex (0.8.1) - bootsnap (1.24.5) + bootsnap (1.24.6) msgpack (~> 1.2) - brakeman (8.0.4) + brakeman (8.0.5) racc builder (3.3.0) bundler-audit (0.9.3) @@ -100,7 +102,7 @@ GEM rack-test (>= 0.6.3) regexp_parser (>= 1.5, < 3.0) xpath (~> 3.2) - concurrent-ruby (1.3.6) + concurrent-ruby (1.3.7) connection_pool (3.0.2) crass (1.0.6) cucumber (10.2.0) @@ -185,7 +187,7 @@ GEM jbuilder (2.15.1) actionview (>= 7.0.0) activesupport (>= 7.0.0) - json (2.19.7) + json (2.19.9) kamal (2.11.0) activesupport (>= 7.0) base64 (~> 0.2) @@ -218,9 +220,9 @@ GEM minitest (6.0.6) drb (~> 2.0) prism (~> 1.5) - msgpack (1.8.1) + msgpack (1.8.3) multi_test (1.1.0) - net-imap (0.6.4) + net-imap (0.6.4.1) date net-protocol net-pop (0.1.2) @@ -262,7 +264,7 @@ GEM actionpack (>= 7.0.0) activesupport (>= 7.0.0) rack - psych (5.3.1) + psych (5.4.0) date stringio public_suffix (7.0.5) @@ -335,7 +337,7 @@ GEM rspec-mocks (>= 3.13.0, < 5.0.0) rspec-support (>= 3.13.0, < 5.0.0) rspec-support (3.13.7) - rubocop (1.87.0) + rubocop (1.88.0) json (~> 2.3) language_server-protocol (~> 3.17.0.2) lint_roller (~> 1.1.0) @@ -353,7 +355,7 @@ GEM lint_roller (~> 1.1) rubocop (>= 1.75.0, < 2.0) rubocop-ast (>= 1.47.1, < 2.0) - rubocop-rails (2.35.3) + rubocop-rails (2.35.4) activesupport (>= 4.2.0) lint_roller (~> 1.1) rack (>= 1.1) @@ -367,9 +369,9 @@ GEM ruby-vips (2.3.0) ffi (~> 1.12) logger - rubyzip (3.2.2) + rubyzip (3.4.0) securerandom (0.4.1) - selenium-webdriver (4.43.0) + selenium-webdriver (4.45.0) base64 (~> 0.2) logger (~> 1.4) rexml (~> 3.2, >= 3.2.5) @@ -393,13 +395,13 @@ GEM fugit (~> 1.11) railties (>= 7.1) thor (>= 1.3.1) - sqlite3 (2.9.4-aarch64-linux-gnu) - sqlite3 (2.9.4-aarch64-linux-musl) - sqlite3 (2.9.4-arm-linux-gnu) - sqlite3 (2.9.4-arm-linux-musl) - sqlite3 (2.9.4-arm64-darwin) - sqlite3 (2.9.4-x86_64-linux-gnu) - sqlite3 (2.9.4-x86_64-linux-musl) + sqlite3 (2.9.5-aarch64-linux-gnu) + sqlite3 (2.9.5-aarch64-linux-musl) + sqlite3 (2.9.5-arm-linux-gnu) + sqlite3 (2.9.5-arm-linux-musl) + sqlite3 (2.9.5-arm64-darwin) + sqlite3 (2.9.5-x86_64-linux-gnu) + sqlite3 (2.9.5-x86_64-linux-musl) sshkit (1.25.0) base64 logger @@ -435,7 +437,7 @@ GEM bindex (>= 0.4.0) railties (>= 8.0.0) websocket (1.2.11) - websocket-driver (0.8.0) + websocket-driver (0.8.1) base64 websocket-extensions (>= 0.1.0) websocket-extensions (0.1.5) @@ -455,6 +457,7 @@ PLATFORMS x86_64-linux-musl DEPENDENCIES + activerecord-import bcrypt (~> 3.1.7) bootsnap brakeman @@ -497,6 +500,7 @@ CHECKSUMS activejob (8.1.3) sha256=a149b1766aa8204c3c3da7309e4becd40fcd5529c348cffbf6c9b16b565fe8d3 activemodel (8.1.3) sha256=90c05cbe4cef3649b8f79f13016191ea94c4525ce4a5c0fb7ef909c4b91c8219 activerecord (8.1.3) sha256=8003be7b2466ba0a2a670e603eeb0a61dd66058fccecfc49901e775260ac70ab + activerecord-import (2.2.0) sha256=f8ca99b196e50775723d1f1d192c379f656378dc9f5628240992a0d78807fa4b activestorage (8.1.3) sha256=0564ce9309143951a67615e1bb4e090ee54b8befed417133cae614479b46384d activesupport (8.1.3) sha256=21a5e0dfbd4c3ddd9e1317ec6a4d782fa226e7867dc70b0743acda81a1dca20e addressable (2.9.0) sha256=7fdf6ac3660f7f4e867a0838be3f6cf722ace541dd97767fa42bc6cfa980c7af @@ -506,13 +510,13 @@ CHECKSUMS bcrypt_pbkdf (1.1.2) sha256=c2414c23ce66869b3eb9f643d6a3374d8322dfb5078125c82792304c10b94cf6 bigdecimal (4.1.2) sha256=53d217666027eab4280346fba98e7d5b66baaae1b9c3c1c0ffe89d48188a3fbd bindex (0.8.1) sha256=7b1ecc9dc539ed8bccfc8cb4d2732046227b09d6f37582ff12e50a5047ceb17e - bootsnap (1.24.5) sha256=36b677448524d279b470469aabd5dff4a980e3fa4931a0df68da4a500eb1b6c4 - brakeman (8.0.4) sha256=7bf921fa9638544835df9aa7b3e720a9a72c0267f34f92135955edd80d4dcf6f + bootsnap (1.24.6) sha256=c60bab88c70332290f0a2636a288f675299eb4f804a02a3c085b42eca9da164a + brakeman (8.0.5) sha256=03735f9690d3fd4b32d66aacbf0a6d15a84266bdd06b32c05c8ecc8f6021d2be builder (3.3.0) sha256=497918d2f9dca528fdca4b88d84e4ef4387256d984b8154e9d5d3fe5a9c8835f bundler (4.0.12) sha256=7f8b757d28dfb636e7b24fba2344ac6dd13b5b24f4b46d62573d483f211825ac bundler-audit (0.9.3) sha256=81c8766c71e47d0d28a0f98c7eed028539f21a6ea3cd8f685eb6f42333c9b4e9 capybara (3.40.0) sha256=42dba720578ea1ca65fd7a41d163dd368502c191804558f6e0f71b391054aeef - concurrent-ruby (1.3.6) sha256=6b56837e1e7e5292f9864f34b69c5a2cbc75c0cf5338f1ce9903d10fa762d5ab + concurrent-ruby (1.3.7) sha256=4412caec3a5ea2e5fdc52076724c071a81f2c0593d83b2ac8cbb8ca63b3151b0 connection_pool (3.0.2) sha256=33fff5ba71a12d2aa26cb72b1db8bba2a1a01823559fb01d29eb74c286e62e0a crass (1.0.6) sha256=dc516022a56e7b3b156099abc81b6d2b08ea1ed12676ac7a5657617f012bd45d cucumber (10.2.0) sha256=fdedbd31ecf40858b60f04853f2aa15c44f5c30bbac29c6a227fa1e7005a8158 @@ -553,7 +557,7 @@ CHECKSUMS io-console (0.8.2) sha256=d6e3ae7a7cc7574f4b8893b4fca2162e57a825b223a177b7afa236c5ef9814cc irb (1.18.0) sha256=de9454a0703a54704b9811a5ef31a60c86949fbf4013fcf244fabc7c775248e3 jbuilder (2.15.1) sha256=2430bec28fb0cebacb5875b1009cf9d8bc3c303ccb810c4c8b062a4b51457637 - json (2.19.7) sha256=fe432c8639f6efff69f9d73b518a3705d9581ab93156f981ea72806e1e5bcc3e + json (2.19.9) sha256=9b9025b7cdddafa38d316eca0b2358488e42d417045c1b90d216a9fefe46b79a kamal (2.11.0) sha256=1408864425e0dec7e0a14d712a3b13f614e9f3a425b7661d3f9d287a51d7dd75 language_server-protocol (3.17.0.5) sha256=fd1e39a51a28bf3eec959379985a72e296e9f9acfce46f6a79d31ca8760803cc lint_roller (1.1.0) sha256=2c0c845b632a7d172cb849cc90c1bce937a28c5c8ccccb50dfd46a485003cc87 @@ -566,9 +570,9 @@ CHECKSUMS mini_magick (5.3.1) sha256=29395dfd76badcabb6403ee5aff6f681e867074f8f28ce08d78661e9e4a351c4 mini_mime (1.1.5) sha256=8681b7e2e4215f2a159f9400b5816d85e9d8c6c6b491e96a12797e798f8bccef minitest (6.0.6) sha256=153ea36d1d987a62942382b61075745042a2b3123b1cd48f4c3675af9cc7d6f1 - msgpack (1.8.1) sha256=3fef787cd3965fd119c08a22724a56a93ca25008c3421fc15039f603a8b7c86c + msgpack (1.8.3) sha256=8bda4a6428d3244e50d6bd55854d354edbada88a4e1f4f5731a39a0f86bee6a1 multi_test (1.1.0) sha256=e9e550cdd863fb72becfe344aefdcd4cbd26ebf307847f4a6c039a4082324d10 - net-imap (0.6.4) sha256=9a5598c67a3022c284d98430ef1d4948e7dbdb62596f61081ea8ca933270a02b + net-imap (0.6.4.1) sha256=29f0360d75a7efd3539f16ac1957dea5c0a51ddeceb348db4553c3120914ea0d net-pop (0.1.2) sha256=848b4e982013c15b2f0382792268763b748cce91c9e91e36b0f27ed26420dff3 net-protocol (0.2.2) sha256=aa73e0cba6a125369de9837b8d8ef82a61849360eba0521900e2c3713aa162a8 net-scp (4.1.0) sha256=a99b0b92a1e5d360b0de4ffbf2dc0c91531502d3d4f56c28b0139a7c093d1a5d @@ -590,7 +594,7 @@ CHECKSUMS prettyprint (0.2.0) sha256=2bc9e15581a94742064a3cc8b0fb9d45aae3d03a1baa6ef80922627a0766f193 prism (1.9.0) sha256=7b530c6a9f92c24300014919c9dcbc055bf4cdf51ec30aed099b06cd6674ef85 propshaft (1.3.2) sha256=1d56a3e56a92c21bfc29caf07406b5386b00d4c47ddf357cf989a5a234b1389e - psych (5.3.1) sha256=eb7a57cef10c9d70173ff74e739d843ac3b2c019a003de48447b2963d81b1974 + psych (5.4.0) sha256=14f72d69a611af663d7d70e4a7b67d9eb1f3ae9f8d916b478961d5a0075ba5b7 public_suffix (7.0.5) sha256=1a8bb08f1bbea19228d3bed6e5ed908d1cb4f7c2726d18bd9cadf60bc676f623 puma (8.0.2) sha256=c8ed871dfbbe66448ea9ffd46692342d9804d4071522b52b5331b7b6e7b686fb raabro (1.4.0) sha256=d4fa9ff5172391edb92b242eed8be802d1934b1464061ae5e70d80962c5da882 @@ -614,27 +618,29 @@ CHECKSUMS rspec-mocks (3.13.8) sha256=086ad3d3d17533f4237643de0b5c42f04b66348c28bf6b9c2d3f4a3b01af1d47 rspec-rails (8.0.4) sha256=06235692fc0892683d3d34977e081db867434b3a24ae0dd0c6f3516bad4e22df rspec-support (3.13.7) sha256=0640e5570872aafefd79867901deeeeb40b0c9875a36b983d85f54fb7381c47c - rubocop (1.87.0) sha256=b9d9ddf55116a513f8ef2c7ae660662d8b49301f118d3f0df61865b33a5c188d + rubocop (1.88.0) sha256=e420ddf1662d0ef34bc8a2910ac4b396a7ddda0b51a708264405241734b08e0b rubocop-ast (1.49.1) sha256=4412f3ee70f6fe4546cc489548e0f6fcf76cafcfa80fa03af67098ffed755035 rubocop-performance (1.26.1) sha256=cd19b936ff196df85829d264b522fd4f98b6c89ad271fa52744a8c11b8f71834 - rubocop-rails (2.35.3) sha256=6edd45410866912b9b2e90ae3aeafd31d576df2bb2a9c9408f1667a50c32c7de + rubocop-rails (2.35.4) sha256=3aeaa325439c89950e8327565682ea794065d08e2ecbbfe95032bfa295a35df5 rubocop-rails-omakase (1.1.0) sha256=2af73ac8ee5852de2919abbd2618af9c15c19b512c4cfc1f9a5d3b6ef009109d ruby-progressbar (1.13.0) sha256=80fc9c47a9b640d6834e0dc7b3c94c9df37f08cb072b7761e4a71e22cff29b33 ruby-vips (2.3.0) sha256=e685ec02c13969912debbd98019e50492e12989282da5f37d05f5471442f5374 - rubyzip (3.2.2) sha256=c0ed99385f0625415c8f05bcae33fe649ed2952894a95ff8b08f26ca57ea5b3c + rubyzip (3.4.0) sha256=6de39bc9eba302b635a476d16c9e16b0872ad24517c2f98f2b3a7ea23caff57b securerandom (0.4.1) sha256=cc5193d414a4341b6e225f0cb4446aceca8e50d5e1888743fac16987638ea0b1 - selenium-webdriver (4.43.0) sha256=a634377b964b701c6ac0a009ce3a08fa34ec1e1e7fe9a6d57e3088d14529a65c + + selenium-webdriver (4.45.0) sha256=ecac65a4df86ac6f7d707e6dcbacaa9c08b6cf2b966babecfb9653c5aa13e2d1 shoulda-matchers (5.3.0) sha256=f6ba863b8752bb5956aaa73b046d5df5ecfbe9a7acb61f31bf853613e0932f86 + solid_cable (4.0.0) sha256=8379680ef6bf36e195eb876a6306ea290f87d5fa10bc4a757bc2a918f83229b5 solid_cache (1.0.10) sha256=bc05a2fb3ac78a6f43cbb5946679cf9db67dd30d22939ededc385cb93e120d41 solid_queue (1.4.0) sha256=e6a18d196f0b27cb6e3c77c5b31258b05fb634f8ed64fb1866ed164047216c2a - sqlite3 (2.9.4-aarch64-linux-gnu) sha256=ecabed721e6eaad54601d2685f09029d90025efc8d931040dc89cb3f8a2080ec - sqlite3 (2.9.4-aarch64-linux-musl) sha256=ffb4255947fb54c8c3eeca97460c9702b40de91ce390455ef7367ca6a3929a31 - sqlite3 (2.9.4-arm-linux-gnu) sha256=9ee2008b9fbec984c3c165b0d7eedd2bd2a415100b761bfa3a4c6fbec9208bf6 - sqlite3 (2.9.4-arm-linux-musl) sha256=8dc1fe4da6977992cd62decf4a93ccf6cc2e124a5e6a340160d52092f70e837a - sqlite3 (2.9.4-arm64-darwin) sha256=1d5aad413a815d236e96d43f05a1acc600b6cd086800770342a3f9c2877499ff - sqlite3 (2.9.4-x86_64-linux-gnu) sha256=537a3eda71b1df1336d0055cbebe55a7317c34870c192c7b6b9d8d0be6871847 - sqlite3 (2.9.4-x86_64-linux-musl) sha256=3fc5e865b4be9a85d998203ef8d0c0fdcb92f20acf34a254346ff8a19088efec + sqlite3 (2.9.5-aarch64-linux-gnu) sha256=78075b6337d3d182c6d2b4691049ed45cd220826160c9ea18946bf6a1de200dc + sqlite3 (2.9.5-aarch64-linux-musl) sha256=18c801185deb4adc01ddb281e8f672a39e3d1729979ca91e39439cd3eac0402d + sqlite3 (2.9.5-arm-linux-gnu) sha256=1bdfca0c7d63998c60b0f4a8e3c8df2d33800ccc4abd2d612eddbbbc92a4c48b + sqlite3 (2.9.5-arm-linux-musl) sha256=bae1109d12b2e9f588455967729b008e1ff4feb7761749df695019c9079913c6 + sqlite3 (2.9.5-arm64-darwin) sha256=d0cf444a70fc9395d513cfbcc1e6719e224aa645314e3824cb0474c721425aa2 + sqlite3 (2.9.5-x86_64-linux-gnu) sha256=233dbcb6714148dd23bc5aeb33e8efd6eac974969564ddd5794c23d5f52b231e + sqlite3 (2.9.5-x86_64-linux-musl) sha256=e7d3a7474e8af0f96150c21abc203fbab5437206bfcdf11deab7741c0ca516f2 sshkit (1.25.0) sha256=c8c6543cdb60f91f1d277306d585dd11b6a064cb44eab0972827e4311ff96744 stimulus-rails (1.3.4) sha256=765676ffa1f33af64ce026d26b48e8ffb2e0b94e0f50e9119e11d6107d67cb06 stringio (3.2.0) sha256=c37cb2e58b4ffbd33fe5cd948c05934af997b36e0b6ca6fdf43afa234cf222e1 @@ -654,7 +660,7 @@ CHECKSUMS useragent (0.16.11) sha256=700e6413ad4bb954bb63547fa098dddf7b0ebe75b40cc6f93b8d54255b173844 web-console (4.3.0) sha256=e13b71301cdfc2093f155b5aa3a622db80b4672d1f2f713119cc7ec7ac6a6da4 websocket (1.2.11) sha256=b7e7a74e2410b5e85c25858b26b3322f29161e300935f70a0e0d3c35e0462737 - websocket-driver (0.8.0) sha256=ed0dba4b943c22f17f9a734817e808bc84cdce6a7e22045f5315aa57676d4962 + websocket-driver (0.8.1) sha256=5ab238238ce230e5d4b262d2be39624c867914eab99171dc4952b58b577c2d96 websocket-extensions (0.1.5) sha256=1c6ba63092cda343eb53fc657110c71c754c56484aad42578495227d717a8241 xpath (3.2.0) sha256=6dfda79d91bb3b949b947ecc5919f042ef2f399b904013eb3ef6d20dd3a4082e zeitwerk (2.8.2) sha256=7212a61311083c604184b1ea2574b9aa05cd14f855a0841c06985cabe9181d12 diff --git a/app/assets/stylesheets/admin.css b/app/assets/stylesheets/admin.css new file mode 100644 index 0000000000..bdb7c3ad32 --- /dev/null +++ b/app/assets/stylesheets/admin.css @@ -0,0 +1,152 @@ +*{ + margin: 0; + padding: 0; + box-sizing: border-box; + font-family: 'Poppins', sans-serif; +} +/* +.header_admin{ + color: yellow; + width: 100%; + height: 0; + background-color: yellow; + top:0; + + + padding: 40px 0 10px 0; +} +*/ + +body{ + height: 100vh; +} + +/*menu principal*/ +nav.navbar{ + width: 80px; + height: 100%; + background-color: #6f2477; + + padding: 40px 0 40px 1%; + + position:fixed; + top:0; + left:0; + + overflow: hidden; + transition: 0.7s; + +} + +nav.navbar.expandir{ + width: 300px; +} + +/*conteudo*/ + +.dashboard-content{ + + width: 100%; + height: 100%; + background-color: #fff; + + padding: 40px 10px 0 8%; + +} + +.dashboard-content{ + transition: 0.7s; +} + +.conteudo-admin{ + color: #000; +} + +.dashboard-content.expandir{ + padding-left: 320px; + + transition: .5s; +} + +/*seções*/ +section{ + overflow: hidden; +} + + +/*botão*/ +.btn-expandir{ + width: 100%; + padding-left: 10px; + +} + +.btn-expandir > i{ + color: #fff; + font-size: 20px; + cursor: pointer; +} + +/* navegação*/ +ul.nav-menu{ + height: 100%; + list-style-type: none; + + padding-top: 10px; +} + +ul li.nav-item{ + transition: 0.2s; + /*margin-left: 10px;*/ +} + +ul li.ativo{ + background-color: #fff; + box-sizing: border-box; + border-end-start-radius: 10px; + border-top-left-radius: 10px; +} + +ul li.nav-item.ativo a{ + color: #6f2477; +} + + +ul li.nav-item:hover{ + background-color: #fff; + box-sizing: border-box; + border-end-start-radius: 10px; + border-top-left-radius: 10px; +} + +ul li.nav-item a:hover{ + color: #6f2477; +} + +ul li.nav-item a{ + color: #fff; + text-decoration: none; + font-size: 20px; + padding: 20px 4%; + + display: flex; + line-height: 40px; + margin-left: 10px; +} + +ul li.nav-item a .nav-text{ + margin-left: 70px; + transition: 0.5s; + opacity:0; + +} + +nav.navbar.expandir .nav-text{ + margin-left: 40px; + opacity: 1; +} + +ul li.nav-item a .nav-icon{ + font-size: 30px; +} + diff --git a/app/assets/stylesheets/admin_gerenciamento.css b/app/assets/stylesheets/admin_gerenciamento.css new file mode 100644 index 0000000000..27e296ea3a --- /dev/null +++ b/app/assets/stylesheets/admin_gerenciamento.css @@ -0,0 +1,59 @@ +.conteudo-admin{ + display: block; + box-sizing: border-box; + justify-content: center; + align-items: center; + min-height: 80vh; + width: 100%; +} + +.btn-group-vertical{ + display: flex; + flex-direction: column; + justify-content: center; + + align-items: center; + + flex-grow: 1; + width: 100%; + padding: 20px; + +} + +.ger-menu{ + padding-top: 10px; + padding-left: 320px; + padding-bottom: 10px; + list-style: none; + width: 100%; +} + + + +ul li.ger-link{ + + width: 100%; + max-width:320px; + padding: 5px; +} + +ul li.ger-link .ger-btn { + display: block; /* Faz o link se comportar como um bloco */ + width: 100%; /* Força o botão a ocupar todos os 320px do pai */ + text-align: center; /* Centraliza o texto dentro do botão */ + color: #000; + text-decoration: none; + font-size: 20px; + padding: 10px; + + background-color: #f8f9fa; + border: 1px solid #ced4da; + border-radius: 8px; + transition: all 0.2s ease-in-out; +} + +ul li.ger-link .ger-btn:hover { + background-color: #e2e6ea; + border-color: #dae0e5; + box-shadow: 0 4px 6px rgba(0, 0, 0, 0.05); +} \ No newline at end of file diff --git a/app/controllers/dashboards_controller.rb b/app/controllers/dashboards_controller.rb index c96d3c9362..4426a400e7 100644 --- a/app/controllers/dashboards_controller.rb +++ b/app/controllers/dashboards_controller.rb @@ -1,9 +1,60 @@ +require "json" + class DashboardsController < ApplicationController before_action :require_login + + layout "admin_layout", only: [ :admin, :admin_gerenciamento, :admin_avaliacao ] + + # tela de admin def admin end + # tela de gerenciamento + def admin_gerenciamento + @turmas = Turma.all + @discentes = Discente.all + @docentes = Docente.all + end + + # importação do json + def importar_json + # codigo de auxilio + if params["json"].blank? + puts "ERRO: O parâmetro 'json' veio vazio!" + flash[:error] = "Por favor, selecione um arquivo JSON." + redirect_to admin_gerenciamento_dashboard_path and return + end + + puts "Arquivo recebido com sucesso: #{params["json"].original_filename}" + + # Chama o service + resultado = Importer::AcademicDataImporter.import!(params["json"]) + + if resultado + puts "SUCESSO: O Service Object terminou sem erros." + flash[:success] = "JSON importado com sucesso!" + else + puts "AVISO: O Service retornou falso." + end + + redirect_to admin_gerenciamento_dashboard_path + + rescue => e + puts "EXCEÇÃO CAPTURADA NO CONTROLLER: #{e.message}" + puts e.backtrace.first(2) + flash[:error] = "Ocorreu um erro na importação: #{e.message}" + redirect_to admin_gerenciamento_dashboard_path + end + + + + + + # tela de avaliações + def admin_avaliacao + end + def discente end end diff --git a/app/javascript/admin_controller.js b/app/javascript/admin_controller.js new file mode 100644 index 0000000000..3dad599706 --- /dev/null +++ b/app/javascript/admin_controller.js @@ -0,0 +1,61 @@ +function ligarMenuAdmin() { + const menuItems = document.querySelectorAll('.nav-item') + const btnExp = document.querySelector('#btn-exp') + const menuSide = document.querySelector('.navbar') + const mainSide = document.querySelector('.dashboard-content') + + + // MANTÉM O ITEM ATIVO + const urlAtual = window.location.pathname + menuItems.forEach((item) => { + const link = item.querySelector('a') + if (link) { + const href = link.getAttribute('href'); + if (urlAtual === href || (href !== '/' && urlAtual.includes(href))) { + item.classList.add('ativo') + } else if (href === '#gerenciamento' && window.location.hash === '#gerenciamento') { + item.classList.add('ativo') + } else { + item.classList.remove('ativo') + } + } + }) + + // --- AJUSTE: LEMBRAR SE O MENU ESTAVA EXPANDIDO --- + if (menuSide && localStorage.getItem('menuExpandido') === 'true') { + menuSide.classList.add('expandir') + mainSide.classList.add('expandir') + } + + // Lógica original do clique nos itens + function selectLink() { + menuItems.forEach((item) => item.classList.remove('ativo')) + this.classList.add('ativo') + } + + menuItems.forEach((item) => { + item.removeEventListener('click', selectLink) + item.addEventListener('click', selectLink) + }) + + // Lógica original do botão de expandir (com o salvamento da memória) + if (btnExp && menuSide && mainSide) { + function toggleMenu(e) { + e.preventDefault() + menuSide.classList.toggle('expandir') + mainSide.classList.toggle('expandir') + + // Salva no navegador se o menu está aberto (true) ou fechado (false) + const estaExpandido = menuSide.classList.contains('expandir') + const mainExpandido = mainSide.classList.contains('expandir') + localStorage.setItem('menuExpandido', estaExpandido) + localStorage.setItem('menuExpandido', mainExpandido) + } + btnExp.removeEventListener('click', toggleMenu) + btnExp.addEventListener('click', toggleMenu) + } +} + +// Garante o funcionamento com as trocas de página do Turbo +document.addEventListener('turbo:load', ligarMenuAdmin) +ligarMenuAdmin() \ No newline at end of file diff --git a/app/javascript/controllers/index.js b/app/javascript/controllers/index.js index 1156bf8362..d0685d3b7b 100644 --- a/app/javascript/controllers/index.js +++ b/app/javascript/controllers/index.js @@ -1,4 +1,8 @@ -// Import and register all your controllers from the importmap via controllers/**/*_controller -import { application } from "controllers/application" -import { eagerLoadControllersFrom } from "@hotwired/stimulus-loading" -eagerLoadControllersFrom("controllers", application) +// This file is auto-generated by ./bin/rails stimulus:manifest:update +// Run that command whenever you add a new controller or create them with +// ./bin/rails generate stimulus controllerName + +import { application } from "./application" + +import HelloController from "./hello_controller" +application.register("hello", HelloController) diff --git a/app/mailers/application_mailer.rb b/app/mailers/application_mailer.rb index 3c34c8148f..5f345efe04 100644 --- a/app/mailers/application_mailer.rb +++ b/app/mailers/application_mailer.rb @@ -1,4 +1,4 @@ class ApplicationMailer < ActionMailer::Base - default from: "from@example.com" + default from: "ES2026_Grupo01@camaar.com" layout "mailer" end diff --git a/app/mailers/user_mailer.rb b/app/mailers/user_mailer.rb new file mode 100644 index 0000000000..91b44e54e3 --- /dev/null +++ b/app/mailers/user_mailer.rb @@ -0,0 +1,13 @@ +class UserMailer < ApplicationMailer + + def primeiro_acesso(usuario) + @usuario = usuario + + @url_definir_senha = definir_senha_url(email: @usuario.email) + + mail( + to: @usuario.email, + subject: 'Bem-vindo ao CAMAAR! Defina sua senha de acesso' + ) + end +end diff --git a/app/models/turma.rb b/app/models/turma.rb index 5c8c137db0..b489b1b006 100644 --- a/app/models/turma.rb +++ b/app/models/turma.rb @@ -5,3 +5,4 @@ class Turma < ApplicationRecord validates :codigo, presence: true validates :nome, presence: true end + diff --git a/app/services/importer/academic_data_importer.rb b/app/services/importer/academic_data_importer.rb new file mode 100644 index 0000000000..6355c0fd42 --- /dev/null +++ b/app/services/importer/academic_data_importer.rb @@ -0,0 +1,121 @@ +module Importer + class AcademicDataImporter + def self.import!(upload_file) + start_time = Time.current + + file_path = File.read(upload_file.tempfile.path) + data_hash = JSON.parse(file_path) + + + + ActiveRecord::Base.transaction do + unique_turmas = data_hash.uniq { |t| [ t["code"], t["classCode"], t["semester"] ] } + + turma_objects = unique_turmas.map do |t| + Turma.new(codigo: t["code"], turma: t["classCode"], semestre: t["semester"], departamento: "Ciência da Computação") + end + # duplicação de objetos + Turma.import turma_objects, on_duplicate_key_ignore: true, validate: false + + turmas_hash = Turma.all.pluck(:codigo, :turma, :semestre, :id).each_with_object({}) do |(codigo, turma, semestre, id), hash| + hash["#{codigo}-#{turma}-#{semestre}"] = id + end + + # armazenar os discentes e docentes + raw_discentes = [] + raw_docentes = [] + + data_hash.each do |turma_dados| + turma_id = turmas_hash["#{turma_dados['code']}-#{turma_dados['classCode']}-#{turma_dados['semester']}"] + next unless turma_id + + if turma_dados["dicente"].is_a?(Array) + turma_dados["dicente"].each do |d| + raw_discentes << d.merge("turma_id" => turma_id) + end + end + + if turma_dados["docente"].is_a?(Hash) + d_user = turma_dados["docente"] + raw_docentes << d_user.merge("turma_id" => turma_id) + end + end + + + unique_discentes = raw_discentes.uniq { |d| d["matricula"] } + unique_docentes = raw_docentes.uniq { |d| d["email"] } + + discente_objects = unique_discentes.map do |members| + Discente.new( + nome: members["nome"]&.downcase, + curso: members["curso"]&.downcase, + matricula: members["matricula"], + usuario: members["usuario"], + formacao: members["formacao"]&.downcase, + ocupacao: members["ocupacao"]&.downcase, + email: members["email"]&.downcase, + turma_id: members["turma_id"] + ) + end + Discente.import discente_objects, on_duplicate_key_ignore: true, validate: false + + users_discente_objects = unique_discentes.map do |members| + User.new( + nome: members["nome"]&.downcase, + matricula: members["matricula"], + email: members["email"], + perfil: "Discente", + password: "123456", + password_confirmation: "123456", + primeiro_acesso: false + ) + + end + User.import users_discente_objects, on_duplicate_key_ignore: true, validate: false + + emails_importados = users_discente_objects.map(&:email) + usuarios_salvos = User.where(email: emails_importados) + + usuarios_salvos.each do |usuario| + UsuarioMailer.email_primeiro_acesso(usuario).deliver_later + end + + docente_objects = unique_docentes.map do |members| + Docente.new( + nome: members["nome"]&.downcase, + departamento: members["departamento"]&.downcase, + usuario: members["usuario"], + formacao: members["formacao"]&.downcase, + ocupacao: members["ocupacao"]&.downcase, + email: members["email"]&.downcase, + turma: members["turma_id"] + ) + end + Docente.import docente_objects, on_duplicate_key_ignore: true, validate: false + + users_docente_objects = unique_docentes.map do |members| + User.new( + nome: members["nome"]&.downcase, + matricula: members["email"], + email: members["email"], + perfil: "Docente", + password: "123456", + password_confirmation: "123456", + primeiro_acesso: false + ) + end + + User.import users_docente_objects, on_duplicate_key_ignore: true, validate: false + end + # registro de erros + rescue StandardError => e + error = "Erro na transação de importação: #{e.message}" + Rails.logger.error error + raise + + elapsed_time = Time.current - start_time + Rails.logger.info "Tempo total de importação: #{elapsed_time.round(2)} segundos" + true + end + end +end \ No newline at end of file diff --git a/app/views/dashboards/admin.html.erb b/app/views/dashboards/admin.html.erb index f09f6f5f84..0a5cd4512e 100644 --- a/app/views/dashboards/admin.html.erb +++ b/app/views/dashboards/admin.html.erb @@ -1,18 +1,15 @@ -
Bem-vindo ao painel do administrador.
-Bem-vindo ao painel do administrador.
+Bem-vindo ao painel do administrador.
+Aqui você pode gerenciar as configurações do painel administrativo.
+ +Para acessar o sistema CAMAAR defina a sua senha
+ ++ <%= link_to 'Definir Minha Senha', @url_definir_senha %> +
+